diff --git a/.gitignore b/.gitignore index a3cbb20fda1..847f4383974 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ bin/ *.backup *.debug *.dump +.attach_pid* # vim .*.sw[a-p] diff --git a/Jenkinsfile b/Jenkinsfile index 7b36dbf4575..554ea76bf1f 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,199 +1,160 @@ #!groovy -// in case of change update method isMainBuild -def jdks = ["jdk8","jdk9","jdk10","jdk11"] -def oss = ["linux"] -def builds = [:] -for (def os in oss) { - for (def jdk in jdks) { - builds[os+"_"+jdk] = getFullBuild( jdk, os ) - } -} - -parallel builds - - -def getFullBuild(jdk, os) { - return { - node(os) { - // System Dependent Locations - def mvnName = 'maven3.5' - def localRepo = "${env.JENKINS_HOME}/${env.EXECUTOR_NUMBER}" // ".repository" // - def settingsName = 'oss-settings.xml' - def mavenOpts = '-Xms1g -Xmx4g -Djava.awt.headless=true' - - - try { - stage("Checkout - ${jdk}") { - checkout scm - } - } catch (Exception e) { - notifyBuild("Checkout Failure", jdk) - throw e - } - - try { - stage("Compile - ${jdk}") { - timeout(time: 15, unit: 'MINUTES') { - withMaven( - maven: mvnName, - jdk: "$jdk", - publisherStrategy: 'EXPLICIT', - globalMavenSettingsConfig: settingsName, - mavenOpts: mavenOpts, - mavenLocalRepo: localRepo) { - sh "mvn -V -B clean install -DskipTests -T6 -e" - } - } - } - } catch(Exception e) { - notifyBuild("Compile Failure", jdk) - throw e - } - - try { - stage("Javadoc - ${jdk}") { - timeout(time: 20, unit: 'MINUTES') { - withMaven( - maven: mvnName, - jdk: "$jdk", - publisherStrategy: 'EXPLICIT', - globalMavenSettingsConfig: settingsName, - mavenOpts: mavenOpts, - mavenLocalRepo: localRepo) { - sh "mvn -V -B javadoc:javadoc -T6 -e" - } - } - } - } catch(Exception e) { - notifyBuild("Javadoc Failure", jdk) - throw e - } - - try { - stage("Test - ${jdk}") { - timeout(time: 90, unit: 'MINUTES') { - // Run test phase / ignore test failures - withMaven( - maven: mvnName, - jdk: "$jdk", - publisherStrategy: 'EXPLICIT', - globalMavenSettingsConfig: settingsName, - //options: [invokerPublisher(disabled: false)], - mavenOpts: mavenOpts, - mavenLocalRepo: localRepo) { - sh "mvn -V -B install -Dmaven.test.failure.ignore=true -e -Pmongodb -T3 -Dunix.socket.tmp="+env.JENKINS_HOME - } - // withMaven doesn't label.. - // Report failures in the jenkins UI - junit testResults:'**/target/surefire-reports/TEST-*.xml,**/target/failsafe-reports/TEST-*.xml' - consoleParsers = [[parserName: 'JavaDoc'], - [parserName: 'JavaC']]; - if (isMainBuild( jdk )) { - // Collect up the jacoco execution results - def jacocoExcludes = - // build tools - "**/org/eclipse/jetty/ant/**" + ",**/org/eclipse/jetty/maven/**" + - ",**/org/eclipse/jetty/jspc/**" + - // example code / documentation - ",**/org/eclipse/jetty/embedded/**" + ",**/org/eclipse/jetty/asyncrest/**" + - ",**/org/eclipse/jetty/demo/**" + - // special environments / late integrations - ",**/org/eclipse/jetty/gcloud/**" + ",**/org/eclipse/jetty/infinispan/**" + - ",**/org/eclipse/jetty/osgi/**" + ",**/org/eclipse/jetty/spring/**" + - ",**/org/eclipse/jetty/http/spi/**" + - // test classes - ",**/org/eclipse/jetty/tests/**" + ",**/org/eclipse/jetty/test/**"; +pipeline { + agent any + // save some io during the build + options { durabilityHint('PERFORMANCE_OPTIMIZED') } + stages { + stage("Parallel Stage") { + parallel { + stage("Build / Test - JDK8") { + agent { node { label 'linux' } } + steps { + timeout(time: 120, unit: 'MINUTES') { + mavenBuild("jdk8", "-Pmongodb install", "maven3", true) + // Collect up the jacoco execution results (only on main build) jacoco inclusionPattern: '**/org/eclipse/jetty/**/*.class', - exclusionPattern: jacocoExcludes, - execPattern : '**/target/jacoco.exec', - classPattern : '**/target/classes', - sourcePattern : '**/src/main/java' - consoleParsers = [[parserName: 'Maven'], - [parserName: 'JavaDoc'], - [parserName: 'JavaC']]; + exclusionPattern: '' + + // build tools + '**/org/eclipse/jetty/ant/**' + + ',**/org/eclipse/jetty/maven/**' + + ',**/org/eclipse/jetty/jspc/**' + + // example code / documentation + ',**/org/eclipse/jetty/embedded/**' + + ',**/org/eclipse/jetty/asyncrest/**' + + ',**/org/eclipse/jetty/demo/**' + + // special environments / late integrations + ',**/org/eclipse/jetty/gcloud/**' + + ',**/org/eclipse/jetty/infinispan/**' + + ',**/org/eclipse/jetty/osgi/**' + + ',**/org/eclipse/jetty/spring/**' + + ',**/org/eclipse/jetty/http/spi/**' + + // test classes + ',**/org/eclipse/jetty/tests/**' + + ',**/org/eclipse/jetty/test/**', + execPattern: '**/target/jacoco.exec', + classPattern: '**/target/classes', + sourcePattern: '**/src/main/java' + warnings consoleParsers: [[parserName: 'Maven'], [parserName: 'Java']] + junit testResults: '**/target/surefire-reports/*.xml,**/target/invoker-reports/TEST*.xml' } - - // Report on Maven and Javadoc warnings - step( [$class : 'WarningsPublisher', - consoleParsers: consoleParsers] ) - } - if(isUnstable()) { - notifyBuild("Unstable / Test Errors", jdk) } } - } catch(Exception e) { - notifyBuild("Test Failure", jdk) - throw e - } - try - { - stage ("Compact3 - ${jdk}") { - withMaven( - maven: mvnName, - jdk: "$jdk", - publisherStrategy: 'EXPLICIT', - globalMavenSettingsConfig: settingsName, - mavenOpts: mavenOpts, - mavenLocalRepo: localRepo) { - sh "mvn -f aggregates/jetty-all-compact3 -V -B -Pcompact3 clean install -T5" + stage("Build / Test - JDK11") { + agent { node { label 'linux' } } + steps { + timeout(time: 120, unit: 'MINUTES') { + mavenBuild("jdk11", "-Pmongodb install", "maven3", true) + warnings consoleParsers: [[parserName: 'Maven'], [parserName: 'Java']] + junit testResults: '**/target/surefire-reports/*.xml,**/target/invoker-reports/TEST*.xml' + } } } - } catch(Exception e) { - notifyBuild("Compact3 Failure", jdk) - throw e - } + stage("Build / Test - JDK12") { + agent { node { label 'linux' } } + steps { + timeout(time: 120, unit: 'MINUTES') { + mavenBuild("jdk12", "-Pmongodb install", "maven3", true) + warnings consoleParsers: [[parserName: 'Maven'], [parserName: 'Java']] + junit testResults: '**/target/surefire-reports/*.xml,**/target/invoker-reports/TEST*.xml' + } + } + } + + stage("Build Javadoc") { + agent { node { label 'linux' } } + steps { + timeout(time: 30, unit: 'MINUTES') { + mavenBuild("jdk11", "install javadoc:javadoc javadoc:aggregate-jar -DskipTests", "maven3", true) + warnings consoleParsers: [[parserName: 'Maven'], [parserName: 'JavaDoc'], [parserName: 'Java']] + } + } + } + + stage("Checkstyle ") { + agent { node { label 'linux' } } + steps { + timeout(time: 30, unit: 'MINUTES') { + mavenBuild("jdk11", "install -f build-resources", "maven3", true) + mavenBuild("jdk11", "install checkstyle:check -DskipTests", "maven3", true) + recordIssues( + enabledForFailure: true, aggregatingResults: true, + tools: [java(), checkStyle(pattern: '**/target/checkstyle-result.xml', reportEncoding: 'UTF-8')]) + } + } + } + + stage("Build Compact3") { + agent { node { label 'linux' } } + steps { + timeout(time: 30, unit: 'MINUTES') { + mavenBuild("jdk8", "-Pcompact3 install -DskipTests", "maven3", true) + warnings consoleParsers: [[parserName: 'Maven'], [parserName: 'Java']] + } + } + } + } + } + } + post { + failure { + slackNotif() + } + unstable { + slackNotif() + } + fixed { + slackNotif() } } } -def isMainBuild(jdk) { - return jdk == "jdk8" +def slackNotif() { + script { + try + { + if ( env.BRANCH_NAME == 'jetty-10.0.x' || env.BRANCH_NAME == 'jetty-9.4.x' ) + { + //BUILD_USER = currentBuild.rawBuild.getCause(Cause.UserIdCause).getUserId() + // by ${BUILD_USER} + COLOR_MAP = ['SUCCESS': 'good', 'FAILURE': 'danger', 'UNSTABLE': 'danger', 'ABORTED': 'danger'] + slackSend channel: '#jenkins', + color: COLOR_MAP[currentBuild.currentResult], + message: "*${currentBuild.currentResult}:* Job ${env.JOB_NAME} build ${env.BUILD_NUMBER} - ${env.BUILD_URL}" + } + } catch (Exception e) { + e.printStackTrace() + echo "skip failure slack notification: " + e.getMessage() + } + } } +/** + * To other developers, if you are using this method above, please use the following syntax. + * + * mavenBuild("", " " + * + * @param jdk the jdk tool name (in jenkins) to use for this build + * @param cmdline the command line in " "`format. + * @return the Jenkinsfile step representing a maven build + */ +def mavenBuild(jdk, cmdline, mvnName, junitPublishDisabled) { + def localRepo = ".repository" + def mavenOpts = '-Xms1g -Xmx4g -Djava.awt.headless=true' -// True if this build is part of the "active" branches -// for Jetty. -def isActiveBranch() { - def branchName = "${env.BRANCH_NAME}" - return ( branchName == "master" || - ( branchName.startsWith("jetty-") && branchName.endsWith(".x") ) ); -} - -// Test if the Jenkins Pipeline or Step has marked the -// current build as unstable -def isUnstable() { - return currentBuild.result == "UNSTABLE" -} - -// Send a notification about the build status -def notifyBuild(String buildStatus, String jdk) { - if ( !isActiveBranch() ) { - // don't send notifications on transient branches - return + withMaven( + maven: mvnName, + jdk: "$jdk", + publisherStrategy: 'EXPLICIT', + options: [junitPublisher(disabled: junitPublishDisabled),mavenLinkerPublisher(disabled: false),pipelineGraphPublisher(disabled: false)], + mavenOpts: mavenOpts, + mavenLocalRepo: localRepo) { + // Some common Maven command line + provided command line + sh "mvn -Pci -V -B -T3 -e -Dmaven.test.failure.ignore=true -Djetty.testtracker.log=true $cmdline -Dunix.socket.tmp=" + env.JENKINS_HOME } - - // default the value - buildStatus = buildStatus ?: "UNKNOWN" - - def email = "${env.EMAILADDRESS}" - def summary = "${env.JOB_NAME}#${env.BUILD_NUMBER} - ${buildStatus} with jdk ${jdk}" - def detail = """

Job: ${env.JOB_NAME} [#${env.BUILD_NUMBER}]

-

${buildStatus}

- - - - -
Build${env.BUILD_URL}
Console${env.BUILD_URL}console
Test Report${env.BUILD_URL}testReport/
- """ - - emailext ( - to: email, - subject: summary, - body: detail - ) } + // vim: et:ts=2:sw=2:ft=groovy diff --git a/Jmh_Jenkinsfile b/Jmh_Jenkinsfile index 5f6dd580375..9837af5ec8f 100644 --- a/Jmh_Jenkinsfile +++ b/Jmh_Jenkinsfile @@ -2,53 +2,49 @@ def branch = params.get("JETTY_BRANCH" ,"jetty-9.4.x") def owner = params.get("REPO_OWNER", "eclipse") +def jdk = params.get("JDK", "jdk8") +def jmhJarPath = params.get("jmhJarPath","jetty-jmh/target/benchmarks.jar") +currentBuild.description = "Build branch $branch with jdk $jdk" node("linux") { // System Dependent Locations - def mvntool = tool name: 'maven3.5', type: 'hudson.tasks.Maven$MavenInstallation' - def jdktool = tool name: "jdk8", type: 'hudson.model.JDK' def mvnName = 'maven3.5' def localRepo = "${env.JENKINS_HOME}/${env.EXECUTOR_NUMBER}" def settingsName = 'oss-settings.xml' def mavenOpts = '-Xms1g -Xmx4g -Djava.awt.headless=true' - // Environment - List mvnEnv = ["PATH+MVN=${mvntool}/bin", "PATH+JDK=${jdktool}/bin", "JAVA_HOME=${jdktool}/", "MAVEN_HOME=${mvntool}"] - mvnEnv.add("MAVEN_OPTS=$mavenOpts") - stage("Checkout") { git url: "https://github.com/$owner/jetty.project.git", branch: "$branch" + } stage("Compile") { - withEnv(mvnEnv) { - timeout(time: 15, unit: 'MINUTES') { - withMaven( - maven: mvnName, - jdk: "jdk8", - publisherStrategy: 'EXPLICIT', - globalMavenSettingsConfig: settingsName, - mavenOpts: mavenOpts, - mavenLocalRepo: localRepo) { - sh "mvn -V -B clean install -DskipTests -T6 -e" - } - + timeout(time: 15, unit: 'MINUTES') { + withMaven( + maven: mvnName, + jdk: jdk, + publisherStrategy: 'EXPLICIT', + globalMavenSettingsConfig: settingsName, + mavenOpts: mavenOpts, + mavenLocalRepo: localRepo) { + sh "mvn -V -B clean install -DskipTests -T6 -e -pl :jetty-jmh -am" } - stash name: 'perf-tests', includes: 'jetty-jmh/target/benchmarks.jar' } + stash name: 'perf-tests', includes: jmhJarPath } } // jmh run - -stage("jmh-run") { - node( 'jmh-build-node' ) { - timeout( time: 120, unit: 'MINUTES' ) { - withEnv( ["JAVA_HOME=${tool "jdk8"}"] ) { +node( 'jmh-build-node' ) { + stage("jmh-run") { + timeout( time: 210, unit: 'MINUTES' ) { + withEnv( ["JAVA_HOME=${tool "$jdk"}"] ) { unstash name: 'perf-tests' - sh "${env.JAVA_HOME}/bin/java -jar jetty-jmh/target/benchmarks.jar -rff jetty-jmh/target/jmh_result.json -rf json" - jmhReport 'jetty-jmh/target/jmh_result.json' + sh "rm -rf jmh_results" + sh "mkdir jmh_results" + sh "${env.JAVA_HOME}/bin/java -jar $jmhJarPath -rff jmh_results/jmh_result.json -rf json -foe true -i 3 -t 3 -wi 3" + jmhReport 'jmh_results/jmh_result.json' } } } diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000000..6acfaf43962 --- /dev/null +++ b/LICENSE @@ -0,0 +1,415 @@ +This program and the accompanying materials are made available under the +terms of the Eclipse Public License 1.0 which is available at +https://www.eclipse.org/org/documents/epl-1.0/EPL-1.0.txt +or the Apache Software License 2.0 which is available at +https://www.apache.org/licenses/LICENSE-2.0 + + + +Eclipse Public License - v 1.0 + +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC +LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM +CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS + +"Contribution" means: + +a) in the case of the initial Contributor, the initial code and documentation + distributed under this Agreement, and +b) in the case of each subsequent Contributor: + i) changes to the Program, and + ii) additions to the Program; + + where such changes and/or additions to the Program originate from and are + distributed by that particular Contributor. A Contribution 'originates' + from a Contributor if it was added to the Program by such Contributor + itself or anyone acting on such Contributor's behalf. Contributions do not + include additions to the Program which: (i) are separate modules of + software distributed in conjunction with the Program under their own + license agreement, and (ii) are not derivative works of the Program. + +"Contributor" means any person or entity that distributes the Program. + +"Licensed Patents" mean patent claims licensable by a Contributor which are +necessarily infringed by the use or sale of its Contribution alone or when +combined with the Program. + +"Program" means the Contributions distributed in accordance with this +Agreement. + +"Recipient" means anyone who receives the Program under this Agreement, +including all Contributors. + +2. GRANT OF RIGHTS + a) Subject to the terms of this Agreement, each Contributor hereby grants + Recipient a non-exclusive, worldwide, royalty-free copyright license to + reproduce, prepare derivative works of, publicly display, publicly + perform, distribute and sublicense the Contribution of such Contributor, + if any, and such derivative works, in source code and object code form. + b) Subject to the terms of this Agreement, each Contributor hereby grants + Recipient a non-exclusive, worldwide, royalty-free patent license under + Licensed Patents to make, use, sell, offer to sell, import and otherwise + transfer the Contribution of such Contributor, if any, in source code and + object code form. This patent license shall apply to the combination of + the Contribution and the Program if, at the time the Contribution is + added by the Contributor, such addition of the Contribution causes such + combination to be covered by the Licensed Patents. The patent license + shall not apply to any other combinations which include the Contribution. + No hardware per se is licensed hereunder. + c) Recipient understands that although each Contributor grants the licenses + to its Contributions set forth herein, no assurances are provided by any + Contributor that the Program does not infringe the patent or other + intellectual property rights of any other entity. Each Contributor + disclaims any liability to Recipient for claims brought by any other + entity based on infringement of intellectual property rights or + otherwise. As a condition to exercising the rights and licenses granted + hereunder, each Recipient hereby assumes sole responsibility to secure + any other intellectual property rights needed, if any. For example, if a + third party patent license is required to allow Recipient to distribute + the Program, it is Recipient's responsibility to acquire that license + before distributing the Program. + d) Each Contributor represents that to its knowledge it has sufficient + copyright rights in its Contribution, if any, to grant the copyright + license set forth in this Agreement. + +3. REQUIREMENTS + +A Contributor may choose to distribute the Program in object code form under +its own license agreement, provided that: + + a) it complies with the terms and conditions of this Agreement; and + b) its license agreement: + i) effectively disclaims on behalf of all Contributors all warranties + and conditions, express and implied, including warranties or + conditions of title and non-infringement, and implied warranties or + conditions of merchantability and fitness for a particular purpose; + ii) effectively excludes on behalf of all Contributors all liability for + damages, including direct, indirect, special, incidental and + consequential damages, such as lost profits; + iii) states that any provisions which differ from this Agreement are + offered by that Contributor alone and not by any other party; and + iv) states that source code for the Program is available from such + Contributor, and informs licensees how to obtain it in a reasonable + manner on or through a medium customarily used for software exchange. + +When the Program is made available in source code form: + + a) it must be made available under this Agreement; and + b) a copy of this Agreement must be included with each copy of the Program. + Contributors may not remove or alter any copyright notices contained + within the Program. + +Each Contributor must identify itself as the originator of its Contribution, +if +any, in a manner that reasonably allows subsequent Recipients to identify the +originator of the Contribution. + +4. COMMERCIAL DISTRIBUTION + +Commercial distributors of software may accept certain responsibilities with +respect to end users, business partners and the like. While this license is +intended to facilitate the commercial use of the Program, the Contributor who +includes the Program in a commercial product offering should do so in a manner +which does not create potential liability for other Contributors. Therefore, +if a Contributor includes the Program in a commercial product offering, such +Contributor ("Commercial Contributor") hereby agrees to defend and indemnify +every other Contributor ("Indemnified Contributor") against any losses, +damages and costs (collectively "Losses") arising from claims, lawsuits and +other legal actions brought by a third party against the Indemnified +Contributor to the extent caused by the acts or omissions of such Commercial +Contributor in connection with its distribution of the Program in a commercial +product offering. The obligations in this section do not apply to any claims +or Losses relating to any actual or alleged intellectual property +infringement. In order to qualify, an Indemnified Contributor must: +a) promptly notify the Commercial Contributor in writing of such claim, and +b) allow the Commercial Contributor to control, and cooperate with the +Commercial Contributor in, the defense and any related settlement +negotiations. The Indemnified Contributor may participate in any such claim at +its own expense. + +For example, a Contributor might include the Program in a commercial product +offering, Product X. That Contributor is then a Commercial Contributor. If +that Commercial Contributor then makes performance claims, or offers +warranties related to Product X, those performance claims and warranties are +such Commercial Contributor's responsibility alone. Under this section, the +Commercial Contributor would have to defend claims against the other +Contributors related to those performance claims and warranties, and if a +court requires any other Contributor to pay any damages as a result, the +Commercial Contributor must pay those damages. + +5. NO WARRANTY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR +IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each +Recipient is solely responsible for determining the appropriateness of using +and distributing the Program and assumes all risks associated with its +exercise of rights under this Agreement , including but not limited to the +risks and costs of program errors, compliance with applicable laws, damage to +or loss of data, programs or equipment, and unavailability or interruption of +operations. + +6. DISCLAIMER OF LIABILITY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY +CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION +LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE +EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGES. + +7. GENERAL + +If any provision of this Agreement is invalid or unenforceable under +applicable law, it shall not affect the validity or enforceability of the +remainder of the terms of this Agreement, and without further action by the +parties hereto, such provision shall be reformed to the minimum extent +necessary to make such provision valid and enforceable. + +If Recipient institutes patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Program itself +(excluding combinations of the Program with other software or hardware) +infringes such Recipient's patent(s), then such Recipient's rights granted +under Section 2(b) shall terminate as of the date such litigation is filed. + +All Recipient's rights under this Agreement shall terminate if it fails to +comply with any of the material terms or conditions of this Agreement and does +not cure such failure in a reasonable period of time after becoming aware of +such noncompliance. If all Recipient's rights under this Agreement terminate, +Recipient agrees to cease use and distribution of the Program as soon as +reasonably practicable. However, Recipient's obligations under this Agreement +and any licenses granted by Recipient relating to the Program shall continue +and survive. + +Everyone is permitted to copy and distribute copies of this Agreement, but in +order to avoid inconsistency the Agreement is copyrighted and may only be +modified in the following manner. The Agreement Steward reserves the right to +publish new versions (including revisions) of this Agreement from time to +time. No one other than the Agreement Steward has the right to modify this +Agreement. The Eclipse Foundation is the initial Agreement Steward. The +Eclipse Foundation may assign the responsibility to serve as the Agreement +Steward to a suitable separate entity. Each new version of the Agreement will +be given a distinguishing version number. The Program (including +Contributions) may always be distributed subject to the version of the +Agreement under which it was received. In addition, after a new version of the +Agreement is published, Contributor may elect to distribute the Program +(including its Contributions) under the new version. Except as expressly +stated in Sections 2(a) and 2(b) above, Recipient receives no rights or +licenses to the intellectual property of any Contributor under this Agreement, +whether expressly, by implication, estoppel or otherwise. All rights in the +Program not expressly granted under this Agreement are reserved. + +This Agreement is governed by the laws of the State of New York and the +intellectual property laws of the United States of America. No party to this +Agreement will bring a legal action under this Agreement more than one year +after the cause of action arose. Each party waives its rights to a jury trial in +any resulting litigation. + + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/LICENSE-eplv10-aslv20.html b/LICENSE-eplv10-aslv20.html deleted file mode 100644 index 48addaaddf7..00000000000 --- a/LICENSE-eplv10-aslv20.html +++ /dev/null @@ -1,576 +0,0 @@ - - - - - - - - -Eclipse Public License - Version 1.0 / Apache License - Version 2.0 - - - - -
- -

Eclipse Public License - v 1.0 -

- -

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER -THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, -REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE -OF THIS AGREEMENT.

- -

1. DEFINITIONS

- -

"Contribution" means:

- -

a) -in the case of the initial Contributor, the initial code and documentation -distributed under this Agreement, and
-b) in the case of each subsequent Contributor:

- -

i) -changes to the Program, and

- -

ii) -additions to the Program;

- -

where -such changes and/or additions to the Program originate from and are distributed -by that particular Contributor. A Contribution 'originates' from a Contributor -if it was added to the Program by such Contributor itself or anyone acting on -such Contributor's behalf. Contributions do not include additions to the -Program which: (i) are separate modules of software distributed in conjunction -with the Program under their own license agreement, and (ii) are not derivative -works of the Program.

- -

"Contributor" means any person or -entity that distributes the Program.

- -

"Licensed Patents " mean patent -claims licensable by a Contributor which are necessarily infringed by the use -or sale of its Contribution alone or when combined with the Program.

- -

"Program" means the Contributions -distributed in accordance with this Agreement.

- -

"Recipient" means anyone who -receives the Program under this Agreement, including all Contributors.

- -

2. GRANT OF RIGHTS

- -

a) -Subject to the terms of this Agreement, each Contributor hereby grants Recipient -a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly -display, publicly perform, distribute and sublicense the Contribution of such -Contributor, if any, and such derivative works, in source code and object code -form.

- -

b) -Subject to the terms of this Agreement, each Contributor hereby grants -Recipient a non-exclusive, worldwide, royalty-free -patent license under Licensed Patents to make, use, sell, offer to sell, import -and otherwise transfer the Contribution of such Contributor, if any, in source -code and object code form. This patent license shall apply to the combination -of the Contribution and the Program if, at the time the Contribution is added -by the Contributor, such addition of the Contribution causes such combination -to be covered by the Licensed Patents. The patent license shall not apply to -any other combinations which include the Contribution. No hardware per se is -licensed hereunder.

- -

c) -Recipient understands that although each Contributor grants the licenses to its -Contributions set forth herein, no assurances are provided by any Contributor -that the Program does not infringe the patent or other intellectual property -rights of any other entity. Each Contributor disclaims any liability to Recipient -for claims brought by any other entity based on infringement of intellectual -property rights or otherwise. As a condition to exercising the rights and -licenses granted hereunder, each Recipient hereby assumes sole responsibility -to secure any other intellectual property rights needed, if any. For example, -if a third party patent license is required to allow Recipient to distribute -the Program, it is Recipient's responsibility to acquire that license before -distributing the Program.

- -

d) -Each Contributor represents that to its knowledge it has sufficient copyright -rights in its Contribution, if any, to grant the copyright license set forth in -this Agreement.

- -

3. REQUIREMENTS

- -

A Contributor may choose to distribute the -Program in object code form under its own license agreement, provided that: -

- -

a) -it complies with the terms and conditions of this Agreement; and

- -

b) -its license agreement:

- -

i) -effectively disclaims on behalf of all Contributors all warranties and -conditions, express and implied, including warranties or conditions of title -and non-infringement, and implied warranties or conditions of merchantability -and fitness for a particular purpose;

- -

ii) -effectively excludes on behalf of all Contributors all liability for damages, -including direct, indirect, special, incidental and consequential damages, such -as lost profits;

- -

iii) -states that any provisions which differ from this Agreement are offered by that -Contributor alone and not by any other party; and

- -

iv) -states that source code for the Program is available from such Contributor, and -informs licensees how to obtain it in a reasonable manner on or through a -medium customarily used for software exchange.

- -

When the Program is made available in source -code form:

- -

a) -it must be made available under this Agreement; and

- -

b) a -copy of this Agreement must be included with each copy of the Program.

- -

Contributors may not remove or alter any -copyright notices contained within the Program.

- -

Each Contributor must identify itself as the -originator of its Contribution, if any, in a manner that reasonably allows -subsequent Recipients to identify the originator of the Contribution.

- -

4. COMMERCIAL DISTRIBUTION

- -

Commercial distributors of software may -accept certain responsibilities with respect to end users, business partners -and the like. While this license is intended to facilitate the commercial use -of the Program, the Contributor who includes the Program in a commercial -product offering should do so in a manner which does not create potential -liability for other Contributors. Therefore, if a Contributor includes the -Program in a commercial product offering, such Contributor ("Commercial -Contributor") hereby agrees to defend and indemnify every other -Contributor ("Indemnified Contributor") against any losses, damages and -costs (collectively "Losses") arising from claims, lawsuits and other -legal actions brought by a third party against the Indemnified Contributor to -the extent caused by the acts or omissions of such Commercial Contributor in -connection with its distribution of the Program in a commercial product -offering. The obligations in this section do not apply to any claims or Losses -relating to any actual or alleged intellectual property infringement. In order -to qualify, an Indemnified Contributor must: a) promptly notify the Commercial -Contributor in writing of such claim, and b) allow the Commercial Contributor -to control, and cooperate with the Commercial Contributor in, the defense and -any related settlement negotiations. The Indemnified Contributor may participate -in any such claim at its own expense.

- -

For example, a Contributor might include the -Program in a commercial product offering, Product X. That Contributor is then a -Commercial Contributor. If that Commercial Contributor then makes performance -claims, or offers warranties related to Product X, those performance claims and -warranties are such Commercial Contributor's responsibility alone. Under this -section, the Commercial Contributor would have to defend claims against the -other Contributors related to those performance claims and warranties, and if a -court requires any other Contributor to pay any damages as a result, the -Commercial Contributor must pay those damages.

- -

5. NO WARRANTY

- -

EXCEPT AS EXPRESSLY SET FORTH IN THIS -AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT -WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, -WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, -MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely -responsible for determining the appropriateness of using and distributing the -Program and assumes all risks associated with its exercise of rights under this -Agreement , including but not limited to the risks and costs of program errors, -compliance with applicable laws, damage to or loss of data, programs or -equipment, and unavailability or interruption of operations.

- -

6. DISCLAIMER OF LIABILITY

- -

EXCEPT AS EXPRESSLY SET FORTH IN THIS -AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY -OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF -THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF -THE POSSIBILITY OF SUCH DAMAGES.

- -

7. GENERAL

- -

If any provision of this Agreement is invalid -or unenforceable under applicable law, it shall not affect the validity or -enforceability of the remainder of the terms of this Agreement, and without -further action by the parties hereto, such provision shall be reformed to the -minimum extent necessary to make such provision valid and enforceable.

- -

If Recipient institutes patent litigation -against any entity (including a cross-claim or counterclaim in a lawsuit) -alleging that the Program itself (excluding combinations of the Program with -other software or hardware) infringes such Recipient's patent(s), then such -Recipient's rights granted under Section 2(b) shall terminate as of the date -such litigation is filed.

- -

All Recipient's rights under this Agreement -shall terminate if it fails to comply with any of the material terms or -conditions of this Agreement and does not cure such failure in a reasonable -period of time after becoming aware of such noncompliance. If all Recipient's -rights under this Agreement terminate, Recipient agrees to cease use and -distribution of the Program as soon as reasonably practicable. However, -Recipient's obligations under this Agreement and any licenses granted by -Recipient relating to the Program shall continue and survive.

- -

Everyone is permitted to copy and distribute -copies of this Agreement, but in order to avoid inconsistency the Agreement is -copyrighted and may only be modified in the following manner. The Agreement -Steward reserves the right to publish new versions (including revisions) of -this Agreement from time to time. No one other than the Agreement Steward has -the right to modify this Agreement. The Eclipse Foundation is the initial -Agreement Steward. The Eclipse Foundation may assign the responsibility to -serve as the Agreement Steward to a suitable separate entity. Each new version -of the Agreement will be given a distinguishing version number. The Program -(including Contributions) may always be distributed subject to the version of -the Agreement under which it was received. In addition, after a new version of -the Agreement is published, Contributor may elect to distribute the Program -(including its Contributions) under the new version. Except as expressly stated -in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to -the intellectual property of any Contributor under this Agreement, whether -expressly, by implication, estoppel or otherwise. All rights in the Program not -expressly granted under this Agreement are reserved.

- -

This Agreement is governed by the laws of the -State of New York and the intellectual property laws of the United States of -America. No party to this Agreement will bring a legal action under this -Agreement more than one year after the cause of action arose. Each party waives -its rights to a jury trial in any resulting litigation.

- -

 

- -
- -
- -

Apache License
-Version 2.0, January 2004
-http://www.apache.org/licenses/
-

-

TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

-

1. Definitions.

-

- "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document.

-

- "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License.

-

- "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity.

-

- "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License.

-

- "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files.

-

- "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types.

-

- "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below).

-

- "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof.

-

- "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution."

-

- "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work.

- -

2. Grant of Copyright License.

-

-Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form.

- - -

3. Grant of Patent License.

- -

- Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. -

-

- 4. Redistribution. -

- -

You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions:

-

    -
  • - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and

    -

  • -
  • - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and

    -

  • - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and

    - -

  • - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License.

    -

  • -
-

- -

- You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. -

-

- 5. Submission of Contributions. -

- -

Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. -

-

- 6. Trademarks. -

- -

This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. -

-

- 7. Disclaimer of Warranty. -

- -

Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. -

-

- 8. Limitation of Liability. -

- -

In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. -

-

- 9. Accepting Warranty or Additional Liability. -

-

While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. -

- -

- END OF TERMS AND CONDITIONS -

- -

- APPENDIX: How to apply the Apache License to your work. -

- -

- To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. -

- -

- Copyright [yyyy] [name of copyright owner] -

- -

- Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at -

- -

- http://www.apache.org/licenses/LICENSE-2.0 -

- -

- Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -

- -
- \ No newline at end of file diff --git a/NOTICE.txt b/NOTICE.txt index 9ca92f1f704..28ee14ee3e1 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -1,6 +1,6 @@ ============================================================== Jetty Web Container - Copyright 1995-2018 Mort Bay Consulting Pty Ltd. + Copyright 1995-2019 Mort Bay Consulting Pty Ltd. ============================================================== The Jetty Web Container is Copyright Mort Bay Consulting Pty Ltd diff --git a/VERSION.txt b/VERSION.txt index 95da0d1ed4a..26288cd7b37 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1,4 +1,251 @@ -jetty-9.4.13-SNAPSHOT +jetty-9.4.21-SNAPSHOT + +jetty-9.4.20.v20190813 - 13 August 2019 + + 300 Implement Deflater / Inflater Object Pool + + 2061 WebSocket hangs in blockingWrite + + 3601 HTTP2 stall on reset streams + + 3648 javax.websocket client container incorrectly creates Server + SslContextFactory + + 3698 Missing WebSocket ServerContainer after server restart + + 3700 stackoverflow in WebAppClassLoaderUrlStreamTest + + 3708 Swap various java.lang.String replace() methods for better performant + ones + + 3731 Add testing of CDI behaviors + + 3736 NPE from WebAppClassLoader during CDI + + 3746 ClassCastException in WriteFlusher.java - IdleState cannot be cast to + FailedState + + 3749 Memory leak while processing AsyncListener annotations + + 3755 ServerWithAnnotations doesn't do anything + + 3758 Avoid sending empty trailer frames for http/2 requests + + 3782 X-Forwarded-Port overrides X-Forwarded-For + + 3786 ALPN support for Java 14 + + 3798 ClasspathPattern match method throws NPE. URI can be null + + 3799 Programmatically added listeners from + ServletContextListener.contextInitialzed() are not called + + 3804 Weld/CDI XML backwards compat + + 3805 XmlConfiguration odd behavior for numbers + + 3806 The error page handler didn't process correctly in proxy + + 3815 PropertyFileLoginModule adds user principle as a role + + 3822 trustAll will not work on some servers + + 3829 Avoid sending empty trailer frames for http/2 responses + + 3835 WebSocketSession are not being stopped properly + + 3840 Byte-range request performance problems with large files + + 3856 Different behaviour with maxFormContentSize=0 if Content-Length header + is present/missing + + 3876 WebSocketPartialListener is only called for initial frames, not for + continuation frames + + 3884 @WebSocket without @OnWebSocketMessage handler fails when receiving a + continuation frame + + 3888 BufferUtil.toBuffer(Resource resource,boolean direct) does not like + large (4G+) Resources + + 3906 Fix for #3840 breaks Path encapsulation in PathResource + + 3929 Deadlock between new HTTP2Connection() and Server.stop() + + 3940 Double initialization of Log + + 3957 CustomRequestLog bad usage of MethodHandles.lookup() + + 3960 Fix HttpConfiguration copy constructor + + 3969 X-Forwarded-Port header customization isn't possible + +jetty-9.4.19.v20190610 - 10 June 2019 + + 2909 Remove B64Code + + 3332 jetty-maven-plugin - transitive dependencies not loaded from + "target/classes" + + 3498 WebSocket Session.suspend() now suspends incoming frames instead of + reads + + 3534 Use System nanoTime, not currentTimeMillis for IdleTimeout + + 3550 Server becomes unresponsive after sitting idle from a load spike + + 3562 InetAccessHandler should be able to apply to a certain port or + connector + + 3568 Make UserStore able to be started/stopped with its LoginService + + 3583 jetty-maven plugin in multi-module-project does not use files from + /target/test-classes folder of dependent projects + + 3605 IdleTimeout with Jetty HTTP/2 and InputStreamResponseListener + + 3608 Reply with 400 Bad request to malformed WebSocket handshake + + 3616 Backport WebSocket SessionTracker from Jetty 10 + + 3620 Use of `throwUnavailableOnStartupException=true` does not stop Server + in jetty-home + + 3627 Only renew session id when spnego authentication is fully complete + + 3628 NPE in QueuedThreadPool.getReservedThreads() + + 3630 X-Forwarded-For missing last hextet for ipv6 + + 3633 endpointIdentificationAlgorithm enabled by default + jetty-ssl-context.xml + + 3653 access control exception if programmatic security manager is used + + 3655 Spaces missing on Cookies generated via RFC6265 + + 3663 Remove deprecation of HttpClient replacement methods in WebSocketClient + + 3680 Bom manages non-existent infinispan-remote and infinispan-embedded + dependencies due to config classifier + + 3683 Multipart file not deleted when client aborts upload + + 3690 Upgrade to asm 7.1 + + 3713 Emit warning when invoking deprecated method in Jetty XML + + 3715 Improve Log.condensePackage performance + + 3722 HttpSessionListener.sessionDestroyed should be able to access webapp + classes + + 3726 Remove OSGi export uses of servlet-api from jetty-util + + 3729 Make creation of java:comp/env threadsafe + + 3743 Update XmlConfiguration usage in Jetty to always use Constructors that + provide Location information + + 3748 @Resource field not injected in Jetty Demo + + 3750 NPE in WebSocketClient.toString() + + 3751 Modern Configure DTD / FPI is used inconsistently + +jetty-9.4.18.v20190429 - 29 April 2019 + + 3476 IllegalStateException in WebSocket ConnectionState + + 3550 Server becomes unresponsive after sitting idle from a load spike + + 3563 Update to apache jasper 8.5.40 + + 3573 Update jetty-bom for new infinispan artifacts + + 3582 HeapByteBuffer cleared unexpected + + 3597 Session persistence broken from 9.4.13+ + + 3609 Fix infinispan start module dependencies + +jetty-9.4.17.v20190418 - 18 April 2019 + + 3464 Split SslContextFactory into Client and Server + + 3549 Directory Listing on Windows reveals Resource Base path + + 3555 DefaultHandler Reveals Base Resource Path of each Context + +jetty-9.4.16.v20190411 - 11 April 2019 + + 1861 Limit total bytes pooled by ByteBufferPools + + 3133 Logging of `key.readyOps()` can throw unchecked `CancelledKeyException` + + 3159 WebSocket permessage-deflate RSV1 validity check + + 3274 OSGi versions of java.base classes in + org.apache.felix:org.osgi.foundation:jar conflicts with new rules on Java 9+ + + 3319 Modernize Directory Listing: HTML5 and Sorting + + 3361 HandlerCollection.addHandler is lacking synchronization + + 3373 OutOfMemoryError: Java heap space in GZIPContentDecoder + + 3389 Websockets jsr356 willDecode not invoked during decoding + + 3394 java.security.acl.Group is deprecated and marked for removal + + 3404 Cleanup QuotedQualityCSV internal use of Double + + 3411 HttpClient does not timeout during multiple redirection + + 3421 Duplicate JSESSIONID sent when invalidating new session + + 3422 CLOSE_WAIT socket status forever after terminating websocket client + side + + 3425 Upgrade conscrypt version to 2.0.0 and remove usage of reflection + + 3429 JMX Operation to trigger manual deployment scan in WebAppProvider + + 3440 Stop server if Unavailable thrown + + 3444 org.eclipse.jetty.http.Http1FieldPreEncoder generates an invalid header + byte-array if header is null + + 3456 Allow multiple programmatic login/logout in same request + + 3464 Split SslContextFactory into Client and Server + + 3481 TLS close_notify() is not guaranteed + + 3489 Using setExtraClasspath("lib/extra/*") does not work on Microsoft + Windows + + 3526 HTTP Request Locale not retained in WebsocketUpgrade Request + + 3540 Use configured Provider in SslContextFactory consistently + + 3545 NullPointerException on ServletOutputStream.print(""); + +jetty-9.4.15.v20190215 - 15 February 2019 + + 113 Add support for NCSA Extended Log File Format + + 150 extraClasspath() method on WebAppContext dont support dir path + + 2646 Better handle concurrent calls to change session id and invalidate + within a context + + 2718 NPE using more than one Endpoint.publish + + 2817 Change HttpClient and WebSocketClient default to always have SSL + support enabled + + 3030 Enforce Content-Encoding check only on parameter extraction + + 3038 SSL Connection Leak + + 3049 Warn on common SslContextFactory problematic configurations + + 3133 Logging of `key.readyOps()` can throw unchecked `CancelledKeyException` + + 3139 NPE on + WebSocketServerContainerInitializer.configureContext(ServletContextHandler) + + 3146 ServletContainerInitializer from war WEB-INF/classes not executing + + 3154 Add support for javax.net.ssl.HostnameVerifier to HttpClient + + 3161 Update to Apache JSP 8.5.35 + + 3178 BufferingResponseListener does not clear buffer in onHeaders + + 3186 Jetty maven plugin - javax.annotation.jar picked up from jetty plugin + rather than from applications classpath + + 3202 jetty-maven plugin in multi-module project not using files from /target + folders of sister projects + + 3207 Async ServletOutputStream print methods + + 3210 Threadpool module creates unmanged threadpool + + 3212 Client and server need to to treat an incoming HTTP/2 RST_STREAM frame + differently + + 3234 AuthenticationProtocolHandler should not cache the failed results + + 3240 ALPN support for Java 13 + + 3241 Missing main manifest attribute in jetty-runner.jar + + 3242 Fix WebSocket components dump() + + 3278 NullPointerException if base resource is an empty ResourceCollection + + 3279 WebSocket write may hang forever + + 3302 Support host:port in X-Forwarded-For header in + ForwardedRequestCustomizer + + 3305 Avoid additional selectNow() on non-Windows runtimes + + 3307 WebAppClassLoader loadClass can throw NullPointerException for missing + class + + 3311 Ability to serve HTTP and HTTPS from the same port + + 3317 Improve uncaught exception handler double logging + + 3329 Hazelcast delete expired session fails in deserialize + + 3350 Do not expect to be able to connect to https URLs with the HttpClient + created from a parameterless constructor + +jetty-9.3.27.v20190418 - 18 April 2019 + + 3549 Directory Listing on Windows reveals Resource Base path + + 3555 DefaultHandler Reveals Base Resource Path of each Context + +jetty-9.3.26.v20190403 - 03 April 2019 + + 2954 Improve cause reporting for HttpClient failures + + 3274 OSGi versions of java.base classes in + org.apache.felix:org.osgi.foundation:jar conflicts with new rules on Java 9+ + + 3302 Support host:port in X-Forwarded-For header in + ForwardedRequestCustomizer + + 3319 Allow reverse sort for directory listed files + +jetty-9.2.28.v20190418 - 18 April 2019 + + 3549 Directory Listing on Windows reveals Resource Base path + + 3555 DefaultHandler Reveals Base Resource Path of each Context + +jetty-9.2.27.v20190403 - 03 April 2019 + + 3319 Refactored Directory Listing to modernize and avoid XSS + +jetty-9.4.14.v20181114 - 14 November 2018 + + 3097 Duplicated programmatic Servlet Listeners causing duplicate calls + + 3103 HttpClientLoadTest reports a leak in byte buffer + + 3104 Align jetty-schemas version within apache-jsp module as well + +jetty-9.4.13.v20181111 - 11 November 2018 + + 2191 JPMS Support + + 2431 Upgrade to Junit 5 + + 2691 LdapLoginModule does not find accounts in subtrees + + 2702 ArithmeticException in Credentials.stringEquals and .byteEquals + + 2718 NPE using more than one Endpoint.publish + + 2727 Cleanup behavior of JMX MBean discovery + + 2740 Ensure OSGiWebappClassLoader uses bundleloader for all loadClass + methods + + 2787 Use status code from nested BadMessageException wrapped in + ServletException + + 2796 HTTP/2 max local stream count exceeded when request fails + + 2834 Support Java 11 bytecode during annotation scanning + + 2865 Update to apache jasper 8.5.33 + + 2868 Adding SPNEGO authentication support for Jetty Client + + 2871 HTTP/2 Server reads -1 after client resets stream + + 2875 Fix WebSocketClient.connect() hang when attempting to connect at an + invalid websocket endpoint + + 2886 SNI matching does not work in certain cases when there is only one CN + certificate in the keystore + + 2901 Introduce HttpConnectionUpgrader as a conversation component in + HttpClient + + 2903 Avoid Listener instantiation during QuickStart generation + + 2906 jetty-maven-plugin run goal adds output directory of reactor project + dependencies to classpath without regard for scope + + 2912 Requests handled with GzipHandler should remove Content-Encoding and + Content-Length headers + + 2913 Remove reliance on sun.reflect.Reflection to be compatible with Java 11 + + 2936 Error during initial RequestDispatch with bad request query results in + failure for ErrorHandler to process + + 2941 Upgrade to ASM 7 to support Java 11 bytecode + + 2954 Improve cause reporting for HttpClient failures + + 2970 Ensure HttpChannel.onComplete is always called + + 3018 Improve error handling and logging of min data rate violations + + 3023 Wrong non-redirect behaviour with "null" path info + + 3030 Enforce Content-Encoding check only on parameter extraction + + 3041 Cookies parsing in RFC2965 should allow deprecated comma separators + + 3049 Warn on common SslContextFactory problematic configurations + + 3054 Update OSGi to ASM 7 + + 3090 MBeanContainer throws NPE for arrays + + 3092 Wrong classloader used to load *MBean classes + +jetty-9.3.25.v20180904 - 04 September 2018 + + 2135 Android 8.1 needs direct buffers for SSL/TLS to work + + 2777 Workaround for Conscrypt's ssl == null + + 2787 BadMessageException wrapped as ServletException not handled + + 2860 Leakage of HttpDestinations in HttpClient + + 2871 Server reads -1 after client resets HTTP/2 stream jetty-9.4.12.v20180830 - 30 August 2018 + 300 Implement Deflater / Inflater Object Pool @@ -19,7 +266,7 @@ jetty-9.4.12.v20180830 - 30 August 2018 + 2398 MultiPartFormInputStream parsing should default to UTF-8, but allowed to be overridden by Request.setCharacterEncoding() + 2468 EWYK concurrent produce can fail SSL connections - + 2501 Include accepting connections in connection limit. + + 2501 Include accepting connections in connection limit + 2530 Client waits forever for cancelled large uploads + 2560 Review PathResource exception handling + 2565 HashLoginService silently ignores file:/ config paths from 9.3.x @@ -33,7 +280,7 @@ jetty-9.4.12.v20180830 - 30 August 2018 beans + 2662 Remove unnecessary boxing conversions + 2663 Guard Throwable.addSuppressed() calls - + 2672 Max local stream count exceeded for HttpClient with HTTP/2 transport + + 2672 Max local stream count exceeded for HttpClient with HTTP/2 transport + 2675 Demo rewrite rules prevent URL Session tracking + 2677 Decode URI before matching against "/favicon.ico" + 2679 HTTP/2 Spec Compliance @@ -92,12 +339,16 @@ jetty-9.4.12.v20180830 - 30 August 2018 + 2860 Leakage of HttpDestinations in HttpClient + 2871 Server reads -1 after client resets HTTP/2 stream -jetty-9.3.25.v20180904 - 04 September 2018 - + 2135 Android 8.1 needs direct buffers for SSL/TLS to work +jetty-9.2.26.v20180806 - 06 August 2018 + 2777 Workaround for Conscrypt's ssl == null - + 2787 BadMessageException wrapped as ServletException not handled - + 2860 Leakage of HttpDestinations in HttpClient - + 2871 Server reads -1 after client resets HTTP/2 stream + +jetty-9.2.25.v20180606 - 06 June 2018 + + 2114 Fix NPE in JettyHttpServerProvider + + 2135 Android 8.1 needs direct buffers for SSL/TLS to work + + 2529 HttpParser cleanup + + 2603 WebSocket ByteAccumulator initialized with wrong maximum + + 2604 WebSocket ByteAccumulator should report sizes in + MessageTooLargeException jetty-9.4.11.v20180605 - 05 June 2018 + 1785 Support for vhost@connectorname syntax of virtual hosts diff --git a/aggregates/jetty-all-compact3/pom.xml b/aggregates/jetty-all-compact3/pom.xml index 95b387a6bb7..b8c6ec526f7 100644 --- a/aggregates/jetty-all-compact3/pom.xml +++ b/aggregates/jetty-all-compact3/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT ../../pom.xml 4.0.0 @@ -37,8 +37,8 @@
**/MANIFEST.MF,javax/** - javax - javax,org.eclipse.jetty.orbit,org.slf4j,org.ow2.asm + javax,jetty-test-helper + javax,org.eclipse.jetty.orbit,org.slf4j,org.ow2.asm,org.junit ${project.build.directory}/classes false true @@ -54,20 +54,11 @@ sources **/* - META-INF/**, - **/Servlet3Continuation*, - **/Jetty6Continuation*, - **/AppContextLeakPreventer*.java, - **/AWTLeakPreventer*.java, - **/IntrospectorCleaner*.java, - **/PostConstructAnnotationHandler*.java, - **/PreDestroyAnnotationHandler*.java, - **/ResourceAnnotationHandler*.java, - **/ResourcesAnnotationHandler*.java + META-INF/**, **/Servlet3Continuation*, **/Jetty6Continuation*, **/AppContextLeakPreventer*.java, **/AWTLeakPreventer*.java, **/IntrospectorCleaner*.java, **/PostConstructAnnotationHandler*.java, **/PreDestroyAnnotationHandler*.java, **/ResourceAnnotationHandler*.java, **/ResourcesAnnotationHandler*.java org.eclipse.jetty,org.eclipse.jetty.websocket - javax - javax,org.eclipse.jetty.orbit,org.slf4j,org.ow2.asm + javax,jetty-test-helper + javax,org.eclipse.jetty.orbit,org.slf4j,org.ow2.asm,org.junit ${project.build.directory}/sources true true @@ -80,8 +71,7 @@ maven-jar-plugin - - + development https://eclipse.org/jetty diff --git a/aggregates/jetty-all/pom.xml b/aggregates/jetty-all/pom.xml index da9e5fc672c..8d622676c96 100644 --- a/aggregates/jetty-all/pom.xml +++ b/aggregates/jetty-all/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT ../../pom.xml 4.0.0 diff --git a/aggregates/jetty-websocket-all/pom.xml b/aggregates/jetty-websocket-all/pom.xml index a97f298bce9..9c5b1bb3e13 100644 --- a/aggregates/jetty-websocket-all/pom.xml +++ b/aggregates/jetty-websocket-all/pom.xml @@ -63,8 +63,7 @@
- - + development http://eclipse.org/jetty diff --git a/apache-jsp/pom.xml b/apache-jsp/pom.xml index 1110d177325..af93f9ebff8 100644 --- a/apache-jsp/pom.xml +++ b/apache-jsp/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 apache-jsp @@ -10,7 +10,8 @@ http://www.eclipse.org/jetty jar - ${project.groupId}.${project.artifactId} + ${project.groupId}.apache-jsp + ${project.groupId}.apache.jsp @@ -18,17 +19,16 @@ org.apache.felix maven-bundle-plugin true - - - Jetty-specific ServletContainerInitializer for Jasper - org.eclipse.jetty.apache.jsp.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}", - org.eclipse.jetty.jsp.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}" - - osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional - osgi.serviceloader;osgi.serviceloader=javax.servlet.ServletContainerInitializer,osgi.serviceloader;osgi.serviceloader=org.apache.juli.logging.Log - <_nouses>true - - + + + Jetty-specific ServletContainerInitializer for Jasper + org.eclipse.jetty.apache.jsp.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}", org.eclipse.jetty.jsp.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}" + + osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional + osgi.serviceloader;osgi.serviceloader=javax.servlet.ServletContainerInitializer,osgi.serviceloader;osgi.serviceloader=org.apache.juli.logging.Log + <_nouses>true + + org.apache.maven.plugins @@ -60,9 +60,9 @@ - org.eclipse.jetty - jetty-util - ${project.version} + org.eclipse.jetty + jetty-util + ${project.version} @@ -73,8 +73,8 @@ - javax.servlet - javax.servlet-api + javax.servlet + javax.servlet-api @@ -90,7 +90,6 @@ ${project.version} - org.eclipse.jetty diff --git a/apache-jsp/src/main/java/org/eclipse/jetty/apache/jsp/JettyJasperInitializer.java b/apache-jsp/src/main/java/org/eclipse/jetty/apache/jsp/JettyJasperInitializer.java index bbb0ce2111d..9538da980c2 100644 --- a/apache-jsp/src/main/java/org/eclipse/jetty/apache/jsp/JettyJasperInitializer.java +++ b/apache-jsp/src/main/java/org/eclipse/jetty/apache/jsp/JettyJasperInitializer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -23,7 +23,6 @@ import java.net.URL; import java.util.Collection; import java.util.Collections; import java.util.List; - import javax.servlet.ServletContext; import org.apache.jasper.servlet.JasperInitializer; @@ -37,7 +36,8 @@ import org.xml.sax.SAXException; */ public class JettyJasperInitializer extends JasperInitializer { - private static final Log LOG = LogFactory.getLog(JasperInitializer.class); + private static final Log LOG = LogFactory.getLog(JasperInitializer.class); + /** * NullTldScanner * @@ -47,10 +47,7 @@ public class JettyJasperInitializer extends JasperInitializer private final class NullTldScanner extends TldScanner { /** - * @param context - * @param namespaceAware - * @param validation - * @param blockExternal + * */ private NullTldScanner(ServletContext context, boolean namespaceAware, boolean validation, boolean blockExternal) { @@ -81,7 +78,7 @@ public class JettyJasperInitializer extends JasperInitializer @Override public void scanJars() { - return; //do nothing + return; //do nothing } } @@ -91,22 +88,25 @@ public class JettyJasperInitializer extends JasperInitializer */ @Override public TldScanner newTldScanner(ServletContext context, boolean namespaceAware, boolean validate, boolean blockExternal) - { + { String tmp = context.getInitParameter("org.eclipse.jetty.jsp.precompiled"); - if (tmp!=null && !tmp.equals("") && Boolean.valueOf(tmp)) + if (tmp != null && !tmp.equals("") && Boolean.valueOf(tmp)) { - if (LOG.isDebugEnabled()) LOG.debug("Jsp precompilation detected"); + if (LOG.isDebugEnabled()) + LOG.debug("Jsp precompilation detected"); return new NullTldScanner(context, namespaceAware, validate, blockExternal); } - + Collection tldUrls = (Collection)context.getAttribute("org.eclipse.jetty.tlds"); if (tldUrls != null) { - if (LOG.isDebugEnabled()) LOG.debug("Tld pre-scan detected"); - return new JettyTldPreScanned(context,namespaceAware,validate,blockExternal,tldUrls); + if (LOG.isDebugEnabled()) + LOG.debug("Tld pre-scan detected"); + return new JettyTldPreScanned(context, namespaceAware, validate, blockExternal, tldUrls); } - - if (LOG.isDebugEnabled()) LOG.debug("Defaulting to jasper tld scanning"); + + if (LOG.isDebugEnabled()) + LOG.debug("Defaulting to jasper tld scanning"); return super.newTldScanner(context, namespaceAware, validate, blockExternal); } } diff --git a/apache-jsp/src/main/java/org/eclipse/jetty/apache/jsp/JettyTldPreScanned.java b/apache-jsp/src/main/java/org/eclipse/jetty/apache/jsp/JettyTldPreScanned.java index 2ee7e0056a8..f7d8b15f598 100644 --- a/apache-jsp/src/main/java/org/eclipse/jetty/apache/jsp/JettyTldPreScanned.java +++ b/apache-jsp/src/main/java/org/eclipse/jetty/apache/jsp/JettyTldPreScanned.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,12 +16,10 @@ // ======================================================================== // - package org.eclipse.jetty.apache.jsp; import java.net.URL; import java.util.Collection; - import javax.servlet.ServletContext; import org.apache.jasper.servlet.TldPreScanned; @@ -33,25 +31,24 @@ import org.apache.tomcat.util.descriptor.tld.TldResourcePath; * Change to TldPreScanned to not require that the tlds have been * pre-scanned from a jar file, but rather may be files in the * file system. - * + * * This is important for running in the jetty maven plugin * environment in multi-module builds, where modules that contain tlds * may be in the reactor at the same time as a webapp being run with the * plugin. That means that the tlds will be used from their location in * the file system, rather than from their assembled jar. - * */ public class JettyTldPreScanned extends TldPreScanned { private final Collection _jettyPreScannedURLs; - + public JettyTldPreScanned(ServletContext context, boolean namespaceAware, boolean validation, boolean blockExternal, Collection preScannedTlds) { super(context, namespaceAware, validation, blockExternal, preScannedTlds); _jettyPreScannedURLs = preScannedTlds; } - /** + /** * @see org.apache.jasper.servlet.TldPreScanned#scanJars() */ @Override @@ -65,8 +62,8 @@ public class JettyTldPreScanned extends TldPreScanned int a = str.indexOf("jar:"); int b = str.indexOf("META-INF"); if (b < 0) - throw new IllegalStateException("Bad tld url: "+str); - + throw new IllegalStateException("Bad tld url: " + str); + String path = str.substring(b); if (a >= 0) { @@ -95,5 +92,4 @@ public class JettyTldPreScanned extends TldPreScanned } } } - } diff --git a/apache-jsp/src/main/java/org/eclipse/jetty/apache/jsp/JuliLog.java b/apache-jsp/src/main/java/org/eclipse/jetty/apache/jsp/JuliLog.java index 2759fde94a2..3416f3a14ee 100644 --- a/apache-jsp/src/main/java/org/eclipse/jetty/apache/jsp/JuliLog.java +++ b/apache-jsp/src/main/java/org/eclipse/jetty/apache/jsp/JuliLog.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,28 +18,28 @@ package org.eclipse.jetty.apache.jsp; -public class JuliLog implements org.apache.juli.logging.Log +public class JuliLog implements org.apache.juli.logging.Log { public static org.apache.juli.logging.Log getInstance(String name) { return new JuliLog(name); } - + private final org.eclipse.jetty.util.log.Logger _logger; private final org.eclipse.jetty.util.log.StdErrLog _stdErrLog; public JuliLog() - { - _logger=org.eclipse.jetty.util.log.Log.getRootLogger(); - _stdErrLog=(_logger instanceof org.eclipse.jetty.util.log.StdErrLog) ? (org.eclipse.jetty.util.log.StdErrLog)_logger:null; + { + _logger = org.eclipse.jetty.util.log.Log.getRootLogger(); + _stdErrLog = (_logger instanceof org.eclipse.jetty.util.log.StdErrLog) ? (org.eclipse.jetty.util.log.StdErrLog)_logger : null; } - + public JuliLog(String name) { - _logger=org.eclipse.jetty.util.log.Log.getLogger(name); - _stdErrLog=(_logger instanceof org.eclipse.jetty.util.log.StdErrLog) ? (org.eclipse.jetty.util.log.StdErrLog)_logger:null; + _logger = org.eclipse.jetty.util.log.Log.getLogger(name); + _stdErrLog = (_logger instanceof org.eclipse.jetty.util.log.StdErrLog) ? (org.eclipse.jetty.util.log.StdErrLog)_logger : null; } - + @Override public boolean isDebugEnabled() { @@ -49,31 +49,31 @@ public class JuliLog implements org.apache.juli.logging.Log @Override public boolean isErrorEnabled() { - return _stdErrLog==null?true:_stdErrLog.getLevel()<=org.eclipse.jetty.util.log.StdErrLog.LEVEL_WARN; + return _stdErrLog == null || _stdErrLog.getLevel() <= org.eclipse.jetty.util.log.StdErrLog.LEVEL_WARN; } @Override public boolean isFatalEnabled() { - return _stdErrLog==null?true:_stdErrLog.getLevel()<=org.eclipse.jetty.util.log.StdErrLog.LEVEL_WARN; + return _stdErrLog == null || _stdErrLog.getLevel() <= org.eclipse.jetty.util.log.StdErrLog.LEVEL_WARN; } @Override public boolean isInfoEnabled() { - return _stdErrLog==null?true:_stdErrLog.getLevel()<=org.eclipse.jetty.util.log.StdErrLog.LEVEL_INFO; + return _stdErrLog == null || _stdErrLog.getLevel() <= org.eclipse.jetty.util.log.StdErrLog.LEVEL_INFO; } @Override public boolean isTraceEnabled() { - return _stdErrLog==null?true:_stdErrLog.getLevel()<=org.eclipse.jetty.util.log.StdErrLog.LEVEL_DEBUG; + return _stdErrLog == null || _stdErrLog.getLevel() <= org.eclipse.jetty.util.log.StdErrLog.LEVEL_DEBUG; } @Override public boolean isWarnEnabled() { - return _stdErrLog==null?true:_stdErrLog.getLevel()<=org.eclipse.jetty.util.log.StdErrLog.LEVEL_WARN; + return _stdErrLog == null || _stdErrLog.getLevel() <= org.eclipse.jetty.util.log.StdErrLog.LEVEL_WARN; } @Override @@ -82,16 +82,16 @@ public class JuliLog implements org.apache.juli.logging.Log if (message instanceof String) _logger.debug((String)message); else - _logger.debug("{}",message); + _logger.debug("{}", message); } @Override public void trace(Object message, Throwable t) { if (message instanceof String) - _logger.debug((String)message,t); + _logger.debug((String)message, t); else - _logger.debug("{}",message,t); + _logger.debug("{}", message, t); } @Override @@ -100,16 +100,16 @@ public class JuliLog implements org.apache.juli.logging.Log if (message instanceof String) _logger.debug((String)message); else - _logger.debug("{}",message); + _logger.debug("{}", message); } @Override public void debug(Object message, Throwable t) { if (message instanceof String) - _logger.debug((String)message,t); + _logger.debug((String)message, t); else - _logger.debug("{}",message,t); + _logger.debug("{}", message, t); } @Override @@ -118,16 +118,16 @@ public class JuliLog implements org.apache.juli.logging.Log if (message instanceof String) _logger.info((String)message); else - _logger.info("{}",message); + _logger.info("{}", message); } @Override public void info(Object message, Throwable t) { if (message instanceof String) - _logger.info((String)message,t); + _logger.info((String)message, t); else - _logger.info("{}",message,t); + _logger.info("{}", message, t); } @Override @@ -136,16 +136,16 @@ public class JuliLog implements org.apache.juli.logging.Log if (message instanceof String) _logger.warn((String)message); else - _logger.warn("{}",message); + _logger.warn("{}", message); } @Override public void warn(Object message, Throwable t) { if (message instanceof String) - _logger.warn((String)message,t); + _logger.warn((String)message, t); else - _logger.warn("{}",message,t); + _logger.warn("{}", message, t); } @Override @@ -154,16 +154,16 @@ public class JuliLog implements org.apache.juli.logging.Log if (message instanceof String) _logger.warn((String)message); else - _logger.warn("{}",message); + _logger.warn("{}", message); } @Override public void error(Object message, Throwable t) { if (message instanceof String) - _logger.warn((String)message,t); + _logger.warn((String)message, t); else - _logger.warn("{}",message,t); + _logger.warn("{}", message, t); } @Override @@ -172,16 +172,16 @@ public class JuliLog implements org.apache.juli.logging.Log if (message instanceof String) _logger.warn((String)message); else - _logger.warn("{}",message); + _logger.warn("{}", message); } @Override public void fatal(Object message, Throwable t) { if (message instanceof String) - _logger.warn((String)message,t); + _logger.warn((String)message, t); else - _logger.warn("{}",message,t); + _logger.warn("{}", message, t); } } diff --git a/apache-jsp/src/main/java/org/eclipse/jetty/jsp/JettyJspServlet.java b/apache-jsp/src/main/java/org/eclipse/jetty/jsp/JettyJspServlet.java index 4535472d6b5..98d54f0e7a8 100644 --- a/apache-jsp/src/main/java/org/eclipse/jetty/jsp/JettyJspServlet.java +++ b/apache-jsp/src/main/java/org/eclipse/jetty/jsp/JettyJspServlet.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -22,7 +22,6 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; - import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -30,11 +29,10 @@ import javax.servlet.http.HttpServletResponse; import org.apache.jasper.servlet.JspServlet; - /** * JettyJspServlet * - * Wrapper for the jsp servlet that handles receiving requests mapped from + * Wrapper for the jsp servlet that handles receiving requests mapped from * jsp-property-groups. Mappings could be wildcard urls like "/*", which would * include welcome files, but we need those to be handled by the DefaultServlet. */ @@ -42,33 +40,29 @@ public class JettyJspServlet extends JspServlet { /** - * + * */ private static final long serialVersionUID = -5387857473125086791L; - - - - @Override public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { HttpServletRequest request = null; if (req instanceof HttpServletRequest) - request = (HttpServletRequest)req; + request = req; else throw new ServletException("Request not HttpServletRequest"); - String servletPath=null; - String pathInfo=null; - if (request.getAttribute(RequestDispatcher.INCLUDE_REQUEST_URI)!=null) + String servletPath = null; + String pathInfo = null; + if (request.getAttribute(RequestDispatcher.INCLUDE_REQUEST_URI) != null) { - servletPath=(String)request.getAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH); - pathInfo=(String)request.getAttribute(RequestDispatcher.INCLUDE_PATH_INFO); - if (servletPath==null) + servletPath = (String)request.getAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH); + pathInfo = (String)request.getAttribute(RequestDispatcher.INCLUDE_PATH_INFO); + if (servletPath == null) { - servletPath=request.getServletPath(); - pathInfo=request.getPathInfo(); + servletPath = request.getServletPath(); + pathInfo = request.getPathInfo(); } } else @@ -76,9 +70,9 @@ public class JettyJspServlet extends JspServlet servletPath = request.getServletPath(); pathInfo = request.getPathInfo(); } - - String pathInContext = addPaths(servletPath,pathInfo); - + + String pathInContext = addPaths(servletPath, pathInfo); + String jspFile = getInitParameter("jspFile"); //if this is a forced-path from a jsp-file, we want the jsp servlet to handle it, @@ -92,7 +86,7 @@ public class JettyJspServlet extends JspServlet return; } else - { + { //check if it resolves to a directory String realPath = getServletContext().getRealPath(pathInContext); if (realPath != null) @@ -107,7 +101,7 @@ public class JettyJspServlet extends JspServlet } } } - + //fall through to the normal jsp servlet handling super.service(req, resp); } @@ -119,12 +113,12 @@ public class JettyJspServlet extends JspServlet */ private String addPaths(String servletPath, String pathInfo) { - if (servletPath.length()==0) + if (servletPath.isEmpty()) return pathInfo; - - if (pathInfo==null) + + if (pathInfo == null) return servletPath; - - return servletPath+pathInfo; + + return servletPath + pathInfo; } } diff --git a/apache-jsp/src/test/java/org/eclipse/jetty/jsp/TestJettyJspServlet.java b/apache-jsp/src/test/java/org/eclipse/jetty/jsp/TestJettyJspServlet.java index 5bdc155ef4e..9eaf21c1b1e 100644 --- a/apache-jsp/src/test/java/org/eclipse/jetty/jsp/TestJettyJspServlet.java +++ b/apache-jsp/src/test/java/org/eclipse/jetty/jsp/TestJettyJspServlet.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,15 +18,10 @@ package org.eclipse.jetty.jsp; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.not; - import java.io.File; import java.io.IOException; import java.net.URL; import java.net.URLClassLoader; - import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -47,6 +42,10 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.not; + @ExtendWith(WorkDirExtension.class) public class TestJettyJspServlet { @@ -54,7 +53,7 @@ public class TestJettyJspServlet private File _dir; private ServletTester _tester; - + public static class DfltServlet extends HttpServlet { @@ -62,8 +61,8 @@ public class TestJettyJspServlet { super(); } - - /** + + /** * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override @@ -72,11 +71,10 @@ public class TestJettyJspServlet resp.setContentType("html/text"); resp.getOutputStream().println("This.Is.The.Default."); } - } - + @BeforeEach - public void setUp () throws Exception + public void setUp() throws Exception { JspFactory.setDefaultFactory(new JspFactoryImpl()); _dir = MavenTestingUtils.getTestResourceDir("base"); @@ -88,12 +86,12 @@ public class TestJettyJspServlet _tester.getContext().setAttribute(InstanceManager.class.getName(), new SimpleInstanceManager()); ServletHolder dfltHolder = new ServletHolder(); dfltHolder.setName("default"); - dfltHolder.setHeldClass( DfltServlet.class); + dfltHolder.setHeldClass(DfltServlet.class); _tester.getContext().addServlet(dfltHolder, "/"); _tester.start(); } - + @AfterEach public void tearDown() throws Exception { @@ -105,8 +103,8 @@ public class TestJettyJspServlet public void testWithJsp() throws Exception { //test that an ordinary jsp is served by jsp servlet - String request = "" + - "GET /context/foo.jsp HTTP/1.1\r\n" + + String request = + "GET /context/foo.jsp HTTP/1.1\r\n" + "Host: localhost\r\n" + "Connection: close\r\n" + "\r\n"; @@ -115,14 +113,13 @@ public class TestJettyJspServlet HttpTester.Response response = HttpTester.parseResponse(rawResponse); assertThat(response.toString(), response.getContent(), not(containsString("This.Is.The.Default."))); } - - + @Test public void testWithDirectory() throws Exception { //test that a dir is served by the default servlet - String request = "" + - "GET /context/dir HTTP/1.1\r\n" + + String request = + "GET /context/dir HTTP/1.1\r\n" + "Host: localhost\r\n" + "Connection: close\r\n" + "\r\n"; diff --git a/apache-jsp/src/test/java/org/eclipse/jetty/jsp/TestJettyTldPreScanned.java b/apache-jsp/src/test/java/org/eclipse/jetty/jsp/TestJettyTldPreScanned.java index 9c738f987ff..6dcc79e267b 100644 --- a/apache-jsp/src/test/java/org/eclipse/jetty/jsp/TestJettyTldPreScanned.java +++ b/apache-jsp/src/test/java/org/eclipse/jetty/jsp/TestJettyTldPreScanned.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,11 +16,8 @@ // ======================================================================== // - package org.eclipse.jetty.jsp; -import static org.junit.jupiter.api.Assertions.*; - import java.io.File; import java.net.URL; import java.util.ArrayList; @@ -34,10 +31,12 @@ import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.fail; + /** * TestJettyTldPreScanned - * - * */ public class TestJettyTldPreScanned { @@ -47,21 +46,21 @@ public class TestJettyTldPreScanned */ @Test public void testIt() - throws Exception + throws Exception { File jar = MavenTestingUtils.getTestResourceFile("taglib.jar"); File tld = MavenTestingUtils.getTestResourceFile("META-INF/foo-taglib.tld"); - + List list = new ArrayList<>(); - list.add(new URL("jar:"+jar.toURI().toURL().toString()+"!/META-INF/bar-taglib.tld")); + list.add(new URL("jar:" + jar.toURI().toURL().toString() + "!/META-INF/bar-taglib.tld")); list.add(tld.toURI().toURL()); - - JettyTldPreScanned preScanned = new JettyTldPreScanned(new ServletContextHandler().getServletContext(),false,false,false,list); + + JettyTldPreScanned preScanned = new JettyTldPreScanned(new ServletContextHandler().getServletContext(), false, false, false, list); preScanned.scanJars(); Map map = preScanned.getTldResourcePathTaglibXmlMap(); assertNotNull(map); assertEquals(2, map.size()); - for (TldResourcePath p: map.keySet()) + for (TldResourcePath p : map.keySet()) { URL u = p.getUrl(); TaglibXml tlx = map.get(p); @@ -70,5 +69,4 @@ public class TestJettyTldPreScanned fail("unknown tag"); } } - } diff --git a/apache-jsp/src/test/java/org/eclipse/jetty/jsp/TestJspFileNameToClass.java b/apache-jsp/src/test/java/org/eclipse/jetty/jsp/TestJspFileNameToClass.java index 7f0966a7756..4d43f01756c 100644 --- a/apache-jsp/src/test/java/org/eclipse/jetty/jsp/TestJspFileNameToClass.java +++ b/apache-jsp/src/test/java/org/eclipse/jetty/jsp/TestJspFileNameToClass.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,12 +18,11 @@ package org.eclipse.jetty.jsp; -import static org.junit.jupiter.api.Assertions.assertEquals; - import org.eclipse.jetty.servlet.ServletHolder; - import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class TestJspFileNameToClass { @@ -33,18 +32,17 @@ public class TestJspFileNameToClass ServletHolder h = new ServletHolder(); h.setName("test"); + assertEquals(null, h.getClassNameForJsp(null)); - assertEquals(null, h.getClassNameForJsp(null)); + assertEquals(null, h.getClassNameForJsp("")); - assertEquals(null, h.getClassNameForJsp("")); + assertEquals(null, h.getClassNameForJsp("/blah/")); - assertEquals(null, h.getClassNameForJsp("/blah/")); + assertEquals(null, h.getClassNameForJsp("//blah///")); - assertEquals(null, h.getClassNameForJsp("//blah///")); + assertEquals(null, h.getClassNameForJsp("/a/b/c/blah/")); - assertEquals(null, h.getClassNameForJsp("/a/b/c/blah/")); - - assertEquals("org.apache.jsp.a.b.c.blah", h.getClassNameForJsp("/a/b/c/blah")); + assertEquals("org.apache.jsp.a.b.c.blah", h.getClassNameForJsp("/a/b/c/blah")); assertEquals("org.apache.jsp.blah_jsp", h.getClassNameForJsp("/blah.jsp")); @@ -56,5 +54,4 @@ public class TestJspFileNameToClass assertEquals("org.apache.jsp.a.b.c.blah_jsp", h.getClassNameForJsp("a/b/c/blah.jsp")); } - } diff --git a/apache-jstl/pom.xml b/apache-jstl/pom.xml index e4f60b67e04..6f16b399b9f 100644 --- a/apache-jstl/pom.xml +++ b/apache-jstl/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 apache-jstl @@ -10,17 +10,17 @@ http://tomcat.apache.org/taglibs/standard/ jar - ${project.groupId}.apache.jstl + ${project.groupId}.apache.jstl - org.apache.maven.plugins - maven-surefire-plugin - - false - + org.apache.maven.plugins + maven-surefire-plugin + + false + org.jacoco @@ -35,36 +35,36 @@ - org.apache.taglibs - taglibs-standard-spec + org.apache.taglibs + taglibs-standard-spec - org.apache.taglibs - taglibs-standard-impl - - - - org.eclipse.jetty.toolchain - jetty-test-helper - test - - - - org.eclipse.jetty - apache-jsp - ${project.version} - test + org.apache.taglibs + taglibs-standard-impl - org.eclipse.jetty - jetty-annotations - ${project.version} - test + org.eclipse.jetty.toolchain + jetty-test-helper + test - + + + org.eclipse.jetty + apache-jsp + ${project.version} + test + + + + org.eclipse.jetty + jetty-annotations + ${project.version} + test + + org.eclipse.jetty jetty-webapp diff --git a/apache-jstl/src/test/java/org/eclipse/jetty/jstl/JspConfig.java b/apache-jstl/src/test/java/org/eclipse/jetty/jstl/JspConfig.java index f0d7d8ad5f4..948a8dd092a 100644 --- a/apache-jstl/src/test/java/org/eclipse/jetty/jstl/JspConfig.java +++ b/apache-jstl/src/test/java/org/eclipse/jetty/jstl/JspConfig.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -33,7 +33,7 @@ public class JspConfig { context.setAttribute("javax.servlet.context.tempdir", scratchDir); context.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern", - ".*/javax.servlet-[^/]*\\.jar$|.*/servlet-api-[^/]*\\.jar$|.*javax.servlet.jsp.jstl-[^/]*\\.jar|.*taglibs-standard-impl-.*\\.jar"); + ".*/javax.servlet-[^/]*\\.jar$|.*/servlet-api-[^/]*\\.jar$|.*javax.servlet.jsp.jstl-[^/]*\\.jar|.*taglibs-standard-impl-.*\\.jar"); context.setWar(baseUri.toASCIIString()); context.setResourceBase(baseUri.toASCIIString()); } diff --git a/apache-jstl/src/test/java/org/eclipse/jetty/jstl/JspIncludeTest.java b/apache-jstl/src/test/java/org/eclipse/jetty/jstl/JspIncludeTest.java index a7b5069fdf0..323aea25e44 100644 --- a/apache-jstl/src/test/java/org/eclipse/jetty/jstl/JspIncludeTest.java +++ b/apache-jstl/src/test/java/org/eclipse/jetty/jstl/JspIncludeTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,10 +18,6 @@ package org.eclipse.jetty.jstl; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -42,11 +38,15 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.is; + public class JspIncludeTest { private static Server server; private static URI baseUri; - + @BeforeAll public static void startServer() throws Exception { @@ -55,37 +55,37 @@ public class JspIncludeTest ServerConnector connector = new ServerConnector(server); connector.setPort(0); server.addConnector(connector); - + // Setup WebAppContext File testWebAppDir = MavenTestingUtils.getProjectDir("src/test/webapp"); - + // Prepare WebApp libs File libDir = new File(testWebAppDir, "WEB-INF/lib"); FS.ensureDirExists(libDir); File testTagLibDir = MavenTestingUtils.getProjectDir("src/test/taglibjar"); JAR.create(testTagLibDir, new File(libDir, "testtaglib.jar")); - + // Configure WebAppContext Configuration.ClassList classlist = Configuration.ClassList - .setServerDefault(server); + .setServerDefault(server); classlist.addBefore( - "org.eclipse.jetty.webapp.JettyWebXmlConfiguration", - "org.eclipse.jetty.annotations.AnnotationConfiguration"); - + "org.eclipse.jetty.webapp.JettyWebXmlConfiguration", + "org.eclipse.jetty.annotations.AnnotationConfiguration"); + WebAppContext context = new WebAppContext(); context.setContextPath("/"); - + File scratchDir = MavenTestingUtils.getTargetFile("tests/" + JspIncludeTest.class.getSimpleName() + "-scratch"); FS.ensureEmpty(scratchDir); JspConfig.init(context, testWebAppDir.toURI(), scratchDir); - + server.setHandler(context); - + // Start Server server.start(); - + // Figure out Base URI String host = connector.getHost(); if (host == null) @@ -95,13 +95,13 @@ public class JspIncludeTest int port = connector.getLocalPort(); baseUri = new URI(String.format("http://%s:%d/", host, port)); } - + @AfterAll public static void stopServer() throws Exception { server.stop(); } - + @Test public void testTopWithIncluded() throws IOException { @@ -114,13 +114,13 @@ public class JspIncludeTest try { - connection = (HttpURLConnection) uri.toURL().openConnection(); + connection = (HttpURLConnection)uri.toURL().openConnection(); connection.connect(); if (HttpURLConnection.HTTP_OK != connection.getResponseCode()) { String body = getPotentialBody(connection); String err = String.format("GET request failed (%d %s) %s%n%s", connection.getResponseCode(), connection.getResponseMessage(), - uri.toASCIIString(), body); + uri.toASCIIString(), body); throw new IOException(err); } in = connection.getInputStream(); diff --git a/apache-jstl/src/test/java/org/eclipse/jetty/jstl/JstlTest.java b/apache-jstl/src/test/java/org/eclipse/jetty/jstl/JstlTest.java index b164d822a21..fd225c2e45f 100644 --- a/apache-jstl/src/test/java/org/eclipse/jetty/jstl/JstlTest.java +++ b/apache-jstl/src/test/java/org/eclipse/jetty/jstl/JstlTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,18 +18,12 @@ package org.eclipse.jetty.jstl; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.MatcherAssert.assertThat; - import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URI; import java.nio.charset.StandardCharsets; - import javax.servlet.jsp.JspException; import org.eclipse.jetty.server.Server; @@ -44,11 +38,16 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; + public class JstlTest { private static Server server; private static URI baseUri; - + @BeforeAll public static void startServer() throws Exception { @@ -57,37 +56,37 @@ public class JstlTest ServerConnector connector = new ServerConnector(server); connector.setPort(0); server.addConnector(connector); - + // Setup WebAppContext File testWebAppDir = MavenTestingUtils.getProjectDir("src/test/webapp"); - + // Prepare WebApp libs File libDir = new File(testWebAppDir, "WEB-INF/lib"); FS.ensureDirExists(libDir); File testTagLibDir = MavenTestingUtils.getProjectDir("src/test/taglibjar"); - JAR.create(testTagLibDir,new File(libDir, "testtaglib.jar")); - + JAR.create(testTagLibDir, new File(libDir, "testtaglib.jar")); + // Configure WebAppContext - + Configuration.ClassList classlist = Configuration.ClassList - .setServerDefault(server); + .setServerDefault(server); classlist.addBefore( - "org.eclipse.jetty.webapp.JettyWebXmlConfiguration", - "org.eclipse.jetty.annotations.AnnotationConfiguration"); - + "org.eclipse.jetty.webapp.JettyWebXmlConfiguration", + "org.eclipse.jetty.annotations.AnnotationConfiguration"); + WebAppContext context = new WebAppContext(); context.setContextPath("/"); - + File scratchDir = MavenTestingUtils.getTargetFile("tests/" + JstlTest.class.getSimpleName() + "-scratch"); FS.ensureEmpty(scratchDir); - JspConfig.init(context,testWebAppDir.toURI(),scratchDir); - + JspConfig.init(context, testWebAppDir.toURI(), scratchDir); + server.setHandler(context); - + // Start Server server.start(); - + // Figure out Base URI String host = connector.getHost(); if (host == null) @@ -95,22 +94,22 @@ public class JstlTest host = "localhost"; } int port = connector.getLocalPort(); - baseUri = new URI(String.format("http://%s:%d/",host,port)); + baseUri = new URI(String.format("http://%s:%d/", host, port)); } - + @AfterAll public static void stopServer() throws Exception { if (server != null) server.stop(); } - + @Test public void testUrlsBasic() throws IOException { - HttpURLConnection http = (HttpURLConnection) baseUri.resolve("/urls.jsp").toURL().openConnection(); + HttpURLConnection http = (HttpURLConnection)baseUri.resolve("/urls.jsp").toURL().openConnection(); assertThat("http response", http.getResponseCode(), is(200)); - try(InputStream input = http.getInputStream()) + try (InputStream input = http.getInputStream()) { String resp = IO.toString(input, StandardCharsets.UTF_8); assertThat("Response should be JSP processed", resp, not(containsString(""))); diff --git a/apache-jstl/src/test/webapp/WEB-INF/web.xml b/apache-jstl/src/test/webapp/WEB-INF/web.xml index b05e490c65b..6f8edc5b330 100644 --- a/apache-jstl/src/test/webapp/WEB-INF/web.xml +++ b/apache-jstl/src/test/webapp/WEB-INF/web.xml @@ -1,7 +1,4 @@ - + Test webapp for JSTL \ No newline at end of file diff --git a/build-resources/jetty-codestyle-eclipse-ide.xml b/build-resources/jetty-codestyle-eclipse-ide.xml new file mode 100644 index 00000000000..be0cefb9e8a --- /dev/null +++ b/build-resources/jetty-codestyle-eclipse-ide.xml @@ -0,0 +1,354 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build-resources/jetty-codestyle-intellij.xml b/build-resources/jetty-codestyle-intellij.xml new file mode 100644 index 00000000000..131dcd75a29 --- /dev/null +++ b/build-resources/jetty-codestyle-intellij.xml @@ -0,0 +1,533 @@ + + \ No newline at end of file diff --git a/build-resources/pom.xml b/build-resources/pom.xml new file mode 100644 index 00000000000..184f002a74b --- /dev/null +++ b/build-resources/pom.xml @@ -0,0 +1,22 @@ + + 4.0.0 + org.eclipse.jetty + build-resources + 9.4.21-SNAPSHOT + jar + Jetty :: Build Resources + + + + + org.apache.maven.plugins + maven-deploy-plugin + 2.8.2 + + + true + + + + + diff --git a/build-resources/src/main/resources/jetty-checkstyle.xml b/build-resources/src/main/resources/jetty-checkstyle.xml new file mode 100644 index 00000000000..6f6c68a9c69 --- /dev/null +++ b/build-resources/src/main/resources/jetty-checkstyle.xml @@ -0,0 +1,281 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build-resources/src/main/resources/jetty-suppressions.xml b/build-resources/src/main/resources/jetty-suppressions.xml new file mode 100644 index 00000000000..5d84676914e --- /dev/null +++ b/build-resources/src/main/resources/jetty-suppressions.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/async-rest/async-rest-jar/pom.xml b/examples/async-rest/async-rest-jar/pom.xml index 628518e0a7b..61c665a1ece 100644 --- a/examples/async-rest/async-rest-jar/pom.xml +++ b/examples/async-rest/async-rest-jar/pom.xml @@ -2,17 +2,19 @@ org.eclipse.jetty example-async-rest - 9.4.13-SNAPSHOT - + 9.4.21-SNAPSHOT + + 4.0.0 org.eclipse.jetty.example-async-rest example-async-rest-jar jar Example Async Rest :: Jar - http://www.eclipse.org/jetty + - ${project.groupId}.examples.asyc.rest + ${project.parent.groupId}.examples.async.rest + org.eclipse.jetty diff --git a/examples/async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/AbstractRestServlet.java b/examples/async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/AbstractRestServlet.java index 7198dd6e4df..6403ff32ec2 100644 --- a/examples/async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/AbstractRestServlet.java +++ b/examples/async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/AbstractRestServlet.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -24,7 +24,6 @@ import java.math.RoundingMode; import java.net.URLEncoder; import java.util.Map; import java.util.Queue; - import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -43,18 +42,17 @@ import javax.servlet.http.HttpServletResponse; */ public class AbstractRestServlet extends HttpServlet { - protected final static String __DEFAULT_APPID = "Webtide81-adf4-4f0a-ad58-d91e41bbe85"; - protected final static String STYLE = - ""; - protected final static String ITEMS_PARAM = "items"; - protected final static String APPID_PARAM = "appid"; + protected static final String ITEMS_PARAM = "items"; + protected static final String APPID_PARAM = "appid"; protected String _appid; @@ -67,41 +65,54 @@ public class AbstractRestServlet extends HttpServlet _appid = servletConfig.getInitParameter(APPID_PARAM); } - - public static String sanitize(String s) + // TODO: consider using StringUtil.sanitizeFileSystemName instead of this? + // might introduce jetty-util dependency though + public static String sanitize(String str) { - if (s==null) + if (str == null) return null; - return s.replace("<","?").replace("&","?").replace("\n","?"); + + char[] chars = str.toCharArray(); + int len = chars.length; + for (int i = 0; i < len; i++) + { + char c = chars[i]; + if ((c <= 0x1F) || // control characters + (c == '<') || (c == '&')) + { + chars[i] = '?'; + } + } + return String.valueOf(chars); } - - protected String restURL(String item) + + protected String restURL(String item) { try { - return ("http://open.api.ebay.com/shopping?MaxEntries=3&appid=" + _appid + - "&version=573&siteid=0&callname=FindItems&responseencoding=JSON&QueryKeywords=" + - URLEncoder.encode(item,"UTF-8")); + return ("http://open.api.ebay.com/shopping?MaxEntries=3&appid=" + _appid + + "&version=573&siteid=0&callname=FindItems&responseencoding=JSON&QueryKeywords=" + + URLEncoder.encode(item, "UTF-8")); } - catch(Exception e) + catch (Exception e) { throw new RuntimeException(e); } } - - protected String generateThumbs(Queue> results) + + protected String generateThumbs(Queue> results) { StringBuilder thumbs = new StringBuilder(); for (Map m : results) { if (!m.containsKey("GalleryURL")) continue; - - thumbs.append(""); - thumbs.append(""); + + thumbs.append(""); + thumbs.append(""); thumbs.append(" "); } return thumbs.toString(); @@ -110,21 +121,20 @@ public class AbstractRestServlet extends HttpServlet protected String ms(long nano) { BigDecimal dec = new BigDecimal(nano); - return dec.divide(new BigDecimal(1000000L)).setScale(1,RoundingMode.UP).toString(); + return dec.divide(new BigDecimal(1000000L)).setScale(1, RoundingMode.UP).toString(); } - + protected int width(long nano) { - int w=(int)((nano+999999L)/5000000L); - if (w==0) - w=2; + int w = (int)((nano + 999999L) / 5000000L); + if (w == 0) + w = 2; return w; } - + @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } - } diff --git a/examples/async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/AsyncRestServlet.java b/examples/async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/AsyncRestServlet.java index f09b28e93fe..c7754f466d9 100644 --- a/examples/async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/AsyncRestServlet.java +++ b/examples/async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/AsyncRestServlet.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -25,7 +25,6 @@ import java.util.Map; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicInteger; - import javax.servlet.AsyncContext; import javax.servlet.ServletConfig; import javax.servlet.ServletException; @@ -52,9 +51,9 @@ import org.eclipse.jetty.util.ajax.JSON; */ public class AsyncRestServlet extends AbstractRestServlet { - final static String RESULTS_ATTR = "org.eclipse.jetty.demo.client"; - final static String DURATION_ATTR = "org.eclipse.jetty.demo.duration"; - final static String START_ATTR = "org.eclispe.jetty.demo.start"; + static final String RESULTS_ATTR = "org.eclipse.jetty.demo.client"; + static final String DURATION_ATTR = "org.eclipse.jetty.demo.duration"; + static final String START_ATTR = "org.eclispe.jetty.demo.start"; HttpClient _client; @@ -78,17 +77,17 @@ public class AsyncRestServlet extends AbstractRestServlet @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - Long start=System.nanoTime(); + Long start = System.nanoTime(); // Do we have results yet? - Queue> results = (Queue>) request.getAttribute(RESULTS_ATTR); + Queue> results = (Queue>)request.getAttribute(RESULTS_ATTR); // If no results, this must be the first dispatch, so send the REST request(s) - if (results==null) + if (results == null) { // define results data structures final Queue> resultsQueue = new ConcurrentLinkedQueue<>(); - request.setAttribute(RESULTS_ATTR, results=resultsQueue); + request.setAttribute(RESULTS_ATTR, results = resultsQueue); // suspend the request // This is done before scheduling async handling to avoid race of @@ -97,24 +96,25 @@ public class AsyncRestServlet extends AbstractRestServlet async.setTimeout(30000); // extract keywords to search for - String[] keywords=sanitize(request.getParameter(ITEMS_PARAM)).split(","); - final AtomicInteger outstanding=new AtomicInteger(keywords.length); + String[] keywords = sanitize(request.getParameter(ITEMS_PARAM)).split(","); + final AtomicInteger outstanding = new AtomicInteger(keywords.length); // Send request each keyword - for (final String item:keywords) + for (final String item : keywords) { _client.newRequest(restURL(item)).method(HttpMethod.GET).send( new AsyncRestRequest() { @Override - void onAuctionFound(Map auction) + void onAuctionFound(Map auction) { resultsQueue.add(auction); } + @Override void onComplete() { - if (outstanding.decrementAndGet()<=0) + if (outstanding.decrementAndGet() <= 0) async.dispatch(); } }); @@ -138,23 +138,23 @@ public class AsyncRestServlet extends AbstractRestServlet out.println(STYLE); out.println(""); - long initial = (Long) request.getAttribute(DURATION_ATTR); - long start0 = (Long) request.getAttribute(START_ATTR); + long initial = (Long)request.getAttribute(DURATION_ATTR); + long start0 = (Long)request.getAttribute(START_ATTR); long now = System.nanoTime(); - long total=now-start0; - long generate=now-start; - long thread=initial+generate; + long total = now - start0; + long generate = now - start; + long thread = initial + generate; - out.print("Asynchronous: "+sanitize(request.getParameter(ITEMS_PARAM))+"
"); - out.print("Total Time: "+ms(total)+"ms
"); + out.print("Asynchronous: " + sanitize(request.getParameter(ITEMS_PARAM)) + "
"); + out.print("Total Time: " + ms(total) + "ms
"); - out.print("Thread held (red): "+ms(thread)+"ms (" + ms(initial) + " initial + " + ms(generate) + " generate )
"); - out.print("Async wait (green): "+ms(total-thread)+"ms
"); + out.print("Thread held (red): " + ms(thread) + "ms (" + ms(initial) + " initial + " + ms(generate) + " generate )
"); + out.print("Async wait (green): " + ms(total - thread) + "ms
"); - out.println(""+ - ""+ - ""); + out.println("" + + "" + + ""); out.println("
"); out.println(thumbs); @@ -162,7 +162,7 @@ public class AsyncRestServlet extends AbstractRestServlet out.println(""); out.close(); } - + private abstract class AsyncRestRequest extends Response.Listener.Adapter { final Utf8StringBuilder _content = new Utf8StringBuilder(); @@ -175,27 +175,28 @@ public class AsyncRestServlet extends AbstractRestServlet public void onContent(Response response, ByteBuffer content) { byte[] bytes = BufferUtil.toArray(content); - _content.append(bytes,0,bytes.length); + _content.append(bytes, 0, bytes.length); } @Override public void onComplete(Result result) { // extract auctions from the results - Map query = (Map) JSON.parse(_content.toString()); - Object[] auctions = (Object[]) query.get("Item"); + Map query = (Map)JSON.parse(_content.toString()); + Object[] auctions = (Object[])query.get("Item"); if (auctions != null) { for (Object o : auctions) - onAuctionFound((Map)o); + { + onAuctionFound((Map)o); + } } onComplete(); - } - abstract void onAuctionFound(Map details); - abstract void onComplete(); + abstract void onAuctionFound(Map details); + abstract void onComplete(); } @Override diff --git a/examples/async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/SerialRestServlet.java b/examples/async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/SerialRestServlet.java index c9093c1e8de..afa291ec873 100644 --- a/examples/async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/SerialRestServlet.java +++ b/examples/async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/SerialRestServlet.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -27,7 +27,6 @@ import java.net.URL; import java.util.LinkedList; import java.util.Map; import java.util.Queue; - import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -39,37 +38,37 @@ import org.eclipse.jetty.util.ajax.JSON; * Servlet implementation class SerialRestServlet */ public class SerialRestServlet extends AbstractRestServlet -{ +{ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { long start = System.nanoTime(); - - String[] keywords=sanitize(request.getParameter(ITEMS_PARAM)).split(","); - Queue> results = new LinkedList>(); - + String[] keywords = sanitize(request.getParameter(ITEMS_PARAM)).split(","); + Queue> results = new LinkedList>(); + // make all requests serially for (String itemName : keywords) { URL url = new URL(restURL(itemName)); - + HttpURLConnection connection = (HttpURLConnection)url.openConnection(); connection.setRequestMethod("GET"); - + Map query = (Map)JSON.parse(new BufferedReader(new InputStreamReader(connection.getInputStream()))); - Object[] auctions = (Object[]) query.get("Item"); + Object[] auctions = (Object[])query.get("Item"); if (auctions != null) { for (Object o : auctions) - results.add((Map) o); + { + results.add((Map)o); + } } } - // Generate the response - String thumbs=generateThumbs(results); - + String thumbs = generateThumbs(results); + response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println(""); @@ -77,32 +76,28 @@ public class SerialRestServlet extends AbstractRestServlet out.println(""); long now = System.nanoTime(); - long total=now-start; + long total = now - start; + + out.print("Blocking: " + sanitize(request.getParameter(ITEMS_PARAM)) + "
"); + out.print("Total Time: " + ms(total) + "ms
"); + out.print("Thread held (red): " + ms(total) + "ms
"); + + out.println(""); - out.print("Blocking: "+sanitize(request.getParameter(ITEMS_PARAM))+"
"); - out.print("Total Time: "+ms(total)+"ms
"); - out.print("Thread held (red): "+ms(total)+"ms
"); - - out.println(""); - out.println("
"); out.println(thumbs); out.println("
"); out.println(""); out.close(); - - - } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse - * response) + * response) */ @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } - } diff --git a/examples/async-rest/async-rest-webapp/pom.xml b/examples/async-rest/async-rest-webapp/pom.xml index 382e262a0fa..aead283d7db 100644 --- a/examples/async-rest/async-rest-webapp/pom.xml +++ b/examples/async-rest/async-rest-webapp/pom.xml @@ -2,16 +2,19 @@ org.eclipse.jetty example-async-rest - 9.4.13-SNAPSHOT - + 9.4.21-SNAPSHOT + + 4.0.0 org.eclipse.jetty.example-async-rest example-async-rest-webapp war Example Async Rest :: Webapp + async-rest + org.eclipse.jetty.example-async-rest @@ -24,10 +27,10 @@ ${project.version} test - - javax.servlet - javax.servlet-api - provided - + + javax.servlet + javax.servlet-api + provided + diff --git a/examples/async-rest/async-rest-webapp/src/main/webapp/WEB-INF/jetty-web.xml b/examples/async-rest/async-rest-webapp/src/main/webapp/WEB-INF/jetty-web.xml index c15dc38f119..efc589f0972 100644 --- a/examples/async-rest/async-rest-webapp/src/main/webapp/WEB-INF/jetty-web.xml +++ b/examples/async-rest/async-rest-webapp/src/main/webapp/WEB-INF/jetty-web.xml @@ -1,5 +1,4 @@ - - + diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/AsyncEchoServlet.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/AsyncEchoServlet.java index f186dca3198..e225703dc2b 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/AsyncEchoServlet.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/AsyncEchoServlet.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,7 +20,6 @@ package org.eclipse.jetty.embedded; import java.io.IOException; import java.util.concurrent.atomic.AtomicBoolean; - import javax.servlet.AsyncContext; import javax.servlet.ReadListener; import javax.servlet.ServletException; @@ -31,7 +30,6 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; - public class AsyncEchoServlet extends HttpServlet { private static final long serialVersionUID = 1L; @@ -60,7 +58,7 @@ public class AsyncEchoServlet extends HttpServlet this.input = asyncContext.getRequest().getInputStream(); this.output = asyncContext.getResponse().getOutputStream(); } - + @Override public void onDataAvailable() throws IOException { @@ -78,7 +76,7 @@ public class AsyncEchoServlet extends HttpServlet { handleAsyncIO(); } - + private void handleAsyncIO() throws IOException { // This method is called: @@ -86,7 +84,7 @@ public class AsyncEchoServlet extends HttpServlet // 2) after first registering a ReadListener iff write is ready // 3) when a previous write completes after an output.isReady() returns false // 4) from an input callback - + // We should try to read, only if we are able to write! while (true) { @@ -98,15 +96,15 @@ public class AsyncEchoServlet extends HttpServlet if (!input.isReady()) // Nothing available to read, so wait for another call to onDataAvailable break; - + int read = input.read(buffer); - if (read<0) + if (read < 0) { - if (complete.compareAndSet(false,true)) + if (complete.compareAndSet(false, true)) asyncContext.complete(); break; } - else if (read>0) + else if (read > 0) { output.write(buffer, 0, read); } @@ -116,7 +114,7 @@ public class AsyncEchoServlet extends HttpServlet @Override public void onError(Throwable failure) { - new Throwable("onError",failure).printStackTrace(); + new Throwable("onError", failure).printStackTrace(); asyncContext.complete(); } } diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/DumpServlet.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/DumpServlet.java index 96dd9139481..38372558bd8 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/DumpServlet.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/DumpServlet.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,8 +20,6 @@ package org.eclipse.jetty.embedded; import java.io.IOException; import java.io.PrintWriter; - -import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -30,9 +28,8 @@ import javax.servlet.http.HttpServletResponse; public class DumpServlet extends HttpServlet { @Override - protected void doGet( HttpServletRequest request, - HttpServletResponse response ) throws ServletException, - IOException + protected void doGet(HttpServletRequest request, + HttpServletResponse response) throws IOException { response.setContentType("text/html"); response.setStatus(HttpServletResponse.SC_OK); @@ -51,8 +48,7 @@ public class DumpServlet extends HttpServlet String r = request.getParameter("resource"); if (r != null) { - out.println("resource(" + r + ")=" - + getServletContext().getResource(r)); + out.println("resource(" + r + ")=" + getServletContext().getResource(r)); } out.println(""); diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ExampleServer.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ExampleServer.java index 43447a34ba5..b4d5ac45fff 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ExampleServer.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ExampleServer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -28,13 +28,13 @@ import org.eclipse.jetty.servlet.ServletContextHandler; public class ExampleServer { - public static void main( String[] args ) throws Exception + public static void main(String[] args) throws Exception { Server server = new Server(); ServerConnector connector = new ServerConnector(server); connector.setPort(8080); - server.setConnectors(new Connector[] { connector }); + server.setConnectors(new Connector[]{connector}); ServletContextHandler context = new ServletContextHandler(); context.setContextPath("/"); @@ -42,7 +42,7 @@ public class ExampleServer context.addServlet(AsyncEchoServlet.class, "/echo/*"); HandlerCollection handlers = new HandlerCollection(); - handlers.setHandlers(new Handler[] { context, new DefaultHandler() }); + handlers.setHandlers(new Handler[]{context, new DefaultHandler()}); server.setHandler(handlers); server.start(); diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ExampleServerXml.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ExampleServerXml.java index 506d5a5e80a..e65f001967a 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ExampleServerXml.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ExampleServerXml.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -29,7 +29,7 @@ import org.eclipse.jetty.xml.XmlConfiguration; */ public class ExampleServerXml { - public static void main( String[] args ) throws Exception + public static void main(String[] args) throws Exception { // Find Jetty XML (in classpath) that configures and starts Server. Resource serverXml = Resource.newSystemResource("exampleserver.xml"); diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/FastFileServer.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/FastFileServer.java index 2bb25507c91..bfcc5493637 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/FastFileServer.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/FastFileServer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -25,7 +25,6 @@ import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.FileChannel.MapMode; import java.nio.file.StandardOpenOption; - import javax.servlet.AsyncContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -59,14 +58,15 @@ import org.eclipse.jetty.util.resource.Resource; */ public class FastFileServer { - public static void main( String[] args ) throws Exception + public static void main(String[] args) throws Exception { Server server = new Server(8080); HandlerList handlers = new HandlerList(); - handlers.setHandlers(new Handler[] { - new FastFileHandler(new File(System.getProperty("user.dir"))), - new DefaultHandler() }); + handlers.setHandlers(new Handler[]{ + new FastFileHandler(new File(System.getProperty("user.dir"))), + new DefaultHandler() + }); server.setHandler(handlers); server.start(); @@ -78,17 +78,17 @@ public class FastFileServer private final MimeTypes mimeTypes = new MimeTypes(); private final File dir; - private FastFileHandler( File dir ) + private FastFileHandler(File dir) { this.dir = dir; } @Override - public void handle( String target, - Request baseRequest, - HttpServletRequest request, - HttpServletResponse response ) throws IOException, - ServletException + public void handle(String target, + Request baseRequest, + HttpServletRequest request, + HttpServletResponse response) throws IOException, + ServletException { // define small medium and large. // This should be turned for your content, JVM and OS, but we will @@ -111,19 +111,20 @@ public class FastFileServer { if (!request.getPathInfo().endsWith(URIUtil.SLASH)) { - response.sendRedirect(response.encodeRedirectURL(request.getRequestURI()+URIUtil.SLASH)); + response.sendRedirect(response.encodeRedirectURL(request.getRequestURI() + URIUtil.SLASH)); return; } String listing = Resource.newResource(file).getListHTML( - request.getRequestURI(), - request.getPathInfo().lastIndexOf("/") > 0); + request.getRequestURI(), + request.getPathInfo().lastIndexOf("/") > 0, + request.getQueryString()); response.setContentType("text/html; charset=utf-8"); response.getWriter().println(listing); return; } // Set some content headers. - + // Jetty DefaultServlet will cache formatted date strings, but we // will reformat for each request here response.setDateHeader("Last-Modified", file.lastModified()); @@ -134,9 +135,9 @@ public class FastFileServer if (file.length() < SMALL) { // need to caste to Jetty output stream for best API - ((HttpOutput) response.getOutputStream()) - .sendContent(FileChannel.open(file.toPath(), - StandardOpenOption.READ)); + ((HttpOutput)response.getOutputStream()) + .sendContent(FileChannel.open(file.toPath(), + StandardOpenOption.READ)); return; } @@ -153,7 +154,7 @@ public class FastFileServer } @Override - public void failed( Throwable x ) + public void failed(Throwable x) { // log error and complete async response; x.printStackTrace(); @@ -165,9 +166,9 @@ public class FastFileServer if (file.length() < MEDIUM) { // the file channel is closed by the async send - ((HttpOutput) response.getOutputStream()) - .sendContent(FileChannel.open(file.toPath(), - StandardOpenOption.READ), completionCB); + ((HttpOutput)response.getOutputStream()) + .sendContent(FileChannel.open(file.toPath(), + StandardOpenOption.READ), completionCB); return; } @@ -176,10 +177,10 @@ public class FastFileServer // can be hard to GC on some JVMs. But for this example we will // create a new buffer per file ByteBuffer buffer; - try ( RandomAccessFile raf = new RandomAccessFile(file, "r"); ) + try (RandomAccessFile raf = new RandomAccessFile(file, "r")) { buffer = raf.getChannel().map(MapMode.READ_ONLY, 0, - raf.length()); + raf.length()); } // Assuming the file buffer might be shared cached version, so lets @@ -188,8 +189,8 @@ public class FastFileServer // send the content as a buffer with a callback to complete the // async request need to caste to Jetty output stream for best API - ((HttpOutput) response.getOutputStream()).sendContent(buffer, - completionCB); + ((HttpOutput)response.getOutputStream()).sendContent(buffer, + completionCB); } } } diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/FileServer.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/FileServer.java index 34df743d930..1934f2e7312 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/FileServer.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/FileServer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -24,7 +24,7 @@ import org.eclipse.jetty.server.handler.DefaultHandler; import org.eclipse.jetty.server.handler.HandlerList; import org.eclipse.jetty.server.handler.ResourceHandler; -/** +/** * Simple Jetty FileServer. * This is a simple example of Jetty configured as a FileServer. */ @@ -39,17 +39,17 @@ public class FileServer // Create the ResourceHandler. It is the object that will actually handle the request for a given file. It is // a Jetty Handler object so it is suitable for chaining with other handlers as you will see in other examples. - ResourceHandler resource_handler = new ResourceHandler(); - + ResourceHandler resourceHandler = new ResourceHandler(); + // Configure the ResourceHandler. Setting the resource base indicates where the files should be served out of. // In this example it is the current directory but it can be configured to anything that the jvm has access to. - resource_handler.setDirectoriesListed(true); - resource_handler.setWelcomeFiles(new String[]{ "index.html" }); - resource_handler.setResourceBase("."); + resourceHandler.setDirectoriesListed(true); + resourceHandler.setWelcomeFiles(new String[]{"index.html"}); + resourceHandler.setResourceBase("."); // Add the ResourceHandler to the server. HandlerList handlers = new HandlerList(); - handlers.setHandlers(new Handler[] { resource_handler, new DefaultHandler() }); + handlers.setHandlers(new Handler[]{resourceHandler, new DefaultHandler()}); server.setHandler(handlers); // Start things up! By using the server.join() the server thread will join with the current thread. diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/FileServerXml.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/FileServerXml.java index 33ec7a9ca5c..8b37cdb6fdd 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/FileServerXml.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/FileServerXml.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -34,12 +34,11 @@ import org.eclipse.jetty.xml.XmlConfiguration; */ public class FileServerXml { - public static void main( String[] args ) throws Exception + public static void main(String[] args) throws Exception { - Resource fileserverXml = Resource.newSystemResource("fileserver.xml"); - XmlConfiguration configuration = new XmlConfiguration( - fileserverXml.getInputStream()); - Server server = (Server) configuration.configure(); + Resource fileServerXml = Resource.newSystemResource("fileserver.xml"); + XmlConfiguration configuration = new XmlConfiguration(fileServerXml); + Server server = (Server)configuration.configure(); server.start(); server.join(); } diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/HelloHandler.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/HelloHandler.java index ec7fd04ecc0..4ddf274c547 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/HelloHandler.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/HelloHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,7 +20,6 @@ package org.eclipse.jetty.embedded; import java.io.IOException; import java.io.PrintWriter; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -38,23 +37,23 @@ public class HelloHandler extends AbstractHandler this("Hello World"); } - public HelloHandler( String greeting ) + public HelloHandler(String greeting) { this(greeting, null); } - public HelloHandler( String greeting, String body ) + public HelloHandler(String greeting, String body) { this.greeting = greeting; this.body = body; } @Override - public void handle( String target, - Request baseRequest, - HttpServletRequest request, - HttpServletResponse response ) throws IOException, - ServletException + public void handle(String target, + Request baseRequest, + HttpServletRequest request, + HttpServletResponse response) throws IOException, + ServletException { response.setContentType("text/html; charset=utf-8"); response.setStatus(HttpServletResponse.SC_OK); diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/HelloServlet.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/HelloServlet.java index f58edee149c..a36957f7e73 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/HelloServlet.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/HelloServlet.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,7 +19,6 @@ package org.eclipse.jetty.embedded; import java.io.IOException; - import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -35,19 +34,19 @@ public class HelloServlet extends HttpServlet this("Hello"); } - public HelloServlet( String greeting ) + public HelloServlet(String greeting) { this.greeting = greeting; } @Override - protected void doGet( HttpServletRequest request, - HttpServletResponse response ) throws ServletException, - IOException + protected void doGet(HttpServletRequest request, + HttpServletResponse response) throws ServletException, + IOException { response.setContentType("text/html"); response.setStatus(HttpServletResponse.SC_OK); response.getWriter().println( - "

" + greeting + " from HelloServlet

"); + "

" + greeting + " from HelloServlet

"); } } diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/HelloSessionServlet.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/HelloSessionServlet.java index be66f201a54..4febfb8eb80 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/HelloSessionServlet.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/HelloSessionServlet.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,7 +20,6 @@ package org.eclipse.jetty.embedded; import java.io.IOException; import java.io.PrintWriter; - import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -30,21 +29,23 @@ import javax.servlet.http.HttpSession; @SuppressWarnings("serial") public class HelloSessionServlet extends HttpServlet { - public HelloSessionServlet() {} + public HelloSessionServlet() + { + } @Override - protected void doGet( HttpServletRequest request, - HttpServletResponse response ) throws ServletException, - IOException + protected void doGet(HttpServletRequest request, + HttpServletResponse response) throws ServletException, + IOException { response.setContentType("text/html"); response.setStatus(HttpServletResponse.SC_OK); - response.addHeader("Cache-Control","no-cache"); - + response.addHeader("Cache-Control", "no-cache"); + HttpSession session = request.getSession(); String message; String link; - + String greeting = request.getParameter("greeting"); if (greeting != null) { @@ -56,7 +57,7 @@ public class HelloSessionServlet extends HttpServlet { greeting = (String)session.getAttribute("greeting"); - if (greeting != null) + if (greeting != null) { message = "Greeting '" + greeting + "' set from session."; } @@ -68,17 +69,15 @@ public class HelloSessionServlet extends HttpServlet link = "Click here to set a new greeting."; } - + PrintWriter out = response.getWriter(); out.println("

" + greeting + " from HelloSessionServlet

"); out.println("

" + message + "

"); out.println("
");
-        out.println("session.getId() = " +session.getId());
-        out.println("session.isNew() = " +session.isNew());
+        out.println("session.getId() = " + session.getId());
+        out.println("session.isNew() = " + session.isNew());
         out.println("
"); out.println("

" + link + "

"); - } - } diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/HelloWorld.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/HelloWorld.java index 8620d00808e..151432fe6b9 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/HelloWorld.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/HelloWorld.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,7 +19,6 @@ package org.eclipse.jetty.embedded; import java.io.IOException; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -31,11 +30,11 @@ import org.eclipse.jetty.server.handler.AbstractHandler; public class HelloWorld extends AbstractHandler { @Override - public void handle( String target, - Request baseRequest, - HttpServletRequest request, - HttpServletResponse response ) throws IOException, - ServletException + public void handle(String target, + Request baseRequest, + HttpServletRequest request, + HttpServletResponse response) throws IOException, + ServletException { // Declare response encoding and types response.setContentType("text/html; charset=utf-8"); @@ -50,7 +49,7 @@ public class HelloWorld extends AbstractHandler baseRequest.setHandled(true); } - public static void main( String[] args ) throws Exception + public static void main(String[] args) throws Exception { Server server = new Server(8080); server.setHandler(new HelloWorld()); diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/Http2Server.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/Http2Server.java index dd55e810565..fa69dba7c23 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/Http2Server.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/Http2Server.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,16 +16,13 @@ // ======================================================================== // - package org.eclipse.jetty.embedded; import java.io.File; import java.io.IOException; import java.lang.management.ManagementFactory; -import java.nio.file.Files; import java.util.Date; import java.util.EnumSet; - import javax.servlet.DispatcherType; import javax.servlet.Filter; import javax.servlet.FilterChain; @@ -59,75 +56,74 @@ import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.servlets.PushCacheFilter; import org.eclipse.jetty.util.ssl.SslContextFactory; - -/* ------------------------------------------------------------ */ /** + * */ public class Http2Server { public static void main(String... args) throws Exception - { + { Server server = new Server(); MBeanContainer mbContainer = new MBeanContainer( - ManagementFactory.getPlatformMBeanServer()); + ManagementFactory.getPlatformMBeanServer()); server.addBean(mbContainer); - ServletContextHandler context = new ServletContextHandler(server, "/",ServletContextHandler.SESSIONS); + ServletContextHandler context = new ServletContextHandler(server, "/", ServletContextHandler.SESSIONS); String docroot = "src/main/resources/docroot"; if (!new File(docroot).exists()) docroot = "examples/embedded/src/main/resources/docroot"; context.setResourceBase(docroot); - context.addFilter(PushCacheFilter.class,"/*",EnumSet.of(DispatcherType.REQUEST)); + context.addFilter(PushCacheFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST)); // context.addFilter(PushSessionCacheFilter.class,"/*",EnumSet.of(DispatcherType.REQUEST)); - context.addFilter(PushedTilesFilter.class,"/*",EnumSet.of(DispatcherType.REQUEST)); + context.addFilter(PushedTilesFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST)); context.addServlet(new ServletHolder(servlet), "/test/*"); - context.addServlet(DefaultServlet.class, "/").setInitParameter("maxCacheSize","81920"); + context.addServlet(DefaultServlet.class, "/").setInitParameter("maxCacheSize", "81920"); server.setHandler(context); // HTTP Configuration - HttpConfiguration http_config = new HttpConfiguration(); - http_config.setSecureScheme("https"); - http_config.setSecurePort(8443); - http_config.setSendXPoweredBy(true); - http_config.setSendServerVersion(true); + HttpConfiguration httpConfig = new HttpConfiguration(); + httpConfig.setSecureScheme("https"); + httpConfig.setSecurePort(8443); + httpConfig.setSendXPoweredBy(true); + httpConfig.setSendServerVersion(true); // HTTP Connector - ServerConnector http = new ServerConnector(server,new HttpConnectionFactory(http_config), new HTTP2CServerConnectionFactory(http_config)); + ServerConnector http = new ServerConnector(server, new HttpConnectionFactory(httpConfig), new HTTP2CServerConnectionFactory(httpConfig)); http.setPort(8080); server.addConnector(http); // SSL Context Factory for HTTPS and HTTP/2 - String jetty_distro = System.getProperty("jetty.distro","../../jetty-distribution/target/distribution"); - if (!new File(jetty_distro).exists()) - jetty_distro = "jetty-distribution/target/distribution"; - SslContextFactory sslContextFactory = new SslContextFactory(); - sslContextFactory.setKeyStorePath(jetty_distro + "/demo-base/etc/keystore"); + String jettyDistro = System.getProperty("jetty.distro", "../../jetty-distribution/target/distribution"); + if (!new File(jettyDistro).exists()) + jettyDistro = "jetty-distribution/target/distribution"; + SslContextFactory sslContextFactory = new SslContextFactory.Server(); + sslContextFactory.setKeyStorePath(jettyDistro + "/demo-base/etc/keystore"); sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"); sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g"); sslContextFactory.setCipherComparator(HTTP2Cipher.COMPARATOR); // sslContextFactory.setProvider("Conscrypt"); // HTTPS Configuration - HttpConfiguration https_config = new HttpConfiguration(http_config); - https_config.addCustomizer(new SecureRequestCustomizer()); + HttpConfiguration httpsConfig = new HttpConfiguration(httpConfig); + httpsConfig.addCustomizer(new SecureRequestCustomizer()); // HTTP/2 Connection Factory - HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(https_config); + HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(httpsConfig); ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory(); alpn.setDefaultProtocol(http.getDefaultProtocol()); // SSL Connection Factory - SslConnectionFactory ssl = new SslConnectionFactory(sslContextFactory,alpn.getProtocol()); + SslConnectionFactory ssl = new SslConnectionFactory(sslContextFactory, alpn.getProtocol()); // HTTP/2 Connector ServerConnector http2Connector = - new ServerConnector(server,ssl,alpn,h2,new HttpConnectionFactory(https_config)); + new ServerConnector(server, ssl, alpn, h2, new HttpConnectionFactory(httpsConfig)); http2Connector.setPort(8443); server.addConnector(http2Connector); - ALPN.debug=false; + ALPN.debug = false; server.start(); server.join(); @@ -145,21 +141,21 @@ public class Http2Server { Request baseRequest = Request.getBaseRequest(request); - if (baseRequest.isPush() && baseRequest.getRequestURI().contains("tiles") ) + if (baseRequest.isPush() && baseRequest.getRequestURI().contains("tiles")) { - String uri = baseRequest.getRequestURI().replace("tiles","pushed").substring(baseRequest.getContextPath().length()); - request.getRequestDispatcher(uri).forward(request,response); + String uri = baseRequest.getRequestURI().replace("tiles", "pushed").substring(baseRequest.getContextPath().length()); + request.getRequestDispatcher(uri).forward(request, response); return; } - chain.doFilter(request,response); + chain.doFilter(request, response); } @Override public void destroy() { } - }; + } static Servlet servlet = new HttpServlet() { @@ -168,25 +164,27 @@ public class Http2Server @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - String code=request.getParameter("code"); - if (code!=null) + String code = request.getParameter("code"); + if (code != null) response.setStatus(Integer.parseInt(code)); HttpSession session = request.getSession(true); if (session.isNew()) response.addCookie(new Cookie("bigcookie", - "This is a test cookies that was created on "+new Date()+" and is used by the jetty http/2 test servlet.")); - response.setHeader("Custom","Value"); + "This is a test cookies that was created on " + new Date() + " and is used by the jetty http/2 test servlet.")); + response.setHeader("Custom", "Value"); response.setContentType("text/plain"); - String content = "Hello from Jetty using "+request.getProtocol() +"\n"; - content+="uri="+request.getRequestURI()+"\n"; - content+="session="+session.getId()+(session.isNew()?"(New)\n":"\n"); - content+="date="+new Date()+"\n"; + String content = "Hello from Jetty using " + request.getProtocol() + "\n"; + content += "uri=" + request.getRequestURI() + "\n"; + content += "session=" + session.getId() + (session.isNew() ? "(New)\n" : "\n"); + content += "date=" + new Date() + "\n"; Cookie[] cookies = request.getCookies(); - if (cookies!=null && cookies.length>0) + if (cookies != null && cookies.length > 0) for (Cookie c : cookies) - content+="cookie "+c.getName()+"="+c.getValue()+"\n"; + { + content += "cookie " + c.getName() + "=" + c.getValue() + "\n"; + } response.setContentLength(content.length()); response.getOutputStream().print(content); diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/JarServer.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/JarServer.java index 6d47c0db457..9b32d6a16cc 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/JarServer.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/JarServer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -27,7 +27,8 @@ import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.util.resource.Resource; -/** +/** + * */ public class JarServer { @@ -40,9 +41,9 @@ public class JarServer Resource base = Resource.newResource("jar:file:src/main/resources/content.jar!/"); context.setBaseResource(base); context.addServlet(new ServletHolder(new DefaultServlet()), "/"); - + HandlerList handlers = new HandlerList(); - handlers.setHandlers(new Handler[] { context, new DefaultHandler() }); + handlers.setHandlers(new Handler[]{context, new DefaultHandler()}); server.setHandler(handlers); server.start(); diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/JettyDistribution.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/JettyDistribution.java new file mode 100644 index 00000000000..97118cfe32e --- /dev/null +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/JettyDistribution.java @@ -0,0 +1,109 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.embedded; + +import java.io.File; +import java.nio.file.Path; + +import org.eclipse.jetty.util.StringUtil; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + +/** + * A utility test class to locate a Jetty Distribution for testing purposes by searching: + *
    + *
  • The jetty.home system property
  • + *
  • The JETTY_HOME environment variable
  • + *
  • The working directory hierarchy with subdirectory jetty-distribution/target/home
  • + *
+ */ +public class JettyDistribution +{ + private static final Logger LOG = Log.getLogger(JettyDistribution.class); + public static final Path DISTRIBUTION; + + static + { + Path distro = asJettyDistribution(System.getProperty("jetty.home")); + if (distro == null) + distro = asJettyDistribution(System.getenv().get("JETTY_HOME")); + + if (distro == null) + { + try + { + Path working = new File(".").getAbsoluteFile().getCanonicalFile().toPath(); + while (distro == null && working != null) + { + distro = asJettyDistribution(working.resolve("jetty-distribution/target/distribution").toString()); + working = working.getParent(); + } + } + catch (Throwable cause) + { + LOG.warn(cause); + } + } + DISTRIBUTION = distro; + } + + private static Path asJettyDistribution(String test) + { + try + { + if (StringUtil.isBlank(test)) + { + LOG.info("asJettyDistribution {} is blank", test); + return null; + } + + File dir = new File(test); + if (!dir.exists() || !dir.isDirectory()) + { + LOG.info("asJettyDistribution {} is not a directory", test); + return null; + } + + File demoBase = new File(dir, "demo-base"); + if (!demoBase.exists() || !demoBase.isDirectory()) + { + LOG.info("asJettyDistribution {} has no demo-base", test); + return null; + } + + LOG.info("asJettyDistribution {}", dir); + return dir.getAbsoluteFile().getCanonicalFile().toPath(); + } + catch (Exception e) + { + LOG.ignore(e); + } + return null; + } + + public static Path resolve(String path) + { + return DISTRIBUTION.resolve(path); + } + + public static void main(String... arg) + { + System.err.println("Jetty Distribution is " + DISTRIBUTION); + } +} diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java index f592d061f30..54a9737464c 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,7 +19,6 @@ package org.eclipse.jetty.embedded; import java.io.File; -import java.io.FileNotFoundException; import java.lang.management.ManagementFactory; import org.eclipse.jetty.deploy.DeploymentManager; @@ -28,14 +27,17 @@ import org.eclipse.jetty.deploy.bindings.DebugListenerBinding; import org.eclipse.jetty.deploy.providers.WebAppProvider; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.jmx.MBeanContainer; +import org.eclipse.jetty.rewrite.handler.MsieSslRule; import org.eclipse.jetty.rewrite.handler.RewriteHandler; +import org.eclipse.jetty.rewrite.handler.ValidUrlRule; import org.eclipse.jetty.security.HashLoginService; +import org.eclipse.jetty.server.AsyncRequestLogWriter; +import org.eclipse.jetty.server.CustomRequestLog; import org.eclipse.jetty.server.DebugListener; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConnectionFactory; import org.eclipse.jetty.server.LowResourceMonitor; -import org.eclipse.jetty.server.NCSARequestLog; import org.eclipse.jetty.server.SecureRequestCustomizer; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnectionStatistics; @@ -44,7 +46,6 @@ import org.eclipse.jetty.server.SslConnectionFactory; import org.eclipse.jetty.server.handler.ContextHandlerCollection; import org.eclipse.jetty.server.handler.DefaultHandler; import org.eclipse.jetty.server.handler.HandlerCollection; -import org.eclipse.jetty.server.handler.RequestLogHandler; import org.eclipse.jetty.server.handler.StatisticsHandler; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.thread.QueuedThreadPool; @@ -57,37 +58,23 @@ import org.eclipse.jetty.webapp.Configuration; */ public class LikeJettyXml { - public static void main( String[] args ) throws Exception + public static void main(String[] args) throws Exception { // Path to as-built jetty-distribution directory - String jettyHomeBuild = "../../jetty-distribution/target/distribution"; - + String jettyHomeBuild = JettyDistribution.DISTRIBUTION.toString(); + // Find jetty home and base directories String homePath = System.getProperty("jetty.home", jettyHomeBuild); - File start_jar = new File(homePath,"start.jar"); - if (!start_jar.exists()) - { - homePath = jettyHomeBuild = "jetty-distribution/target/distribution"; - start_jar = new File(homePath,"start.jar"); - if (!start_jar.exists()) - throw new FileNotFoundException(start_jar.toString()); - } - File homeDir = new File(homePath); String basePath = System.getProperty("jetty.base", homeDir + "/demo-base"); File baseDir = new File(basePath); - if(!baseDir.exists()) - { - throw new FileNotFoundException(baseDir.getAbsolutePath()); - } - - // Configure jetty.home and jetty.base system properties - String jetty_home = homeDir.getAbsolutePath(); - String jetty_base = baseDir.getAbsolutePath(); - System.setProperty("jetty.home", jetty_home); - System.setProperty("jetty.base", jetty_base); + // Configure jetty.home and jetty.base system properties + String jettyHome = homeDir.getAbsolutePath(); + String jettyBase = baseDir.getAbsolutePath(); + System.setProperty("jetty.home", jettyHome); + System.setProperty("jetty.base", jettyBase); // === jetty.xml === // Setup Threadpool @@ -98,101 +85,98 @@ public class LikeJettyXml Server server = new Server(threadPool); // Scheduler - server.addBean(new ScheduledExecutorScheduler()); + server.addBean(new ScheduledExecutorScheduler(null, false)); // HTTP Configuration - HttpConfiguration http_config = new HttpConfiguration(); - http_config.setSecureScheme("https"); - http_config.setSecurePort(8443); - http_config.setOutputBufferSize(32768); - http_config.setRequestHeaderSize(8192); - http_config.setResponseHeaderSize(8192); - http_config.setSendServerVersion(true); - http_config.setSendDateHeader(false); + HttpConfiguration httpConfig = new HttpConfiguration(); + httpConfig.setSecureScheme("https"); + httpConfig.setSecurePort(8443); + httpConfig.setOutputBufferSize(32768); + httpConfig.setRequestHeaderSize(8192); + httpConfig.setResponseHeaderSize(8192); + httpConfig.setSendServerVersion(true); + httpConfig.setSendDateHeader(false); // httpConfig.addCustomizer(new ForwardedRequestCustomizer()); // Handler Structure HandlerCollection handlers = new HandlerCollection(); ContextHandlerCollection contexts = new ContextHandlerCollection(); - handlers.setHandlers(new Handler[] { contexts, new DefaultHandler() }); + handlers.setHandlers(new Handler[]{contexts, new DefaultHandler()}); server.setHandler(handlers); // Extra options - server.setDumpAfterStart(false); + server.setDumpAfterStart(true); server.setDumpBeforeStop(false); server.setStopAtShutdown(true); // === jetty-jmx.xml === MBeanContainer mbContainer = new MBeanContainer( - ManagementFactory.getPlatformMBeanServer()); + ManagementFactory.getPlatformMBeanServer()); server.addBean(mbContainer); - // === jetty-http.xml === ServerConnector http = new ServerConnector(server, - new HttpConnectionFactory(http_config)); + new HttpConnectionFactory(httpConfig)); http.setPort(8080); http.setIdleTimeout(30000); server.addConnector(http); - // === jetty-https.xml === // SSL Context Factory - SslContextFactory sslContextFactory = new SslContextFactory(); - sslContextFactory.setKeyStorePath(jetty_home + "/../../../jetty-server/src/test/config/etc/keystore"); + SslContextFactory sslContextFactory = new SslContextFactory.Server(); + sslContextFactory.setKeyStorePath(jettyHome + "/../../../jetty-server/src/test/config/etc/keystore"); sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"); sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g"); - sslContextFactory.setTrustStorePath(jetty_home + "/../../../jetty-server/src/test/config/etc/keystore"); + sslContextFactory.setTrustStorePath(jettyHome + "/../../../jetty-server/src/test/config/etc/keystore"); sslContextFactory.setTrustStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"); sslContextFactory.setExcludeCipherSuites("SSL_RSA_WITH_DES_CBC_SHA", - "SSL_DHE_RSA_WITH_DES_CBC_SHA", "SSL_DHE_DSS_WITH_DES_CBC_SHA", - "SSL_RSA_EXPORT_WITH_RC4_40_MD5", - "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", - "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", - "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"); + "SSL_DHE_RSA_WITH_DES_CBC_SHA", "SSL_DHE_DSS_WITH_DES_CBC_SHA", + "SSL_RSA_EXPORT_WITH_RC4_40_MD5", + "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", + "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", + "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"); // SSL HTTP Configuration - HttpConfiguration https_config = new HttpConfiguration(http_config); - https_config.addCustomizer(new SecureRequestCustomizer()); + HttpConfiguration httpsConfig = new HttpConfiguration(httpConfig); + httpsConfig.addCustomizer(new SecureRequestCustomizer()); // SSL Connector ServerConnector sslConnector = new ServerConnector(server, - new SslConnectionFactory(sslContextFactory,HttpVersion.HTTP_1_1.asString()), - new HttpConnectionFactory(https_config)); + new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()), + new HttpConnectionFactory(httpsConfig)); sslConnector.setPort(8443); server.addConnector(sslConnector); - // === jetty-deploy.xml === DeploymentManager deployer = new DeploymentManager(); - DebugListener debug = new DebugListener(System.err,true,true,true); - server.addBean(debug); + DebugListener debug = new DebugListener(System.err, true, true, true); + server.addBean(debug); deployer.addLifeCycleBinding(new DebugListenerBinding(debug)); deployer.setContexts(contexts); deployer.setContextAttribute( - "org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern", - ".*/[^/]*servlet-api-[^/]*\\.jar$|.*/javax.servlet.jsp.jstl-.*\\.jar$|.*/[^/]*taglibs.*\\.jar$"); + "org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern", + ".*/[^/]*servlet-api-[^/]*\\.jar$|.*/javax.servlet.jsp.jstl-.*\\.jar$|.*/[^/]*taglibs.*\\.jar$"); - WebAppProvider webapp_provider = new WebAppProvider(); - webapp_provider.setMonitoredDirName(jetty_base + "/webapps"); - webapp_provider.setDefaultsDescriptor(jetty_home + "/etc/webdefault.xml"); - webapp_provider.setScanInterval(1); - webapp_provider.setExtractWars(true); - webapp_provider.setConfigurationManager(new PropertiesConfigurationManager()); + WebAppProvider webAppProvider = new WebAppProvider(); + webAppProvider.setMonitoredDirName(jettyBase + "/webapps"); + webAppProvider.setDefaultsDescriptor(jettyHome + "/etc/webdefault.xml"); + webAppProvider.setScanInterval(1); + webAppProvider.setExtractWars(true); + webAppProvider.setConfigurationManager(new PropertiesConfigurationManager()); - deployer.addAppProvider(webapp_provider); + deployer.addAppProvider(webAppProvider); server.addBean(deployer); - + // === setup jetty plus == Configuration.ClassList classlist = Configuration.ClassList - .setServerDefault( server ); + .setServerDefault(server); classlist.addAfter( - "org.eclipse.jetty.webapp.FragmentConfiguration", - "org.eclipse.jetty.plus.webapp.EnvConfiguration", - "org.eclipse.jetty.plus.webapp.PlusConfiguration"); - + "org.eclipse.jetty.webapp.FragmentConfiguration", + "org.eclipse.jetty.plus.webapp.EnvConfiguration", + "org.eclipse.jetty.plus.webapp.PlusConfiguration"); + classlist.addBefore("org.eclipse.jetty.webapp.JettyWebXmlConfiguration", - "org.eclipse.jetty.annotations.AnnotationConfiguration"); + "org.eclipse.jetty.annotations.AnnotationConfiguration"); // === jetty-stats.xml === StatisticsHandler stats = new StatisticsHandler(); @@ -204,39 +188,33 @@ public class LikeJettyXml RewriteHandler rewrite = new RewriteHandler(); rewrite.setHandler(server.getHandler()); server.setHandler(rewrite); + rewrite.addRule(new MsieSslRule()); + rewrite.addRule(new ValidUrlRule()); // === jetty-requestlog.xml === - NCSARequestLog requestLog = new NCSARequestLog(); - requestLog.setFilename(jetty_home + "/logs/yyyy_mm_dd.request.log"); - requestLog.setFilenameDateFormat("yyyy_MM_dd"); - requestLog.setRetainDays(90); - requestLog.setAppend(true); - requestLog.setExtended(true); - requestLog.setLogCookies(false); - requestLog.setLogTimeZone("GMT"); - RequestLogHandler requestLogHandler = new RequestLogHandler(); - requestLogHandler.setRequestLog(requestLog); - handlers.addHandler(requestLogHandler); - + AsyncRequestLogWriter logWriter = new AsyncRequestLogWriter(jettyHome + "/logs/yyyy_mm_dd.request.log"); + CustomRequestLog requestLog = new CustomRequestLog(logWriter, CustomRequestLog.EXTENDED_NCSA_FORMAT + " \"%C\""); + logWriter.setFilenameDateFormat("yyyy_MM_dd"); + logWriter.setRetainDays(90); + logWriter.setTimeZone("GMT"); + server.setRequestLog(requestLog); // === jetty-lowresources.xml === - LowResourceMonitor lowResourcesMonitor=new LowResourceMonitor(server); + LowResourceMonitor lowResourcesMonitor = new LowResourceMonitor(server); lowResourcesMonitor.setPeriod(1000); lowResourcesMonitor.setLowResourcesIdleTimeout(200); lowResourcesMonitor.setMonitorThreads(true); - lowResourcesMonitor.setMaxConnections(0); lowResourcesMonitor.setMaxMemory(0); lowResourcesMonitor.setMaxLowResourcesTime(5000); server.addBean(lowResourcesMonitor); - // === test-realm.xml === HashLoginService login = new HashLoginService(); login.setName("Test Realm"); - login.setConfig(jetty_base + "/etc/realm.properties"); + login.setConfig(jettyBase + "/etc/realm.properties"); login.setHotReload(false); server.addBean(login); - + // Start the server server.start(); server.join(); diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyConnectors.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyConnectors.java index ef62bcbc2df..13b41236678 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyConnectors.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyConnectors.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,9 +20,7 @@ package org.eclipse.jetty.embedded; import java.io.File; import java.io.FileNotFoundException; -import java.security.Security; -import org.conscrypt.OpenSSLProvider; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.HttpConfiguration; @@ -38,8 +36,8 @@ import org.eclipse.jetty.util.ssl.SslContextFactory; */ public class ManyConnectors { - public static void main( String[] args ) throws Exception - { + public static void main(String[] args) throws Exception + { // Since this example shows off SSL configuration, we need a keystore // with the appropriate key. These lookup of jetty.home is purely a hack // to get access to a keystore that we use in many unit tests and should @@ -67,10 +65,10 @@ public class ManyConnectors // http of course, as the default for secured http is // https but we show setting the scheme to show it can be // done. The port for secured communication is also set here. - HttpConfiguration http_config = new HttpConfiguration(); - http_config.setSecureScheme("https"); - http_config.setSecurePort(8443); - http_config.setOutputBufferSize(32768); + HttpConfiguration httpConfig = new HttpConfiguration(); + httpConfig.setSecureScheme("https"); + httpConfig.setSecurePort(8443); + httpConfig.setOutputBufferSize(32768); // HTTP connector // The first server connector we create is the one for http, passing in @@ -78,7 +76,7 @@ public class ManyConnectors // the output buffer size, etc. We also set the port (8080) and // configure an idle timeout. ServerConnector http = new ServerConnector(server, - new HttpConnectionFactory(http_config)); + new HttpConnectionFactory(httpConfig)); http.setPort(8080); http.setIdleTimeout(30000); @@ -88,8 +86,8 @@ public class ManyConnectors // to know about. Much more configuration is available the ssl context, // including things like choosing the particular certificate out of a // keystore to be used. - - SslContextFactory sslContextFactory = new SslContextFactory(); + + SslContextFactory sslContextFactory = new SslContextFactory.Server(); sslContextFactory.setKeyStorePath(keystoreFile.getAbsolutePath()); sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"); sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g"); @@ -107,19 +105,19 @@ public class ManyConnectors // SecureRequestCustomizer which is how a new connector is able to // resolve the https connection before handing control over to the Jetty // Server. - HttpConfiguration https_config = new HttpConfiguration(http_config); + HttpConfiguration httpsConfig = new HttpConfiguration(httpConfig); SecureRequestCustomizer src = new SecureRequestCustomizer(); src.setStsMaxAge(2000); src.setStsIncludeSubDomains(true); - https_config.addCustomizer(src); + httpsConfig.addCustomizer(src); // HTTPS connector // We create a second ServerConnector, passing in the http configuration // we just made along with the previously created ssl context factory. // Next we set the port and a longer idle timeout. ServerConnector https = new ServerConnector(server, - new SslConnectionFactory(sslContextFactory,HttpVersion.HTTP_1_1.asString()), - new HttpConnectionFactory(https_config)); + new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()), + new HttpConnectionFactory(httpsConfig)); https.setPort(8443); https.setIdleTimeout(500000); @@ -130,14 +128,14 @@ public class ManyConnectors // has something to pass requests off to. // Set the connectors - server.setConnectors(new Connector[] { http, https }); + server.setConnectors(new Connector[]{http, https}); // Set a handler server.setHandler(new HelloHandler()); // Start the server server.start(); - + server.dumpStdErr(); server.join(); } } diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyContexts.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyContexts.java index 87c39c0727b..dc1f10985f5 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyContexts.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyContexts.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -25,7 +25,7 @@ import org.eclipse.jetty.server.handler.ContextHandlerCollection; public class ManyContexts { - public static void main( String[] args ) throws Exception + public static void main(String[] args) throws Exception { Server server = new Server(8080); @@ -40,16 +40,19 @@ public class ManyContexts contextIT.setHandler(new HelloHandler("Bongiorno")); ContextHandler contextV = new ContextHandler("/"); - contextV.setVirtualHosts(new String[] { "127.0.0.2" }); + contextV.setVirtualHosts(new String[]{"127.0.0.2"}); contextV.setHandler(new HelloHandler("Virtual Hello")); ContextHandlerCollection contexts = new ContextHandlerCollection(); - contexts.setHandlers(new Handler[] { context, contextFR, contextIT, - contextV }); + contexts.setHandlers(new Handler[]{ + context, contextFR, contextIT, + contextV + }); server.setHandler(contexts); server.start(); + server.dumpStdErr(); server.join(); } } diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyHandlers.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyHandlers.java index 337f760af86..49bc494302f 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyHandlers.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyHandlers.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -21,13 +21,12 @@ package org.eclipse.jetty.embedded; import java.io.File; import java.io.IOException; import java.util.Map; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.server.CustomRequestLog; import org.eclipse.jetty.server.Handler; -import org.eclipse.jetty.server.NCSARequestLog; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.AbstractHandler; @@ -35,7 +34,6 @@ import org.eclipse.jetty.server.handler.DefaultHandler; import org.eclipse.jetty.server.handler.HandlerCollection; import org.eclipse.jetty.server.handler.HandlerList; import org.eclipse.jetty.server.handler.HandlerWrapper; -import org.eclipse.jetty.server.handler.RequestLogHandler; import org.eclipse.jetty.server.handler.gzip.GzipHandler; import org.eclipse.jetty.util.ajax.JSON; @@ -73,14 +71,14 @@ public class ManyHandlers public static class ParamHandler extends AbstractHandler { @Override - public void handle( String target, - Request baseRequest, - HttpServletRequest request, - HttpServletResponse response ) throws IOException, - ServletException + public void handle(String target, + Request baseRequest, + HttpServletRequest request, + HttpServletResponse response) throws IOException, + ServletException { Map params = request.getParameterMap(); - if (params.size() > 0) + if (!params.isEmpty()) { response.setContentType("text/plain"); response.getWriter().println(JSON.toString(params)); @@ -95,18 +93,18 @@ public class ManyHandlers public static class WelcomeWrapHandler extends HandlerWrapper { @Override - public void handle( String target, - Request baseRequest, - HttpServletRequest request, - HttpServletResponse response ) throws IOException, - ServletException + public void handle(String target, + Request baseRequest, + HttpServletRequest request, + HttpServletResponse response) throws IOException, + ServletException { request.setAttribute("welcome", "Hello"); super.handle(target, baseRequest, request, response); } } - public static void main( String[] args ) throws Exception + public static void main(String[] args) throws Exception { Server server = new Server(8080); @@ -115,13 +113,11 @@ public class ManyHandlers HandlerWrapper wrapper = new WelcomeWrapHandler(); Handler hello = new HelloHandler(); Handler dft = new DefaultHandler(); - RequestLogHandler requestLog = new RequestLogHandler(); // configure request logging File requestLogFile = File.createTempFile("demo", "log"); - NCSARequestLog ncsaLog = new NCSARequestLog( - requestLogFile.getAbsolutePath()); - requestLog.setRequestLog(ncsaLog); + CustomRequestLog ncsaLog = new CustomRequestLog(requestLogFile.getAbsolutePath()); + server.setRequestLog(ncsaLog); // create the handler collections HandlerCollection handlers = new HandlerCollection(); @@ -129,20 +125,8 @@ public class ManyHandlers // link them all together wrapper.setHandler(hello); - list.setHandlers(new Handler[] { param, new GzipHandler(), dft }); - handlers.setHandlers(new Handler[] { list, requestLog }); - - // Handler tree looks like the following - //
-        // Server
-        // + HandlerCollection
-        // . + HandlerList
-        // . | + param (ParamHandler)
-        // . | + wrapper (WelcomeWrapHandler)
-        // . | | \ hello (HelloHandler)
-        // . | \ dft (DefaultHandler)
-        // . \ requestLog (RequestLogHandler)
-        // 
+ list.setHandlers(new Handler[]{param, new GzipHandler()}); + handlers.setHandlers(new Handler[]{list, dft}); server.setHandler(handlers); diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyServletContexts.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyServletContexts.java index 52ca4a4d514..53fa7317c04 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyServletContexts.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyServletContexts.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -29,13 +29,13 @@ import org.eclipse.jetty.servlet.ServletHolder; public class ManyServletContexts { - public static void main( String[] args ) throws Exception + public static void main(String[] args) throws Exception { Server server = new Server(8080); // Setup JMX MBeanContainer mbContainer = new MBeanContainer( - ManagementFactory.getPlatformMBeanServer()); + ManagementFactory.getPlatformMBeanServer()); server.addBean(mbContainer, true); // Declare server handler collection @@ -44,7 +44,7 @@ public class ManyServletContexts // Configure context "/" (root) for servlets ServletContextHandler root = new ServletContextHandler(contexts, "/", - ServletContextHandler.SESSIONS); + ServletContextHandler.SESSIONS); // Add servlets to root context root.addServlet(new ServletHolder(new HelloServlet("Hello")), "/"); root.addServlet(new ServletHolder(new HelloServlet("Ciao")), "/it/*"); @@ -52,7 +52,7 @@ public class ManyServletContexts // Configure context "/other" for servlets ServletContextHandler other = new ServletContextHandler(contexts, - "/other", ServletContextHandler.SESSIONS); + "/other", ServletContextHandler.SESSIONS); // Add servlets to /other context other.addServlet(DefaultServlet.class.getCanonicalName(), "/"); other.addServlet(new ServletHolder(new HelloServlet("YO!")), "*.yo"); diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/MinimalServlets.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/MinimalServlets.java index c785512f7b1..5ce9a24016c 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/MinimalServlets.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/MinimalServlets.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,7 +19,6 @@ package org.eclipse.jetty.embedded; import java.io.IOException; - import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -30,7 +29,7 @@ import org.eclipse.jetty.servlet.ServletHandler; public class MinimalServlets { - public static void main( String[] args ) throws Exception + public static void main(String[] args) throws Exception { // Create a basic jetty server object that will listen on port 8080. // Note that if you set this to port 0 then a randomly available port @@ -66,9 +65,9 @@ public class MinimalServlets public static class HelloServlet extends HttpServlet { @Override - protected void doGet( HttpServletRequest request, - HttpServletResponse response ) throws ServletException, - IOException + protected void doGet(HttpServletRequest request, + HttpServletResponse response) throws ServletException, + IOException { response.setContentType("text/html"); response.setStatus(HttpServletResponse.SC_OK); diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneConnector.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneConnector.java index ca3ce6bce24..c6debe8a23b 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneConnector.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneConnector.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -26,7 +26,7 @@ import org.eclipse.jetty.server.ServerConnector; */ public class OneConnector { - public static void main( String[] args ) throws Exception + public static void main(String[] args) throws Exception { // The Server Server server = new Server(); diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneContext.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneContext.java index e425f76de51..1331e6abb55 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneContext.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneContext.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -23,18 +23,18 @@ import org.eclipse.jetty.server.handler.ContextHandler; public class OneContext { - public static void main( String[] args ) throws Exception + public static void main(String[] args) throws Exception { - Server server = new Server( 8080 ); + Server server = new Server(8080); // Add a single handler on context "/hello" ContextHandler context = new ContextHandler(); - context.setContextPath( "/hello" ); - context.setHandler( new HelloHandler() ); + context.setContextPath("/hello"); + context.setHandler(new HelloHandler()); // Can be accessed using http://localhost:8080/hello - server.setHandler( context ); + server.setHandler(context); // Start the server server.start(); diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneHandler.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneHandler.java index ff6a14a5ea9..b9a2f942f75 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneHandler.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -22,7 +22,7 @@ import org.eclipse.jetty.server.Server; public class OneHandler { - public static void main( String[] args ) throws Exception + public static void main(String[] args) throws Exception { Server server = new Server(8080); server.setHandler(new HelloHandler()); diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneServletContext.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneServletContext.java index a09dab91db1..720309dd917 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneServletContext.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneServletContext.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,28 +18,102 @@ package org.eclipse.jetty.embedded; +import java.io.IOException; +import java.util.EnumSet; +import javax.servlet.DispatcherType; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletRequestEvent; +import javax.servlet.ServletRequestListener; +import javax.servlet.ServletResponse; + import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.DefaultServlet; +import org.eclipse.jetty.servlet.ListenerHolder; import org.eclipse.jetty.servlet.ServletContextHandler; public class OneServletContext { - public static void main( String[] args ) throws Exception + public static void main(String[] args) throws Exception { Server server = new Server(8080); ServletContextHandler context = new ServletContextHandler( - ServletContextHandler.SESSIONS); + ServletContextHandler.SESSIONS); context.setContextPath("/"); context.setResourceBase(System.getProperty("java.io.tmpdir")); server.setHandler(context); // Add dump servlet - context.addServlet(DumpServlet.class, "/dump/*"); - // Add default servlet + context.addServlet( + context.addServlet(DumpServlet.class, "/dump/*"), + "*.dump"); + context.addServlet(HelloServlet.class, "/hello/*"); context.addServlet(DefaultServlet.class, "/"); + context.addFilter(TestFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST)); + context.addFilter(TestFilter.class, "/test", EnumSet.of(DispatcherType.REQUEST, DispatcherType.ASYNC)); + context.addFilter(TestFilter.class, "*.test", EnumSet.of(DispatcherType.REQUEST, DispatcherType.INCLUDE, DispatcherType.FORWARD)); + + context.getServletHandler().addListener(new ListenerHolder(InitListener.class)); + context.getServletHandler().addListener(new ListenerHolder(RequestListener.class)); + server.start(); + server.dumpStdErr(); server.join(); } + + public static class TestFilter implements Filter + { + @Override + public void init(FilterConfig filterConfig) throws ServletException + { + + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException + { + chain.doFilter(request, response); + } + + @Override + public void destroy() + { + + } + } + + public static class InitListener implements ServletContextListener + { + @Override + public void contextInitialized(ServletContextEvent sce) + { + } + + @Override + public void contextDestroyed(ServletContextEvent sce) + { + } + } + + public static class RequestListener implements ServletRequestListener + { + @Override + public void requestDestroyed(ServletRequestEvent sre) + { + + } + + @Override + public void requestInitialized(ServletRequestEvent sre) + { + + } + } } diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneServletContextJmxStats.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneServletContextJmxStats.java index e80e86a8c15..557c4588b65 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneServletContextJmxStats.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneServletContextJmxStats.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -28,15 +28,15 @@ import org.eclipse.jetty.servlet.ServletContextHandler; public class OneServletContextJmxStats { - public static void main( String[] args ) throws Exception + public static void main(String[] args) throws Exception { Server server = new Server(8080); // Add JMX tracking to Server server.addBean(new MBeanContainer(ManagementFactory - .getPlatformMBeanServer())); + .getPlatformMBeanServer())); ServletContextHandler context = new ServletContextHandler( - ServletContextHandler.SESSIONS); + ServletContextHandler.SESSIONS); context.setContextPath("/"); server.setHandler(context); diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneServletContextWithSession.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneServletContextWithSession.java index d098589d0bc..35d18c2d848 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneServletContextWithSession.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneServletContextWithSession.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -25,7 +25,6 @@ import org.eclipse.jetty.server.session.SessionCache; import org.eclipse.jetty.server.session.SessionHandler; import org.eclipse.jetty.servlet.ServletContextHandler; - public class OneServletContextWithSession { public static void main(String[] args) throws Exception @@ -34,14 +33,14 @@ public class OneServletContextWithSession // Create a ServletContext, with a session handler enabled. ServletContextHandler context = new ServletContextHandler( - ServletContextHandler.SESSIONS); + ServletContextHandler.SESSIONS); context.setContextPath("/"); context.setResourceBase(System.getProperty("java.io.tmpdir")); server.setHandler(context); // Access the SessionHandler from the context. SessionHandler sessions = context.getSessionHandler(); - + // Explicitly set Session Cache and null Datastore. // This is normally done by default, // but is done explicitly here for demonstration. @@ -58,6 +57,7 @@ public class OneServletContextWithSession context.addServlet(HelloSessionServlet.class, "/"); server.start(); + server.dumpStdErr(); server.join(); } } diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneWebApp.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneWebApp.java index 36177dbf336..720bdaa3494 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneWebApp.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneWebApp.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -23,12 +23,11 @@ import java.lang.management.ManagementFactory; import org.eclipse.jetty.jmx.MBeanContainer; import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.handler.AllowSymLinkAliasChecker; import org.eclipse.jetty.webapp.WebAppContext; public class OneWebApp { - public static void main( String[] args ) throws Exception + public static void main(String[] args) throws Exception { // Create a basic jetty server object that will listen on port 8080. // Note that if you set this to port 0 then a randomly available port @@ -38,7 +37,7 @@ public class OneWebApp // Setup JMX MBeanContainer mbContainer = new MBeanContainer( - ManagementFactory.getPlatformMBeanServer()); + ManagementFactory.getPlatformMBeanServer()); server.addBean(mbContainer); // The WebAppContext is the entity that controls the environment in @@ -50,19 +49,18 @@ public class OneWebApp // PlusConfiguration) to choosing where the webapp will unpack itself. WebAppContext webapp = new WebAppContext(); webapp.setContextPath("/"); - File warFile = new File( - "../../tests/test-jmx/jmx-webapp/target/jmx-webapp"); + File warFile = JettyDistribution.resolve("demo-base/webapps/async-rest.war").toFile(); webapp.setWar(warFile.getAbsolutePath()); // A WebAppContext is a ContextHandler as well so it needs to be set to // the server so it is aware of where to send the appropriate requests. server.setHandler(webapp); - // Start things up! + // Start things up! server.start(); server.dumpStdErr(); - + // The use of server.join() the will make the current thread join and // wait until the server is done executing. // See http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#join() diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneWebAppWithJsp.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneWebAppWithJsp.java index 99054e58b39..bb9348e62ca 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneWebAppWithJsp.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneWebAppWithJsp.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -29,19 +29,19 @@ import org.eclipse.jetty.webapp.WebAppContext; public class OneWebAppWithJsp { - public static void main( String[] args ) throws Exception + public static void main(String[] args) throws Exception { // Create a basic jetty server object that will listen on port 8080. // Note that if you set this to port 0 then // a randomly available port will be assigned that you can either look // in the logs for the port, // or programmatically obtain it for use in test cases. - Server server = new Server( 8080 ); + Server server = new Server(8080); // Setup JMX MBeanContainer mbContainer = new MBeanContainer( - ManagementFactory.getPlatformMBeanServer() ); - server.addBean( mbContainer ); + ManagementFactory.getPlatformMBeanServer()); + server.addBean(mbContainer); // The WebAppContext is the entity that controls the environment in // which a web application lives and @@ -53,38 +53,37 @@ public class OneWebAppWithJsp // the webapp (through // PlusConfiguration) to choosing where the webapp will unpack itself. WebAppContext webapp = new WebAppContext(); - webapp.setContextPath( "/" ); + webapp.setContextPath("/"); File warFile = new File( - "../../jetty-distribution/target/distribution/demo-base/webapps/test.war" ); + "jetty-distribution/target/distribution/demo-base/webapps/test.war"); if (!warFile.exists()) { - throw new RuntimeException( "Unable to find WAR File: " - + warFile.getAbsolutePath() ); + throw new RuntimeException("Unable to find WAR File: " + warFile.getAbsolutePath()); } - webapp.setWar( warFile.getAbsolutePath() ); + webapp.setWar(warFile.getAbsolutePath()); webapp.setExtractWAR(true); // This webapp will use jsps and jstl. We need to enable the // AnnotationConfiguration in order to correctly // set up the jsp container Configuration.ClassList classlist = Configuration.ClassList - .setServerDefault( server ); + .setServerDefault(server); classlist.addBefore( - "org.eclipse.jetty.webapp.JettyWebXmlConfiguration", - "org.eclipse.jetty.annotations.AnnotationConfiguration" ); + "org.eclipse.jetty.webapp.JettyWebXmlConfiguration", + "org.eclipse.jetty.annotations.AnnotationConfiguration"); // Set the ContainerIncludeJarPattern so that jetty examines these // container-path jars for tlds, web-fragments etc. // If you omit the jar that contains the jstl .tlds, the jsp engine will // scan for them instead. webapp.setAttribute( - "org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern", - ".*/[^/]*servlet-api-[^/]*\\.jar$|.*/javax.servlet.jsp.jstl-.*\\.jar$|.*/[^/]*taglibs.*\\.jar$" ); + "org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern", + ".*/[^/]*servlet-api-[^/]*\\.jar$|.*/javax.servlet.jsp.jstl-.*\\.jar$|.*/[^/]*taglibs.*\\.jar$"); // A WebAppContext is a ContextHandler as well so it needs to be set to // the server so it is aware of where to // send the appropriate requests. - server.setHandler( webapp ); + server.setHandler(webapp); // Configure a LoginService. // Since this example is for our test webapp, we need to setup a @@ -95,13 +94,13 @@ public class OneWebAppWithJsp // can be started and stopped according to the lifecycle of the server // itself. HashLoginService loginService = new HashLoginService(); - loginService.setName( "Test Realm" ); - loginService.setConfig( "src/test/resources/realm.properties" ); - server.addBean( loginService ); + loginService.setName("Test Realm"); + loginService.setConfig("examples/embedded/src/test/resources/realm.properties"); + server.addBean(loginService); // Start things up! server.start(); - + server.dumpStdErr(); // The use of server.join() the will make the current thread join and diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ProxyServer.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ProxyServer.java index 45647f39364..ff3412f6cb3 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ProxyServer.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ProxyServer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -27,7 +27,7 @@ import org.eclipse.jetty.servlet.ServletHolder; public class ProxyServer { - public static void main( String[] args ) throws Exception + public static void main(String[] args) throws Exception { Server server = new Server(); ServerConnector connector = new ServerConnector(server); @@ -40,12 +40,11 @@ public class ProxyServer // Setup proxy servlet ServletContextHandler context = new ServletContextHandler(proxy, "/", - ServletContextHandler.SESSIONS); + ServletContextHandler.SESSIONS); ServletHolder proxyServlet = new ServletHolder(ProxyServlet.class); proxyServlet.setInitParameter("blackList", "www.eclipse.org"); context.addServlet(proxyServlet, "/*"); server.start(); } - } diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/RewriteServer.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/RewriteServer.java index e9aa8f627ad..a74427f0ffd 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/RewriteServer.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/RewriteServer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -28,19 +28,19 @@ import org.eclipse.jetty.servlet.ServletContextHandler; public class RewriteServer { - public static void main( String[] args ) throws Exception + public static void main(String[] args) throws Exception { Server server = new Server(8080); - - HttpConfiguration config=server.getConnectors()[0].getConnectionFactory(HttpConnectionFactory.class).getHttpConfiguration(); + + HttpConfiguration config = server.getConnectors()[0].getConnectionFactory(HttpConnectionFactory.class).getHttpConfiguration(); RewriteCustomizer rewrite = new RewriteCustomizer(); config.addCustomizer(rewrite); rewrite.addRule(new CompactPathRule()); - rewrite.addRule(new RewriteRegexRule("(.*)foo(.*)","$1FOO$2")); - + rewrite.addRule(new RewriteRegexRule("(.*)foo(.*)", "$1FOO$2")); + ServletContextHandler context = new ServletContextHandler( - ServletContextHandler.SESSIONS); + ServletContextHandler.SESSIONS); context.setContextPath("/"); server.setHandler(context); diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SecuredHelloHandler.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SecuredHelloHandler.java index fb68c42a040..aaa0c806a5e 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SecuredHelloHandler.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SecuredHelloHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -30,7 +30,7 @@ import org.eclipse.jetty.util.security.Constraint; public class SecuredHelloHandler { - public static void main( String[] args ) throws Exception + public static void main(String[] args) throws Exception { // Create a basic jetty server object that will listen on port 8080. // Note that if you set this to port 0 then a randomly available port @@ -47,7 +47,7 @@ public class SecuredHelloHandler // In this example the name can be whatever you like since we are not // dealing with webapp realms. LoginService loginService = new HashLoginService("MyRealm", - "src/test/resources/realm.properties"); + "src/test/resources/realm.properties"); server.addBean(loginService); // A security handler is a jetty handler that secures content behind a @@ -65,7 +65,7 @@ public class SecuredHelloHandler Constraint constraint = new Constraint(); constraint.setName("auth"); constraint.setAuthenticate(true); - constraint.setRoles(new String[] { "user", "admin" }); + constraint.setRoles(new String[]{"user", "admin"}); // Binds a url pattern with the previously created constraint. The roles // for this constraing mapping are mined from the Constraint itself diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ServerWithAnnotations.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ServerWithAnnotations.java index d67880eef52..42dda96c7a0 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ServerWithAnnotations.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ServerWithAnnotations.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -21,6 +21,7 @@ package org.eclipse.jetty.embedded; import java.io.File; import org.eclipse.jetty.plus.jndi.EnvEntry; +import org.eclipse.jetty.plus.jndi.NamingDump; import org.eclipse.jetty.plus.jndi.Resource; import org.eclipse.jetty.plus.jndi.Transaction; import org.eclipse.jetty.security.HashLoginService; @@ -33,30 +34,28 @@ import org.eclipse.jetty.webapp.WebAppContext; */ public class ServerWithAnnotations { - public static final void main( String args[] ) throws Exception + public static final void main(String[] args) throws Exception { // Create the server Server server = new Server(8080); // Enable parsing of jndi-related parts of web.xml and jetty-env.xml Configuration.ClassList classlist = Configuration.ClassList - .setServerDefault(server); + .setServerDefault(server); classlist.addAfter("org.eclipse.jetty.webapp.FragmentConfiguration", - "org.eclipse.jetty.plus.webapp.EnvConfiguration", - "org.eclipse.jetty.plus.webapp.PlusConfiguration"); + "org.eclipse.jetty.plus.webapp.EnvConfiguration", + "org.eclipse.jetty.plus.webapp.PlusConfiguration"); classlist.addBefore( - "org.eclipse.jetty.webapp.JettyWebXmlConfiguration", - "org.eclipse.jetty.annotations.AnnotationConfiguration"); - + "org.eclipse.jetty.webapp.JettyWebXmlConfiguration", + "org.eclipse.jetty.annotations.AnnotationConfiguration"); // Create a WebApp WebAppContext webapp = new WebAppContext(); webapp.setContextPath("/"); - File warFile = new File( - "../../jetty-distribution/target/distribution/demo-base/webapps/test.war"); + File warFile = JettyDistribution.resolve("demo-base/webapps/test-spec.war").toFile(); webapp.setWar(warFile.getAbsolutePath()); webapp.setAttribute( - "org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern", - ".*/javax.servlet-[^/]*\\.jar$|.*/servlet-api-[^/]*\\.jar$"); + "org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern", + ".*/javax.servlet-[^/]*\\.jar$|.*/servlet-api-[^/]*\\.jar$"); server.setHandler(webapp); // Register new transaction manager in JNDI @@ -64,19 +63,23 @@ public class ServerWithAnnotations new Transaction(new com.acme.MockUserTransaction()); // Define an env entry with webapp scope. - new EnvEntry(webapp, "maxAmount", new Double(100), true); + // THIS ENTRY IS OVERRIDEN BY THE ENTRY IN jetty-env.xml + new EnvEntry(webapp, "maxAmount", 100d, true); // Register a mock DataSource scoped to the webapp - new Resource(webapp, "jdbc/mydatasource", new com.acme.MockDataSource()); + new Resource(server, "jdbc/mydatasource", new com.acme.MockDataSource()); + + // Add JNDI context to server for dump + server.addBean(new NamingDump()); // Configure a LoginService HashLoginService loginService = new HashLoginService(); loginService.setName("Test Realm"); - loginService.setConfig("src/test/resources/realm.properties"); + loginService.setConfig("examples/embedded/src/test/resources/realm.properties"); server.addBean(loginService); server.start(); + server.dumpStdErr(); server.join(); } - } diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ServerWithJMX.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ServerWithJMX.java index 7c73c73b116..95b38e56a18 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ServerWithJMX.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ServerWithJMX.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,7 +19,6 @@ package org.eclipse.jetty.embedded; import java.lang.management.ManagementFactory; - import javax.management.remote.JMXServiceURL; import org.eclipse.jetty.jmx.ConnectorServer; @@ -31,24 +30,24 @@ import org.eclipse.jetty.server.Server; */ public class ServerWithJMX { - public static void main( String[] args ) throws Exception + public static void main(String[] args) throws Exception { // === jetty-jmx.xml === MBeanContainer mbContainer = new MBeanContainer( - ManagementFactory.getPlatformMBeanServer()); - + ManagementFactory.getPlatformMBeanServer()); + Server server = new Server(8080); server.addBean(mbContainer); - + ConnectorServer jmx = new ConnectorServer( - new JMXServiceURL( - "rmi", - null, - 1999, - "/jndi/rmi://localhost:1999/jmxrmi"), - "org.eclipse.jetty.jmx:name=rmiconnectorserver"); + new JMXServiceURL( + "rmi", + null, + 1999, + "/jndi/rmi://localhost:1999/jmxrmi"), + "org.eclipse.jetty.jmx:name=rmiconnectorserver"); server.addBean(jmx); - + server.start(); server.dumpStdErr(); server.join(); diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ServerWithJNDI.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ServerWithJNDI.java index 23c51719037..59ec7075115 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ServerWithJNDI.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ServerWithJNDI.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -30,7 +30,7 @@ import org.eclipse.jetty.webapp.WebAppContext; */ public class ServerWithJNDI { - public static void main( String[] args ) throws Exception + public static void main(String[] args) throws Exception { // Create the server @@ -38,23 +38,23 @@ public class ServerWithJNDI // Enable parsing of jndi-related parts of web.xml and jetty-env.xml Configuration.ClassList classlist = Configuration.ClassList - .setServerDefault(server); + .setServerDefault(server); classlist.addAfter("org.eclipse.jetty.webapp.FragmentConfiguration", - "org.eclipse.jetty.plus.webapp.EnvConfiguration", - "org.eclipse.jetty.plus.webapp.PlusConfiguration"); + "org.eclipse.jetty.plus.webapp.EnvConfiguration", + "org.eclipse.jetty.plus.webapp.PlusConfiguration"); // Create a WebApp WebAppContext webapp = new WebAppContext(); webapp.setContextPath("/"); File warFile = new File( - "../../jetty-distribution/target/distribution/demo-base/webapps/test-jndi.war"); + "../../jetty-distribution/target/distribution/demo-base/webapps/test-jndi.war"); webapp.setWar(warFile.getAbsolutePath()); server.setHandler(webapp); // Register new transaction manager in JNDI // At runtime, the webapp accesses this as java:comp/UserTransaction new org.eclipse.jetty.plus.jndi.Transaction( - new com.acme.MockUserTransaction()); + new com.acme.MockUserTransaction()); // Define an env entry with Server scope. // At runtime, the webapp accesses this as java:comp/env/woggle @@ -108,7 +108,7 @@ public class ServerWithJNDI // At runtime the webapp accesses this as // java:comp/env/jdbc/mydatasource new org.eclipse.jetty.plus.jndi.Resource( - webapp, "jdbc/mydatasource", new com.acme.MockDataSource()); + webapp, "jdbc/mydatasource", new com.acme.MockDataSource()); server.start(); server.join(); diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SimplestServer.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SimplestServer.java index 73f8fbbe04c..a48235c55d5 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SimplestServer.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SimplestServer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -25,7 +25,7 @@ import org.eclipse.jetty.server.Server; */ public class SimplestServer { - public static void main( String[] args ) throws Exception + public static void main(String[] args) throws Exception { Server server = new Server(8080); server.start(); diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SplitFileServer.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SplitFileServer.java index a4c873f3b1f..4a681baa93e 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SplitFileServer.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SplitFileServer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -37,7 +37,7 @@ import org.eclipse.jetty.util.resource.Resource; */ public class SplitFileServer { - public static void main( String[] args ) throws Exception + public static void main(String[] args) throws Exception { // Create the Server object and a corresponding ServerConnector and then // set the port for the connector. In this example the server will @@ -47,7 +47,7 @@ public class SplitFileServer Server server = new Server(); ServerConnector connector = new ServerConnector(server); connector.setPort(8090); - server.setConnectors(new Connector[] { connector }); + server.setConnectors(new Connector[]{connector}); // Create a Context Handler and ResourceHandler. The ContextHandler is // getting set to "/" path but this could be anything you like for @@ -77,13 +77,13 @@ public class SplitFileServer // This will let jetty process urls against the declared contexts in // order to match up content. ContextHandlerCollection contexts = new ContextHandlerCollection(); - contexts.setHandlers(new Handler[] { context0, context1 }); + contexts.setHandlers(new Handler[]{context0, context1}); server.setHandler(contexts); // Start things up! server.start(); - + // Dump the server state System.out.println(server.dump()); diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/WebSocketJsrServer.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/WebSocketJsrServer.java index 916727658c0..c880bf229ad 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/WebSocketJsrServer.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/WebSocketJsrServer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -23,6 +23,8 @@ import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.handler.DefaultHandler; +import org.eclipse.jetty.server.handler.HandlerList; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.websocket.jsr356.server.ServerContainer; import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer; @@ -39,28 +41,33 @@ public class WebSocketJsrServer public static class EchoJsrSocket { @OnMessage - public void onMessage( Session session, String message ) + public void onMessage(Session session, String message) { session.getAsyncRemote().sendText(message); } } - public static void main( String[] args ) throws Exception + public static void main(String[] args) throws Exception { Server server = new Server(8080); + HandlerList handlers = new HandlerList(); + ServletContextHandler context = new ServletContextHandler( - ServletContextHandler.SESSIONS); + ServletContextHandler.SESSIONS); context.setContextPath("/"); - server.setHandler(context); + handlers.addHandler(context); // Enable javax.websocket configuration for the context ServerContainer wsContainer = WebSocketServerContainerInitializer - .configureContext(context); + .configureContext(context); // Add your websockets to the container wsContainer.addEndpoint(EchoJsrSocket.class); + handlers.addHandler(new DefaultHandler()); + + server.setHandler(handlers); server.start(); context.dumpStdErr(); server.join(); diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/WebSocketServer.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/WebSocketServer.java index 1b854ebf24b..ea92c922a17 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/WebSocketServer.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/WebSocketServer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -41,7 +41,7 @@ public class WebSocketServer public static class EchoSocket { @OnWebSocketMessage - public void onMessage( Session session, String message ) + public void onMessage(Session session, String message) { session.getRemote().sendStringByFuture(message); } @@ -54,19 +54,19 @@ public class WebSocketServer public static class EchoServlet extends WebSocketServlet { @Override - public void configure( WebSocketServletFactory factory ) + public void configure(WebSocketServletFactory factory) { // Register the echo websocket with the basic WebSocketCreator factory.register(EchoSocket.class); } } - public static void main( String[] args ) throws Exception + public static void main(String[] args) throws Exception { Server server = new Server(8080); ServletContextHandler context = new ServletContextHandler( - ServletContextHandler.SESSIONS); + ServletContextHandler.SESSIONS); context.setContextPath("/"); server.setHandler(context); diff --git a/examples/embedded/src/main/resources/exampleserver.xml b/examples/embedded/src/main/resources/exampleserver.xml index deae1ddec15..8f843d7a504 100644 --- a/examples/embedded/src/main/resources/exampleserver.xml +++ b/examples/embedded/src/main/resources/exampleserver.xml @@ -1,5 +1,4 @@ - - + diff --git a/examples/embedded/src/main/resources/jetty-logging.properties b/examples/embedded/src/main/resources/jetty-logging.properties index 810f9896c7e..c0a226179d4 100644 --- a/examples/embedded/src/main/resources/jetty-logging.properties +++ b/examples/embedded/src/main/resources/jetty-logging.properties @@ -9,3 +9,4 @@ #org.eclipse.jetty.server.LEVEL=DEBUG #org.eclipse.jetty.servlets.LEVEL=DEBUG #org.eclipse.jetty.alpn.LEVEL=DEBUG +#org.eclipse.jetty.jmx.LEVEL=DEBUG diff --git a/examples/embedded/src/main/resources/jetty-otherserver.xml b/examples/embedded/src/main/resources/jetty-otherserver.xml index 21272bb3a91..e65262d8071 100644 --- a/examples/embedded/src/main/resources/jetty-otherserver.xml +++ b/examples/embedded/src/main/resources/jetty-otherserver.xml @@ -1,5 +1,4 @@ - - + diff --git a/examples/embedded/src/test/java/org/eclipse/jetty/embedded/TestXml.java b/examples/embedded/src/test/java/org/eclipse/jetty/embedded/TestXml.java index 614f981fd10..bb45cf6c124 100644 --- a/examples/embedded/src/test/java/org/eclipse/jetty/embedded/TestXml.java +++ b/examples/embedded/src/test/java/org/eclipse/jetty/embedded/TestXml.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -24,8 +24,8 @@ public class TestXml { public static void main(String[] args) throws Exception { - System.setProperty("jetty.home","../jetty-distribution/target/distribution"); + System.setProperty("jetty.home", "../jetty-distribution/target/distribution"); XmlConfiguration.main("../jetty-jmx/src/main/config/etc/jetty-jmx.xml", - "../jetty-server/src/main/config/etc/jetty.xml"); + "../jetty-server/src/main/config/etc/jetty.xml"); } } diff --git a/examples/pom.xml b/examples/pom.xml index 22b9af3d71d..76613249caa 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -1,21 +1,31 @@ - 4.0.0 org.eclipse.jetty jetty-project - 9.4.13-SNAPSHOT - ../pom.xml + 9.4.21-SNAPSHOT + + 4.0.0 org.eclipse.jetty.examples examples-parent Jetty Examples :: Parent pom + true + + + org.apache.maven.plugins + maven-deploy-plugin + + + true + + org.codehaus.mojo findbugs-maven-plugin @@ -26,6 +36,7 @@ + - org.apache.maven.plugins - maven-source-plugin + org.apache.maven.plugins + maven-source-plugin org.codehaus.mojo diff --git a/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnection.java b/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnection.java index 8ec25a3661f..69b3cb83edc 100644 --- a/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnection.java +++ b/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnection.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -21,7 +21,6 @@ package org.eclipse.jetty.alpn.client; import java.util.List; import java.util.Map; import java.util.concurrent.Executor; - import javax.net.ssl.SSLEngine; import org.eclipse.jetty.io.ClientConnectionFactory; @@ -49,7 +48,7 @@ public class ALPNClientConnection extends NegotiatingClientConnection public void selected(String protocol) { - if (protocol==null || !protocols.contains(protocol)) + if (protocol == null || !protocols.contains(protocol)) close(); else super.completed(); diff --git a/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java b/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java index 04750504e14..3f6e1b9ebb4 100644 --- a/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java +++ b/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,14 +18,12 @@ package org.eclipse.jetty.alpn.client; -import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.ServiceLoader; import java.util.concurrent.Executor; - import javax.net.ssl.SSLEngine; import org.eclipse.jetty.io.ClientConnectionFactory; @@ -34,11 +32,10 @@ import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.NegotiatingClientConnectionFactory; import org.eclipse.jetty.io.ssl.ALPNProcessor.Client; import org.eclipse.jetty.io.ssl.SslClientConnectionFactory; -import org.eclipse.jetty.io.ssl.SslHandshakeListener; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -public class ALPNClientConnectionFactory extends NegotiatingClientConnectionFactory implements SslHandshakeListener +public class ALPNClientConnectionFactory extends NegotiatingClientConnectionFactory { private static final Logger LOG = Log.getLogger(ALPNClientConnectionFactory.class); @@ -57,14 +54,14 @@ public class ALPNClientConnectionFactory extends NegotiatingClientConnectionFact IllegalStateException failure = new IllegalStateException("No Client ALPNProcessors!"); // Use a for loop on iterator so load exceptions can be caught and ignored - for (Iterator i = ServiceLoader.load(Client.class).iterator(); i.hasNext();) + for (Iterator i = ServiceLoader.load(Client.class).iterator(); i.hasNext(); ) { Client processor; try { processor = i.next(); } - catch(Throwable x) + catch (Throwable x) { if (LOG.isDebugEnabled()) LOG.debug(x); @@ -96,7 +93,7 @@ public class ALPNClientConnectionFactory extends NegotiatingClientConnectionFact } @Override - public Connection newConnection(EndPoint endPoint, Map context) throws IOException + public Connection newConnection(EndPoint endPoint, Map context) { SSLEngine engine = (SSLEngine)context.get(SslClientConnectionFactory.SSL_ENGINE_CONTEXT_KEY); for (Client processor : processors) @@ -106,7 +103,7 @@ public class ALPNClientConnectionFactory extends NegotiatingClientConnectionFact if (LOG.isDebugEnabled()) LOG.debug("{} for {} on {}", processor, engine, endPoint); ALPNClientConnection connection = new ALPNClientConnection(endPoint, executor, getClientConnectionFactory(), - engine, context, protocols); + engine, context, protocols); processor.configure(engine, connection); return customize(connection, context); } diff --git a/jetty-alpn/jetty-alpn-conscrypt-client/pom.xml b/jetty-alpn/jetty-alpn-conscrypt-client/pom.xml index 2e63806ca5b..ea08886ffcd 100644 --- a/jetty-alpn/jetty-alpn-conscrypt-client/pom.xml +++ b/jetty-alpn/jetty-alpn-conscrypt-client/pom.xml @@ -1,12 +1,10 @@ - + org.eclipse.jetty jetty-alpn-parent - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 @@ -35,23 +33,23 @@ test
- + - - org.apache.felix - maven-bundle-plugin - true - - - Conscrypt Client ALPN - org.conscrypt;version="${conscrypt.version}",* - * - osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional - osgi.serviceloader; osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Client - <_nouses>true - - - + + org.apache.felix + maven-bundle-plugin + true + + + Conscrypt Client ALPN + org.conscrypt;version="${conscrypt.version}",* + * + osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional + osgi.serviceloader; osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Client + <_nouses>true + + + diff --git a/jetty-alpn/jetty-alpn-conscrypt-client/src/main/java/org/eclipse/jetty/alpn/conscrypt/client/ConscryptClientALPNProcessor.java b/jetty-alpn/jetty-alpn-conscrypt-client/src/main/java/org/eclipse/jetty/alpn/conscrypt/client/ConscryptClientALPNProcessor.java index 4a3f94833b6..2c80c687c44 100644 --- a/jetty-alpn/jetty-alpn-conscrypt-client/src/main/java/org/eclipse/jetty/alpn/conscrypt/client/ConscryptClientALPNProcessor.java +++ b/jetty-alpn/jetty-alpn-conscrypt-client/src/main/java/org/eclipse/jetty/alpn/conscrypt/client/ConscryptClientALPNProcessor.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,12 +18,10 @@ package org.eclipse.jetty.alpn.conscrypt.client; -import java.lang.reflect.Method; -import java.nio.charset.StandardCharsets; import java.security.Security; - import javax.net.ssl.SSLEngine; +import org.conscrypt.Conscrypt; import org.conscrypt.OpenSSLProvider; import org.eclipse.jetty.alpn.client.ALPNClientConnection; import org.eclipse.jetty.io.Connection; @@ -40,7 +38,7 @@ public class ConscryptClientALPNProcessor implements ALPNProcessor.Client @Override public void init() { - if (Security.getProvider("Conscrypt")==null) + if (Security.getProvider("Conscrypt") == null) { Security.addProvider(new OpenSSLProvider()); if (LOG.isDebugEnabled()) @@ -59,13 +57,11 @@ public class ConscryptClientALPNProcessor implements ALPNProcessor.Client { try { - Method setAlpnProtocols = sslEngine.getClass().getDeclaredMethod("setApplicationProtocols", String[].class); - setAlpnProtocols.setAccessible(true); ALPNClientConnection alpn = (ALPNClientConnection)connection; String[] protocols = alpn.getProtocols().toArray(new String[0]); - setAlpnProtocols.invoke(sslEngine, (Object)protocols); + Conscrypt.setApplicationProtocols(sslEngine, protocols); ((SslConnection.DecryptedEndPoint)connection.getEndPoint()).getSslConnection() - .addHandshakeListener(new ALPNListener(alpn)); + .addHandshakeListener(new ALPNListener(alpn)); } catch (RuntimeException x) { @@ -92,9 +88,9 @@ public class ConscryptClientALPNProcessor implements ALPNProcessor.Client try { SSLEngine sslEngine = alpnConnection.getSSLEngine(); - Method method = sslEngine.getClass().getDeclaredMethod("getApplicationProtocol"); - method.setAccessible(true); - String protocol = (String)method.invoke(sslEngine); + String protocol = Conscrypt.getApplicationProtocol(sslEngine); + if (LOG.isDebugEnabled()) + LOG.debug("Selected {} for {}", protocol, alpnConnection); alpnConnection.selected(protocol); } catch (Throwable e) diff --git a/jetty-alpn/jetty-alpn-conscrypt-client/src/test/java/org/eclipse/jetty/alpn/java/client/ConscryptHTTP2Client.java b/jetty-alpn/jetty-alpn-conscrypt-client/src/test/java/org/eclipse/jetty/alpn/java/client/ConscryptHTTP2Client.java deleted file mode 100644 index 8b72b1eefde..00000000000 --- a/jetty-alpn/jetty-alpn-conscrypt-client/src/test/java/org/eclipse/jetty/alpn/java/client/ConscryptHTTP2Client.java +++ /dev/null @@ -1,89 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.alpn.java.client; - -import java.net.InetSocketAddress; -import java.security.Security; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import org.conscrypt.OpenSSLProvider; -import org.eclipse.jetty.http.HttpFields; -import org.eclipse.jetty.http.HttpURI; -import org.eclipse.jetty.http.HttpVersion; -import org.eclipse.jetty.http.MetaData; -import org.eclipse.jetty.http2.api.Session; -import org.eclipse.jetty.http2.api.Stream; -import org.eclipse.jetty.http2.client.HTTP2Client; -import org.eclipse.jetty.http2.frames.DataFrame; -import org.eclipse.jetty.http2.frames.HeadersFrame; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.FuturePromise; -import org.eclipse.jetty.util.Jetty; -import org.eclipse.jetty.util.Promise; -import org.eclipse.jetty.util.ssl.SslContextFactory; - -public class ConscryptHTTP2Client -{ - public static void main(String[] args) throws Exception - { - Security.addProvider(new OpenSSLProvider()); - SslContextFactory sslContextFactory = new SslContextFactory(); - sslContextFactory.setProvider("Conscrypt"); - HTTP2Client client = new HTTP2Client(); - client.addBean(sslContextFactory); - client.start(); - - String host = "webtide.com"; - int port = 443; - - FuturePromise sessionPromise = new FuturePromise<>(); - client.connect(sslContextFactory, new InetSocketAddress(host, port), new Session.Listener.Adapter(), sessionPromise); - Session session = sessionPromise.get(5, TimeUnit.SECONDS); - - HttpFields requestFields = new HttpFields(); - requestFields.put("User-Agent", client.getClass().getName() + "/" + Jetty.VERSION); - MetaData.Request metaData = new MetaData.Request("GET", new HttpURI("https://" + host + ":" + port + "/"), HttpVersion.HTTP_2, requestFields); - HeadersFrame headersFrame = new HeadersFrame(metaData, null, true); - CountDownLatch latch = new CountDownLatch(1); - session.newStream(headersFrame, new Promise.Adapter<>(), new Stream.Listener.Adapter() - { - @Override - public void onHeaders(Stream stream, HeadersFrame frame) - { - System.err.println(frame); - if (frame.isEndStream()) - latch.countDown(); - } - - @Override - public void onData(Stream stream, DataFrame frame, Callback callback) - { - System.err.println(frame); - callback.succeeded(); - if (frame.isEndStream()) - latch.countDown(); - } - }); - - latch.await(5, TimeUnit.SECONDS); - - client.stop(); - } -} diff --git a/jetty-alpn/jetty-alpn-conscrypt-client/src/test/java/org/eclipse/jetty/alpn/java/client/ConscryptHTTP2ClientTest.java b/jetty-alpn/jetty-alpn-conscrypt-client/src/test/java/org/eclipse/jetty/alpn/java/client/ConscryptHTTP2ClientTest.java new file mode 100644 index 00000000000..cc3ef1dbaa7 --- /dev/null +++ b/jetty-alpn/jetty-alpn-conscrypt-client/src/test/java/org/eclipse/jetty/alpn/java/client/ConscryptHTTP2ClientTest.java @@ -0,0 +1,120 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.alpn.java.client; + +import java.net.InetSocketAddress; +import java.net.Socket; +import java.security.Security; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.conscrypt.Conscrypt; +import org.conscrypt.OpenSSLProvider; +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpURI; +import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http.MetaData; +import org.eclipse.jetty.http2.api.Session; +import org.eclipse.jetty.http2.api.Stream; +import org.eclipse.jetty.http2.client.HTTP2Client; +import org.eclipse.jetty.http2.frames.DataFrame; +import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.FuturePromise; +import org.eclipse.jetty.util.Jetty; +import org.eclipse.jetty.util.Promise; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class ConscryptHTTP2ClientTest +{ + @Tag("external") + @Test + public void testConscryptHTTP2Client() throws Exception + { + String host = "webtide.com"; + int port = 443; + + Assumptions.assumeTrue(canConnectTo(host, port)); + + Security.insertProviderAt(new OpenSSLProvider(), 1); + SslContextFactory sslContextFactory = new SslContextFactory.Client(); + sslContextFactory.setProvider("Conscrypt"); + Conscrypt.setDefaultHostnameVerifier((hostname, session) -> true); + + HTTP2Client client = new HTTP2Client(); + try + { + client.addBean(sslContextFactory); + client.start(); + + FuturePromise sessionPromise = new FuturePromise<>(); + client.connect(sslContextFactory, new InetSocketAddress(host, port), new Session.Listener.Adapter(), sessionPromise); + Session session = sessionPromise.get(15, TimeUnit.SECONDS); + + HttpFields requestFields = new HttpFields(); + requestFields.put("User-Agent", client.getClass().getName() + "/" + Jetty.VERSION); + MetaData.Request metaData = new MetaData.Request("GET", new HttpURI("https://" + host + ":" + port + "/"), HttpVersion.HTTP_2, requestFields); + HeadersFrame headersFrame = new HeadersFrame(metaData, null, true); + CountDownLatch latch = new CountDownLatch(1); + session.newStream(headersFrame, new Promise.Adapter<>(), new Stream.Listener.Adapter() + { + @Override + public void onHeaders(Stream stream, HeadersFrame frame) + { + System.err.println(frame); + if (frame.isEndStream()) + latch.countDown(); + } + + @Override + public void onData(Stream stream, DataFrame frame, Callback callback) + { + System.err.println(frame); + callback.succeeded(); + if (frame.isEndStream()) + latch.countDown(); + } + }); + + assertTrue(latch.await(15, TimeUnit.SECONDS)); + } + finally + { + client.stop(); + } + } + + private boolean canConnectTo(String host, int port) + { + try + { + new Socket(host, port).close(); + return true; + } + catch (Throwable x) + { + return false; + } + } +} diff --git a/jetty-alpn/jetty-alpn-conscrypt-server/pom.xml b/jetty-alpn/jetty-alpn-conscrypt-server/pom.xml index a4cb0e784fb..468be1e4079 100644 --- a/jetty-alpn/jetty-alpn-conscrypt-server/pom.xml +++ b/jetty-alpn/jetty-alpn-conscrypt-server/pom.xml @@ -1,10 +1,9 @@ - + org.eclipse.jetty jetty-alpn-parent - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 @@ -38,23 +37,48 @@ ${project.version} test
+ + org.eclipse.jetty + jetty-alpn-conscrypt-client + ${project.version} + test + + + org.eclipse.jetty + jetty-client + ${project.version} + test + + + org.eclipse.jetty.http2 + http2-client + ${project.version} + test + + + org.eclipse.jetty.http2 + http2-http-client-transport + ${project.version} + test + +
- - org.apache.felix - maven-bundle-plugin - true - - - Conscrypt ALPN - org.conscrypt;version="${conscrypt.version}",* - osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional - osgi.serviceloader;osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Server - <_nouses>true - - - + + org.apache.felix + maven-bundle-plugin + true + + + Conscrypt ALPN + org.conscrypt;version="${conscrypt.version}",* + osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional + osgi.serviceloader;osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Server + <_nouses>true + + + diff --git a/jetty-alpn/jetty-alpn-conscrypt-server/src/main/java/org/eclipse/jetty/alpn/conscrypt/server/ConscryptServerALPNProcessor.java b/jetty-alpn/jetty-alpn-conscrypt-server/src/main/java/org/eclipse/jetty/alpn/conscrypt/server/ConscryptServerALPNProcessor.java index 76dfaa3a8db..3e5a4ca2598 100644 --- a/jetty-alpn/jetty-alpn-conscrypt-server/src/main/java/org/eclipse/jetty/alpn/conscrypt/server/ConscryptServerALPNProcessor.java +++ b/jetty-alpn/jetty-alpn-conscrypt-server/src/main/java/org/eclipse/jetty/alpn/conscrypt/server/ConscryptServerALPNProcessor.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,13 +18,13 @@ package org.eclipse.jetty.alpn.conscrypt.server; -import java.lang.reflect.Method; import java.security.Security; import java.util.List; -import java.util.function.BiFunction; - import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLSocket; +import org.conscrypt.ApplicationProtocolSelector; +import org.conscrypt.Conscrypt; import org.conscrypt.OpenSSLProvider; import org.eclipse.jetty.alpn.server.ALPNServerConnection; import org.eclipse.jetty.io.Connection; @@ -41,7 +41,7 @@ public class ConscryptServerALPNProcessor implements ALPNProcessor.Server @Override public void init() { - if (Security.getProvider("Conscrypt")==null) + if (Security.getProvider("Conscrypt") == null) { Security.addProvider(new OpenSSLProvider()); if (LOG.isDebugEnabled()) @@ -56,13 +56,11 @@ public class ConscryptServerALPNProcessor implements ALPNProcessor.Server } @Override - public void configure(SSLEngine sslEngine,Connection connection) + public void configure(SSLEngine sslEngine, Connection connection) { try { - Method method = sslEngine.getClass().getMethod("setHandshakeApplicationProtocolSelector", BiFunction.class); - method.setAccessible(true); - method.invoke(sslEngine,new ALPNCallback((ALPNServerConnection)connection)); + Conscrypt.setApplicationProtocolSelector(sslEngine, new ALPNCallback((ALPNServerConnection)connection)); } catch (RuntimeException x) { @@ -74,23 +72,30 @@ public class ConscryptServerALPNProcessor implements ALPNProcessor.Server } } - private final class ALPNCallback implements BiFunction,String>, SslHandshakeListener + private final class ALPNCallback extends ApplicationProtocolSelector implements SslHandshakeListener { private final ALPNServerConnection alpnConnection; private ALPNCallback(ALPNServerConnection connection) { - alpnConnection = connection; + alpnConnection = connection; ((DecryptedEndPoint)alpnConnection.getEndPoint()).getSslConnection().addHandshakeListener(this); } @Override - public String apply(SSLEngine engine, List protocols) + public String selectApplicationProtocol(SSLEngine engine, List protocols) { - if (LOG.isDebugEnabled()) - LOG.debug("apply {} {}", alpnConnection, protocols); alpnConnection.select(protocols); - return alpnConnection.getProtocol(); + String protocol = alpnConnection.getProtocol(); + if (LOG.isDebugEnabled()) + LOG.debug("Selected {} among {} for {}", protocol, protocols, alpnConnection); + return protocol; + } + + @Override + public String selectApplicationProtocol(SSLSocket socket, List protocols) + { + throw new UnsupportedOperationException(); } @Override @@ -99,7 +104,7 @@ public class ConscryptServerALPNProcessor implements ALPNProcessor.Server String protocol = alpnConnection.getProtocol(); if (LOG.isDebugEnabled()) LOG.debug("TLS handshake succeeded, protocol={} for {}", protocol, alpnConnection); - if (protocol ==null) + if (protocol == null) alpnConnection.unsupported(); } diff --git a/jetty-alpn/jetty-alpn-conscrypt-server/src/test/java/org/eclipse/jetty/alpn/conscrypt/server/ConscryptHTTP2Server.java b/jetty-alpn/jetty-alpn-conscrypt-server/src/test/java/org/eclipse/jetty/alpn/conscrypt/server/ConscryptHTTP2Server.java deleted file mode 100644 index 2c70dd6db0d..00000000000 --- a/jetty-alpn/jetty-alpn-conscrypt-server/src/test/java/org/eclipse/jetty/alpn/conscrypt/server/ConscryptHTTP2Server.java +++ /dev/null @@ -1,72 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.alpn.conscrypt.server; - -import java.security.Security; - -import org.conscrypt.OpenSSLProvider; -import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory; -import org.eclipse.jetty.http2.HTTP2Cipher; -import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory; -import org.eclipse.jetty.server.HttpConfiguration; -import org.eclipse.jetty.server.HttpConnectionFactory; -import org.eclipse.jetty.server.SecureRequestCustomizer; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.server.SslConnectionFactory; -import org.eclipse.jetty.util.ssl.SslContextFactory; - -/** - * Test server that verifies that the Conscrypt ALPN mechanism works. - */ -public class ConscryptHTTP2Server -{ - public static void main(String[] args) throws Exception - { - Security.addProvider(new OpenSSLProvider()); - - Server server = new Server(); - - HttpConfiguration httpsConfig = new HttpConfiguration(); - httpsConfig.setSecureScheme("https"); - httpsConfig.setSecurePort(8443); - httpsConfig.setSendXPoweredBy(true); - httpsConfig.setSendServerVersion(true); - httpsConfig.addCustomizer(new SecureRequestCustomizer()); - - SslContextFactory sslContextFactory = new SslContextFactory(); - sslContextFactory.setProvider("Conscrypt"); - sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks"); - sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"); - sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g"); - sslContextFactory.setCipherComparator(HTTP2Cipher.COMPARATOR); - - HttpConnectionFactory http = new HttpConnectionFactory(httpsConfig); - HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(httpsConfig); - ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory(); - alpn.setDefaultProtocol(http.getProtocol()); - SslConnectionFactory ssl = new SslConnectionFactory(sslContextFactory, alpn.getProtocol()); - - ServerConnector http2Connector = new ServerConnector(server, ssl, alpn, h2, http); - http2Connector.setPort(8443); - server.addConnector(http2Connector); - - server.start(); - } -} diff --git a/jetty-alpn/jetty-alpn-conscrypt-server/src/test/java/org/eclipse/jetty/alpn/conscrypt/server/ConscryptHTTP2ServerTest.java b/jetty-alpn/jetty-alpn-conscrypt-server/src/test/java/org/eclipse/jetty/alpn/conscrypt/server/ConscryptHTTP2ServerTest.java new file mode 100644 index 00000000000..2a0036b9348 --- /dev/null +++ b/jetty-alpn/jetty-alpn-conscrypt-server/src/test/java/org/eclipse/jetty/alpn/conscrypt/server/ConscryptHTTP2ServerTest.java @@ -0,0 +1,151 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.alpn.conscrypt.server; + +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.Security; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.conscrypt.OpenSSLProvider; +import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.http2.client.HTTP2Client; +import org.eclipse.jetty.http2.client.http.HttpClientTransportOverHTTP2; +import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory; +import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.server.HttpConnectionFactory; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.SecureRequestCustomizer; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.SslConnectionFactory; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.util.JavaVersion; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Test server that verifies that the Conscrypt ALPN mechanism works for both server and client side + */ +public class ConscryptHTTP2ServerTest +{ + static + { + Security.addProvider(new OpenSSLProvider()); + } + + private Server server = new Server(); + + private SslContextFactory.Server newServerSslContextFactory() + { + SslContextFactory.Server sslContextFactory = new SslContextFactory.Server(); + configureSslContextFactory(sslContextFactory); + return sslContextFactory; + } + + private SslContextFactory.Client newClientSslContextFactory() + { + SslContextFactory.Client sslContextFactory = new SslContextFactory.Client(); + configureSslContextFactory(sslContextFactory); + sslContextFactory.setEndpointIdentificationAlgorithm(null); + return sslContextFactory; + } + + private void configureSslContextFactory(SslContextFactory sslContextFactory) + { + Path path = Paths.get("src", "test", "resources"); + File keys = path.resolve("keystore").toFile(); + sslContextFactory.setKeyStorePath(keys.getAbsolutePath()); + sslContextFactory.setKeyManagerPassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"); + sslContextFactory.setTrustStorePath(keys.getAbsolutePath()); + sslContextFactory.setTrustStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"); + sslContextFactory.setProvider("Conscrypt"); + if (JavaVersion.VERSION.getPlatform() < 9) + { + // Conscrypt enables TLSv1.3 by default but it's not supported in Java 8. + sslContextFactory.addExcludeProtocols("TLSv1.3"); + } + } + + @BeforeEach + public void startServer() throws Exception + { + HttpConfiguration httpsConfig = new HttpConfiguration(); + httpsConfig.setSecureScheme("https"); + + httpsConfig.setSendXPoweredBy(true); + httpsConfig.setSendServerVersion(true); + httpsConfig.addCustomizer(new SecureRequestCustomizer()); + + HttpConnectionFactory http = new HttpConnectionFactory(httpsConfig); + HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(httpsConfig); + ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory(); + alpn.setDefaultProtocol(http.getProtocol()); + SslConnectionFactory ssl = new SslConnectionFactory(newServerSslContextFactory(), alpn.getProtocol()); + + ServerConnector http2Connector = new ServerConnector(server, ssl, alpn, h2, http); + http2Connector.setPort(0); + server.addConnector(http2Connector); + + server.setHandler(new AbstractHandler() + { + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) + { + response.setStatus(200); + baseRequest.setHandled(true); + } + }); + + server.start(); + } + + @AfterEach + public void stopServer() throws Exception + { + if (server != null) + server.stop(); + } + + @Test + public void testSimpleRequest() throws Exception + { + HTTP2Client h2Client = new HTTP2Client(); + HttpClient client = new HttpClient(new HttpClientTransportOverHTTP2(h2Client), newClientSslContextFactory()); + client.start(); + try + { + int port = ((ServerConnector)server.getConnectors()[0]).getLocalPort(); + ContentResponse contentResponse = client.GET("https://localhost:" + port); + assertEquals(200, contentResponse.getStatus()); + } + finally + { + client.stop(); + } + } +} diff --git a/jetty-alpn/jetty-alpn-conscrypt-server/src/test/resources/keystore b/jetty-alpn/jetty-alpn-conscrypt-server/src/test/resources/keystore new file mode 100644 index 00000000000..428ba54776e Binary files /dev/null and b/jetty-alpn/jetty-alpn-conscrypt-server/src/test/resources/keystore differ diff --git a/jetty-alpn/jetty-alpn-conscrypt-server/src/test/resources/keystore.jks b/jetty-alpn/jetty-alpn-conscrypt-server/src/test/resources/keystore.jks deleted file mode 100644 index d6592f95ee9..00000000000 Binary files a/jetty-alpn/jetty-alpn-conscrypt-server/src/test/resources/keystore.jks and /dev/null differ diff --git a/jetty-alpn/jetty-alpn-java-client/pom.xml b/jetty-alpn/jetty-alpn-java-client/pom.xml index f013d1dba03..2a47e9ae2b1 100644 --- a/jetty-alpn/jetty-alpn-java-client/pom.xml +++ b/jetty-alpn/jetty-alpn-java-client/pom.xml @@ -1,61 +1,59 @@ - + - - org.eclipse.jetty - jetty-alpn-parent - 9.4.13-SNAPSHOT - + + org.eclipse.jetty + jetty-alpn-parent + 9.4.21-SNAPSHOT + - 4.0.0 - jetty-alpn-java-client - Jetty :: ALPN :: JDK9 Client Implementation + 4.0.0 + jetty-alpn-java-client + Jetty :: ALPN :: JDK9 Client Implementation - - ${project.groupId}.alpn.java.client - + + ${project.groupId}.alpn.java.client + - - - - maven-compiler-plugin - - 1.9 - 1.9 - 9 - - - - org.apache.felix - maven-bundle-plugin - true - - - JDK9 Client ALPN - * - osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional - osgi.serviceloader; osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Client - <_nouses>true - - - - - + + + + maven-compiler-plugin + + 1.9 + 1.9 + 9 + + + + org.apache.felix + maven-bundle-plugin + true + + + JDK9 Client ALPN + * + osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional + osgi.serviceloader; osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Client + <_nouses>true + + + + + - - - org.eclipse.jetty - jetty-alpn-client - ${project.version} - - - org.eclipse.jetty.http2 - http2-client - ${project.version} - test - - + + + org.eclipse.jetty + jetty-alpn-client + ${project.version} + + + org.eclipse.jetty.http2 + http2-client + ${project.version} + test + + diff --git a/jetty-alpn/jetty-alpn-java-client/src/main/java/org/eclipse/jetty/alpn/java/client/JDK9ClientALPNProcessor.java b/jetty-alpn/jetty-alpn-java-client/src/main/java/org/eclipse/jetty/alpn/java/client/JDK9ClientALPNProcessor.java index d049de486c0..f8e444b051e 100644 --- a/jetty-alpn/jetty-alpn-java-client/src/main/java/org/eclipse/jetty/alpn/java/client/JDK9ClientALPNProcessor.java +++ b/jetty-alpn/jetty-alpn-java-client/src/main/java/org/eclipse/jetty/alpn/java/client/JDK9ClientALPNProcessor.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,7 +19,6 @@ package org.eclipse.jetty.alpn.java.client; import java.util.List; - import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLParameters; @@ -39,15 +38,15 @@ public class JDK9ClientALPNProcessor implements ALPNProcessor.Client @Override public void init() { - if (JavaVersion.VERSION.getPlatform()<9) - throw new IllegalStateException(this + " not applicable for java "+JavaVersion.VERSION); + if (JavaVersion.VERSION.getPlatform() < 9) + throw new IllegalStateException(this + " not applicable for java " + JavaVersion.VERSION); } @Override public boolean appliesTo(SSLEngine sslEngine) { Module module = sslEngine.getClass().getModule(); - return module!=null && "java.base".equals(module.getName()); + return module != null && "java.base".equals(module.getName()); } @Override @@ -59,7 +58,7 @@ public class JDK9ClientALPNProcessor implements ALPNProcessor.Client sslParameters.setApplicationProtocols(protocols.toArray(new String[protocols.size()])); sslEngine.setSSLParameters(sslParameters); ((DecryptedEndPoint)connection.getEndPoint()).getSslConnection() - .addHandshakeListener(new ALPNListener(alpn)); + .addHandshakeListener(new ALPNListener(alpn)); } private final class ALPNListener implements SslHandshakeListener diff --git a/jetty-alpn/jetty-alpn-java-client/src/test/java/org/eclipse/jetty/alpn/java/client/JDK9HTTP2Client.java b/jetty-alpn/jetty-alpn-java-client/src/test/java/org/eclipse/jetty/alpn/java/client/JDK9HTTP2Client.java deleted file mode 100644 index 7067fd66e5a..00000000000 --- a/jetty-alpn/jetty-alpn-java-client/src/test/java/org/eclipse/jetty/alpn/java/client/JDK9HTTP2Client.java +++ /dev/null @@ -1,85 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.alpn.java.client; - -import java.net.InetSocketAddress; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.http.HttpFields; -import org.eclipse.jetty.http.HttpURI; -import org.eclipse.jetty.http.HttpVersion; -import org.eclipse.jetty.http.MetaData; -import org.eclipse.jetty.http2.api.Session; -import org.eclipse.jetty.http2.api.Stream; -import org.eclipse.jetty.http2.client.HTTP2Client; -import org.eclipse.jetty.http2.frames.DataFrame; -import org.eclipse.jetty.http2.frames.HeadersFrame; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.FuturePromise; -import org.eclipse.jetty.util.Jetty; -import org.eclipse.jetty.util.Promise; -import org.eclipse.jetty.util.ssl.SslContextFactory; - -public class JDK9HTTP2Client -{ - public static void main(String[] args) throws Exception - { - HTTP2Client client = new HTTP2Client(); - SslContextFactory sslContextFactory = new SslContextFactory(); - client.addBean(sslContextFactory); - client.start(); - - String host = "webtide.com"; - int port = 443; - - FuturePromise sessionPromise = new FuturePromise<>(); - client.connect(sslContextFactory, new InetSocketAddress(host, port), new Session.Listener.Adapter(), sessionPromise); - Session session = sessionPromise.get(5, TimeUnit.SECONDS); - - HttpFields requestFields = new HttpFields(); - requestFields.put("User-Agent", client.getClass().getName() + "/" + Jetty.VERSION); - MetaData.Request metaData = new MetaData.Request("GET", new HttpURI("https://" + host + ":" + port + "/"), HttpVersion.HTTP_2, requestFields); - HeadersFrame headersFrame = new HeadersFrame(metaData, null, true); - CountDownLatch latch = new CountDownLatch(1); - session.newStream(headersFrame, new Promise.Adapter<>(), new Stream.Listener.Adapter() - { - @Override - public void onHeaders(Stream stream, HeadersFrame frame) - { - System.err.println(frame); - if (frame.isEndStream()) - latch.countDown(); - } - - @Override - public void onData(Stream stream, DataFrame frame, Callback callback) - { - System.err.println(frame); - callback.succeeded(); - if (frame.isEndStream()) - latch.countDown(); - } - }); - - latch.await(5, TimeUnit.SECONDS); - - client.stop(); - } -} diff --git a/jetty-alpn/jetty-alpn-java-client/src/test/java/org/eclipse/jetty/alpn/java/client/JDK9HTTP2ClientTest.java b/jetty-alpn/jetty-alpn-java-client/src/test/java/org/eclipse/jetty/alpn/java/client/JDK9HTTP2ClientTest.java new file mode 100644 index 00000000000..6d6f73f79e8 --- /dev/null +++ b/jetty-alpn/jetty-alpn-java-client/src/test/java/org/eclipse/jetty/alpn/java/client/JDK9HTTP2ClientTest.java @@ -0,0 +1,111 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.alpn.java.client; + +import java.net.InetSocketAddress; +import java.net.Socket; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpURI; +import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http.MetaData; +import org.eclipse.jetty.http2.api.Session; +import org.eclipse.jetty.http2.api.Stream; +import org.eclipse.jetty.http2.client.HTTP2Client; +import org.eclipse.jetty.http2.frames.DataFrame; +import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.FuturePromise; +import org.eclipse.jetty.util.Jetty; +import org.eclipse.jetty.util.Promise; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +public class JDK9HTTP2ClientTest +{ + @Tag("external") + @Test + public void testJDK9HTTP2Client() throws Exception + { + String host = "webtide.com"; + int port = 443; + + Assumptions.assumeTrue(canConnectTo(host, port)); + + HTTP2Client client = new HTTP2Client(); + try + { + SslContextFactory sslContextFactory = new SslContextFactory.Client(); + client.addBean(sslContextFactory); + client.start(); + + FuturePromise sessionPromise = new FuturePromise<>(); + client.connect(sslContextFactory, new InetSocketAddress(host, port), new Session.Listener.Adapter(), sessionPromise); + Session session = sessionPromise.get(15, TimeUnit.SECONDS); + + HttpFields requestFields = new HttpFields(); + requestFields.put("User-Agent", client.getClass().getName() + "/" + Jetty.VERSION); + MetaData.Request metaData = new MetaData.Request("GET", new HttpURI("https://" + host + ":" + port + "/"), HttpVersion.HTTP_2, requestFields); + HeadersFrame headersFrame = new HeadersFrame(metaData, null, true); + CountDownLatch latch = new CountDownLatch(1); + session.newStream(headersFrame, new Promise.Adapter<>(), new Stream.Listener.Adapter() + { + @Override + public void onHeaders(Stream stream, HeadersFrame frame) + { + System.err.println(frame); + if (frame.isEndStream()) + latch.countDown(); + } + + @Override + public void onData(Stream stream, DataFrame frame, Callback callback) + { + System.err.println(frame); + callback.succeeded(); + if (frame.isEndStream()) + latch.countDown(); + } + }); + + latch.await(15, TimeUnit.SECONDS); + } + finally + { + client.stop(); + } + } + + private boolean canConnectTo(String host, int port) + { + try + { + new Socket(host, port).close(); + return true; + } + catch (Throwable x) + { + return false; + } + } +} diff --git a/jetty-alpn/jetty-alpn-java-server/pom.xml b/jetty-alpn/jetty-alpn-java-server/pom.xml index 2d496426ea2..8cef4b2325a 100644 --- a/jetty-alpn/jetty-alpn-java-server/pom.xml +++ b/jetty-alpn/jetty-alpn-java-server/pom.xml @@ -1,74 +1,72 @@ - - - org.eclipse.jetty - jetty-alpn-parent - 9.4.13-SNAPSHOT - + + + org.eclipse.jetty + jetty-alpn-parent + 9.4.21-SNAPSHOT + - 4.0.0 - jetty-alpn-java-server - Jetty :: ALPN :: JDK9 Server Implementation + 4.0.0 + jetty-alpn-java-server + Jetty :: ALPN :: JDK9 Server Implementation - - ${project.groupId}.alpn.java.server - + + ${project.groupId}.alpn.java.server + - - - - maven-compiler-plugin - - 1.9 - 1.9 - 9 - - - - org.apache.felix - maven-bundle-plugin - true - - - JDK9 Server ALPN - osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional - osgi.serviceloader;osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Server - <_nouses>true - - - - - + + + + maven-compiler-plugin + + 1.9 + 1.9 + 9 + + + + org.apache.felix + maven-bundle-plugin + true + + + JDK9 Server ALPN + osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional + osgi.serviceloader;osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Server + <_nouses>true + + + + + - - - org.eclipse.jetty - jetty-io - ${project.version} - - - org.eclipse.jetty.alpn - alpn-api - ${alpn.api.version} - - - org.eclipse.jetty - jetty-alpn-server - ${project.version} - - - org.eclipse.jetty.http2 - http2-server - ${project.version} - test - - - org.eclipse.jetty.toolchain - jetty-test-helper - test - - + + + org.eclipse.jetty + jetty-io + ${project.version} + + + org.eclipse.jetty.alpn + alpn-api + ${alpn.api.version} + + + org.eclipse.jetty + jetty-alpn-server + ${project.version} + + + org.eclipse.jetty.http2 + http2-server + ${project.version} + test + + + org.eclipse.jetty.toolchain + jetty-test-helper + test + + diff --git a/jetty-alpn/jetty-alpn-java-server/src/main/java/org/eclipse/jetty/alpn/java/server/JDK9ServerALPNProcessor.java b/jetty-alpn/jetty-alpn-java-server/src/main/java/org/eclipse/jetty/alpn/java/server/JDK9ServerALPNProcessor.java index d999a898692..ca091a96e15 100644 --- a/jetty-alpn/jetty-alpn-java-server/src/main/java/org/eclipse/jetty/alpn/java/server/JDK9ServerALPNProcessor.java +++ b/jetty-alpn/jetty-alpn-java-server/src/main/java/org/eclipse/jetty/alpn/java/server/JDK9ServerALPNProcessor.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,7 +20,6 @@ package org.eclipse.jetty.alpn.java.server; import java.util.List; import java.util.function.BiFunction; - import javax.net.ssl.SSLEngine; import org.eclipse.jetty.alpn.server.ALPNServerConnection; @@ -39,15 +38,15 @@ public class JDK9ServerALPNProcessor implements ALPNProcessor.Server, SslHandsha @Override public void init() { - if (JavaVersion.VERSION.getPlatform()<9) - throw new IllegalStateException(this + " not applicable for java "+JavaVersion.VERSION); + if (JavaVersion.VERSION.getPlatform() < 9) + throw new IllegalStateException(this + " not applicable for java " + JavaVersion.VERSION); } @Override public boolean appliesTo(SSLEngine sslEngine) { Module module = sslEngine.getClass().getModule(); - return module!=null && "java.base".equals(module.getName()); + return module != null && "java.base".equals(module.getName()); } @Override @@ -56,7 +55,7 @@ public class JDK9ServerALPNProcessor implements ALPNProcessor.Server, SslHandsha sslEngine.setHandshakeApplicationProtocolSelector(new ALPNCallback((ALPNServerConnection)connection)); } - private final class ALPNCallback implements BiFunction,String>, SslHandshakeListener + private final class ALPNCallback implements BiFunction, String>, SslHandshakeListener { private final ALPNServerConnection alpnConnection; @@ -81,7 +80,7 @@ public class JDK9ServerALPNProcessor implements ALPNProcessor.Server, SslHandsha String protocol = alpnConnection.getProtocol(); if (LOG.isDebugEnabled()) LOG.debug("TLS handshake succeeded, protocol={} for {}", protocol, alpnConnection); - if (protocol ==null) + if (protocol == null) alpnConnection.unsupported(); } diff --git a/jetty-alpn/jetty-alpn-java-server/src/test/java/org/eclipse/jetty/alpn/java/server/JDK9ALPNTest.java b/jetty-alpn/jetty-alpn-java-server/src/test/java/org/eclipse/jetty/alpn/java/server/JDK9ALPNTest.java index 2aa48a522eb..38582512df9 100644 --- a/jetty-alpn/jetty-alpn-java-server/src/test/java/org/eclipse/jetty/alpn/java/server/JDK9ALPNTest.java +++ b/jetty-alpn/jetty-alpn-java-server/src/test/java/org/eclipse/jetty/alpn/java/server/JDK9ALPNTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,16 +18,12 @@ package org.eclipse.jetty.alpn.java.server; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; - import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.nio.charset.StandardCharsets; - import javax.net.ssl.SSLContext; import javax.net.ssl.SSLParameters; import javax.net.ssl.SSLSocket; @@ -47,6 +43,9 @@ import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.junit.jupiter.api.Test; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; + public class JDK9ALPNTest { private Server server; @@ -68,7 +67,7 @@ public class JDK9ALPNTest private SslContextFactory newSslContextFactory() { - SslContextFactory sslContextFactory = new SslContextFactory(); + SslContextFactory sslContextFactory = new SslContextFactory.Server(); sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks"); sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"); sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g"); @@ -90,7 +89,7 @@ public class JDK9ALPNTest } }); - SslContextFactory sslContextFactory = new SslContextFactory(true); + SslContextFactory sslContextFactory = new SslContextFactory.Client(true); sslContextFactory.start(); SSLContext sslContext = sslContextFactory.getSslContext(); try (SSLSocket client = (SSLSocket)sslContext.getSocketFactory().createSocket("localhost", connector.getLocalPort())) @@ -100,8 +99,8 @@ public class JDK9ALPNTest client.startHandshake(); OutputStream output = client.getOutputStream(); - output.write(("" + - "GET / HTTP/1.1\r\n" + + output.write(( + "GET / HTTP/1.1\r\n" + "Host: localhost\r\n" + "Connection: close\r\n" + "\r\n" + @@ -132,7 +131,7 @@ public class JDK9ALPNTest } }); - SslContextFactory sslContextFactory = new SslContextFactory(true); + SslContextFactory sslContextFactory = new SslContextFactory.Client(true); sslContextFactory.start(); SSLContext sslContext = sslContextFactory.getSslContext(); try (SSLSocket client = (SSLSocket)sslContext.getSocketFactory().createSocket("localhost", connector.getLocalPort())) @@ -145,8 +144,8 @@ public class JDK9ALPNTest client.startHandshake(); OutputStream output = client.getOutputStream(); - output.write(("" + - "GET / HTTP/1.1\r\n" + + output.write(( + "GET / HTTP/1.1\r\n" + "Host: localhost\r\n" + "Connection: close\r\n" + "\r\n" + @@ -163,6 +162,5 @@ public class JDK9ALPNTest break; } } - } } diff --git a/jetty-alpn/jetty-alpn-java-server/src/test/java/org/eclipse/jetty/alpn/java/server/JDK9HTTP2Server.java b/jetty-alpn/jetty-alpn-java-server/src/test/java/org/eclipse/jetty/alpn/java/server/JDK9HTTP2Server.java index b3fe4b61ede..5ada3b7c3b3 100644 --- a/jetty-alpn/jetty-alpn-java-server/src/test/java/org/eclipse/jetty/alpn/java/server/JDK9HTTP2Server.java +++ b/jetty-alpn/jetty-alpn-java-server/src/test/java/org/eclipse/jetty/alpn/java/server/JDK9HTTP2Server.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -45,7 +45,7 @@ public class JDK9HTTP2Server httpsConfig.setSendServerVersion(true); httpsConfig.addCustomizer(new SecureRequestCustomizer()); - SslContextFactory sslContextFactory = new SslContextFactory(); + SslContextFactory sslContextFactory = new SslContextFactory.Server(); sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks"); sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"); sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g"); diff --git a/jetty-alpn/jetty-alpn-openjdk8-client/pom.xml b/jetty-alpn/jetty-alpn-openjdk8-client/pom.xml index e6ae3c210b1..4bbdb4e0b2f 100644 --- a/jetty-alpn/jetty-alpn-openjdk8-client/pom.xml +++ b/jetty-alpn/jetty-alpn-openjdk8-client/pom.xml @@ -1,12 +1,10 @@ - + org.eclipse.jetty jetty-alpn-parent - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 @@ -53,21 +51,21 @@
- - org.apache.felix - maven-bundle-plugin - true - - - OpenJDK8 Client ALPN - org.eclipse.jetty.alpn;version="${alpn.majorVersion}.${alpn.minorVersion}.${alpn.incrementalVersion}",* - * - osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional - osgi.serviceloader; osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Client - <_nouses>true - - - + + org.apache.felix + maven-bundle-plugin + true + + + OpenJDK8 Client ALPN + org.eclipse.jetty.alpn;version="${alpn.majorVersion}.${alpn.minorVersion}.${alpn.incrementalVersion}",* + * + osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional + osgi.serviceloader; osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Client + <_nouses>true + + +
diff --git a/jetty-alpn/jetty-alpn-openjdk8-client/src/main/java/org/eclipse/jetty/alpn/java/client/OpenJDK8ClientALPNProcessor.java b/jetty-alpn/jetty-alpn-openjdk8-client/src/main/java/org/eclipse/jetty/alpn/java/client/OpenJDK8ClientALPNProcessor.java index fd1d4f10db3..941f5539da8 100644 --- a/jetty-alpn/jetty-alpn-openjdk8-client/src/main/java/org/eclipse/jetty/alpn/java/client/OpenJDK8ClientALPNProcessor.java +++ b/jetty-alpn/jetty-alpn-openjdk8-client/src/main/java/org/eclipse/jetty/alpn/java/client/OpenJDK8ClientALPNProcessor.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,7 +19,6 @@ package org.eclipse.jetty.alpn.java.client; import java.util.List; - import javax.net.ssl.SSLEngine; import org.eclipse.jetty.alpn.ALPN; @@ -37,9 +36,9 @@ public class OpenJDK8ClientALPNProcessor implements ALPNProcessor.Client @Override public void init() { - if (JavaVersion.VERSION.getPlatform()!=8) - throw new IllegalStateException(this + " not applicable for java "+JavaVersion.VERSION); - if (ALPN.class.getClassLoader()!=null) + if (JavaVersion.VERSION.getPlatform() != 8) + throw new IllegalStateException(this + " not applicable for java " + JavaVersion.VERSION); + if (ALPN.class.getClassLoader() != null) throw new IllegalStateException(ALPN.class.getName() + " must be on JVM boot classpath"); if (LOG.isDebugEnabled()) ALPN.debug = true; diff --git a/jetty-alpn/jetty-alpn-openjdk8-client/src/test/java/org/eclipse/jetty/alpn/java/client/OpenJDK8HTTP2Client.java b/jetty-alpn/jetty-alpn-openjdk8-client/src/test/java/org/eclipse/jetty/alpn/java/client/OpenJDK8HTTP2Client.java index bdbacdbfc56..0b2f01d13bf 100644 --- a/jetty-alpn/jetty-alpn-openjdk8-client/src/test/java/org/eclipse/jetty/alpn/java/client/OpenJDK8HTTP2Client.java +++ b/jetty-alpn/jetty-alpn-openjdk8-client/src/test/java/org/eclipse/jetty/alpn/java/client/OpenJDK8HTTP2Client.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -42,7 +42,7 @@ public class OpenJDK8HTTP2Client public static void main(String[] args) throws Exception { HTTP2Client client = new HTTP2Client(); - SslContextFactory sslContextFactory = new SslContextFactory(); + SslContextFactory sslContextFactory = new SslContextFactory.Client(); client.addBean(sslContextFactory); client.start(); diff --git a/jetty-alpn/jetty-alpn-openjdk8-server/pom.xml b/jetty-alpn/jetty-alpn-openjdk8-server/pom.xml index 934dce46afd..f096d85e465 100644 --- a/jetty-alpn/jetty-alpn-openjdk8-server/pom.xml +++ b/jetty-alpn/jetty-alpn-openjdk8-server/pom.xml @@ -1,10 +1,9 @@ - + org.eclipse.jetty jetty-alpn-parent - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 @@ -58,21 +57,21 @@
- - org.apache.felix - maven-bundle-plugin - true - - - OpenJDK8 Server ALPN - * - org.eclipse.jetty.alpn;version="${alpn.majorVersion}.${alpn.minorVersion}.${alpn.incrementalVersion}",* - osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional - osgi.serviceloader; osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Server - <_nouses>true - - - + + org.apache.felix + maven-bundle-plugin + true + + + OpenJDK8 Server ALPN + * + org.eclipse.jetty.alpn;version="${alpn.majorVersion}.${alpn.minorVersion}.${alpn.incrementalVersion}",* + osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional + osgi.serviceloader; osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Server + <_nouses>true + + +
diff --git a/jetty-alpn/jetty-alpn-openjdk8-server/src/main/java/org/eclipse/jetty/alpn/openjdk8/server/OpenJDK8ServerALPNProcessor.java b/jetty-alpn/jetty-alpn-openjdk8-server/src/main/java/org/eclipse/jetty/alpn/openjdk8/server/OpenJDK8ServerALPNProcessor.java index 91058abc384..2984c51d195 100644 --- a/jetty-alpn/jetty-alpn-openjdk8-server/src/main/java/org/eclipse/jetty/alpn/openjdk8/server/OpenJDK8ServerALPNProcessor.java +++ b/jetty-alpn/jetty-alpn-openjdk8-server/src/main/java/org/eclipse/jetty/alpn/openjdk8/server/OpenJDK8ServerALPNProcessor.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,7 +20,6 @@ package org.eclipse.jetty.alpn.openjdk8.server; import java.util.Collections; import java.util.List; - import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLException; @@ -35,13 +34,13 @@ import org.eclipse.jetty.util.log.Logger; public class OpenJDK8ServerALPNProcessor implements ALPNProcessor.Server { private static final Logger LOG = Log.getLogger(OpenJDK8ServerALPNProcessor.class); - + @Override public void init() { - if (JavaVersion.VERSION.getPlatform()!=8) - throw new IllegalStateException(this + " not applicable for java "+JavaVersion.VERSION); - if (ALPN.class.getClassLoader()!=null) + if (JavaVersion.VERSION.getPlatform() != 8) + throw new IllegalStateException(this + " not applicable for java " + JavaVersion.VERSION); + if (ALPN.class.getClassLoader() != null) throw new IllegalStateException(ALPN.class.getName() + " must be on JVM boot classpath"); if (LOG.isDebugEnabled()) ALPN.debug = true; @@ -83,7 +82,7 @@ public class OpenJDK8ServerALPNProcessor implements ALPNProcessor.Server LOG.debug("onClosed {}", alpnConnection); ALPN.remove(alpnConnection.getSSLEngine()); } - + @Override public void unsupported() { diff --git a/jetty-alpn/jetty-alpn-openjdk8-server/src/test/java/org/eclipse/jetty/alpn/openjdk8/server/OpenJDK8HTTP2Server.java b/jetty-alpn/jetty-alpn-openjdk8-server/src/test/java/org/eclipse/jetty/alpn/openjdk8/server/OpenJDK8HTTP2Server.java index 714cdc1dcf4..4cb95fbdaf8 100644 --- a/jetty-alpn/jetty-alpn-openjdk8-server/src/test/java/org/eclipse/jetty/alpn/openjdk8/server/OpenJDK8HTTP2Server.java +++ b/jetty-alpn/jetty-alpn-openjdk8-server/src/test/java/org/eclipse/jetty/alpn/openjdk8/server/OpenJDK8HTTP2Server.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -45,7 +45,7 @@ public class OpenJDK8HTTP2Server httpsConfig.setSendServerVersion(true); httpsConfig.addCustomizer(new SecureRequestCustomizer()); - SslContextFactory sslContextFactory = new SslContextFactory(); + SslContextFactory sslContextFactory = new SslContextFactory.Server(); sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks"); sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"); sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g"); diff --git a/jetty-alpn/jetty-alpn-server/pom.xml b/jetty-alpn/jetty-alpn-server/pom.xml index 2080647cf95..fd5c1983bfa 100644 --- a/jetty-alpn/jetty-alpn-server/pom.xml +++ b/jetty-alpn/jetty-alpn-server/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-alpn-parent - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 jetty-alpn-server @@ -15,8 +15,8 @@ - org.apache.maven.plugins - maven-source-plugin + org.apache.maven.plugins + maven-source-plugin org.codehaus.mojo @@ -45,12 +45,12 @@ org.apache.felix maven-bundle-plugin - - ${bundle-symbolic-name};singleton:=true - org.eclipse.jetty.alpn.server,* - org.eclipse.jetty.alpn;version="${alpn.majorVersion}.${alpn.minorVersion}.${alpn.incrementalVersion}",* - osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)";resolution:=optional, osgi.serviceloader; filter:="(osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Server)";resolution:=optional;cardinality:=multiple - + + ${bundle-symbolic-name};singleton:=true + org.eclipse.jetty.alpn.server,* + org.eclipse.jetty.alpn;version="${alpn.majorVersion}.${alpn.minorVersion}.${alpn.incrementalVersion}",* + osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)";resolution:=optional, osgi.serviceloader; filter:="(osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Server)";resolution:=optional;cardinality:=multiple + diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/etc/jetty-alpn.xml b/jetty-alpn/jetty-alpn-server/src/main/config/etc/jetty-alpn.xml index 01bc39b28cd..899c54f0228 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/etc/jetty-alpn.xml +++ b/jetty-alpn/jetty-alpn-server/src/main/config/etc/jetty-alpn.xml @@ -1,5 +1,4 @@ - - + diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_191.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_191.mod new file mode 100644 index 00000000000..ed8a55508d6 --- /dev/null +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_191.mod @@ -0,0 +1,7 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + +[files] +maven://org.mortbay.jetty.alpn/alpn-boot/8.1.13.v20181017|lib/alpn/alpn-boot-8.1.13.v20181017.jar + +[exec] +-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.13.v20181017.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_192.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_192.mod new file mode 100644 index 00000000000..ed8a55508d6 --- /dev/null +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_192.mod @@ -0,0 +1,7 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + +[files] +maven://org.mortbay.jetty.alpn/alpn-boot/8.1.13.v20181017|lib/alpn/alpn-boot-8.1.13.v20181017.jar + +[exec] +-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.13.v20181017.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_201.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_201.mod new file mode 100644 index 00000000000..ed8a55508d6 --- /dev/null +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_201.mod @@ -0,0 +1,7 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + +[files] +maven://org.mortbay.jetty.alpn/alpn-boot/8.1.13.v20181017|lib/alpn/alpn-boot-8.1.13.v20181017.jar + +[exec] +-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.13.v20181017.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_202.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_202.mod new file mode 100644 index 00000000000..ed8a55508d6 --- /dev/null +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_202.mod @@ -0,0 +1,7 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + +[files] +maven://org.mortbay.jetty.alpn/alpn-boot/8.1.13.v20181017|lib/alpn/alpn-boot-8.1.13.v20181017.jar + +[exec] +-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.13.v20181017.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_211.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_211.mod new file mode 100644 index 00000000000..ed8a55508d6 --- /dev/null +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_211.mod @@ -0,0 +1,7 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + +[files] +maven://org.mortbay.jetty.alpn/alpn-boot/8.1.13.v20181017|lib/alpn/alpn-boot-8.1.13.v20181017.jar + +[exec] +-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.13.v20181017.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_212.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_212.mod new file mode 100644 index 00000000000..ed8a55508d6 --- /dev/null +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_212.mod @@ -0,0 +1,7 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + +[files] +maven://org.mortbay.jetty.alpn/alpn-boot/8.1.13.v20181017|lib/alpn/alpn-boot-8.1.13.v20181017.jar + +[exec] +-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.13.v20181017.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_221.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_221.mod new file mode 100644 index 00000000000..ed8a55508d6 --- /dev/null +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_221.mod @@ -0,0 +1,7 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + +[files] +maven://org.mortbay.jetty.alpn/alpn-boot/8.1.13.v20181017|lib/alpn/alpn-boot-8.1.13.v20181017.jar + +[exec] +-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.13.v20181017.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_222.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_222.mod new file mode 100644 index 00000000000..ed8a55508d6 --- /dev/null +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_222.mod @@ -0,0 +1,7 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + +[files] +maven://org.mortbay.jetty.alpn/alpn-boot/8.1.13.v20181017|lib/alpn/alpn-boot-8.1.13.v20181017.jar + +[exec] +-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.13.v20181017.jar diff --git a/jetty-cdi/cdi-servlet/src/main/config/modules/cdi.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-13.mod similarity index 65% rename from jetty-cdi/cdi-servlet/src/main/config/modules/cdi.mod rename to jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-13.mod index 26262df8dd4..689601a4197 100644 --- a/jetty-cdi/cdi-servlet/src/main/config/modules/cdi.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-13.mod @@ -1,7 +1,4 @@ DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html -[description] -Experimental CDI/Weld integration - [depend] -cdi1 +alpn-impl/alpn-9 diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-14.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-14.mod new file mode 100644 index 00000000000..689601a4197 --- /dev/null +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-14.mod @@ -0,0 +1,4 @@ +DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + +[depend] +alpn-impl/alpn-9 diff --git a/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnection.java b/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnection.java index fcd3a1c6bdb..bdc448be261 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnection.java +++ b/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnection.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,7 +20,6 @@ package org.eclipse.jetty.alpn.server; import java.util.Collections; import java.util.List; - import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLSession; @@ -44,7 +43,7 @@ public class ALPNServerConnection extends NegotiatingServerConnection { select(Collections.emptyList()); } - + public void select(List clientProtocols) { SSLEngine sslEngine = getSSLEngine(); diff --git a/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java b/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java index 8c95d5db0cc..452431863e2 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java +++ b/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -23,7 +23,6 @@ import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.ServiceLoader; - import javax.net.ssl.SSLEngine; import org.eclipse.jetty.io.AbstractConnection; @@ -45,21 +44,21 @@ public class ALPNServerConnectionFactory extends NegotiatingServerConnectionFact { this(protocols.trim().split(",", 0)); } - + public ALPNServerConnectionFactory(@Name("protocols") String... protocols) { super("alpn", protocols); IllegalStateException failure = new IllegalStateException("No Server ALPNProcessors!"); // Use a for loop on iterator so load exceptions can be caught and ignored - for (Iterator i = ServiceLoader.load(Server.class).iterator(); i.hasNext();) + for (Iterator i = ServiceLoader.load(Server.class).iterator(); i.hasNext(); ) { Server processor; try { processor = i.next(); } - catch(Throwable x) + catch (Throwable x) { if (LOG.isDebugEnabled()) LOG.debug(x); @@ -81,7 +80,7 @@ public class ALPNServerConnectionFactory extends NegotiatingServerConnectionFact failure.addSuppressed(x); } } - + if (LOG.isDebugEnabled()) { LOG.debug("protocols: {}", Arrays.asList(protocols)); @@ -106,9 +105,9 @@ public class ALPNServerConnectionFactory extends NegotiatingServerConnectionFact return connection; } } - + if (LOG.isDebugEnabled()) - LOG.debug("No ALPNProcessor: {} {}",engine,endPoint); + LOG.debug("No ALPNProcessor: {} {}", engine, endPoint); throw new IllegalStateException("Connection rejected: No ALPN Processor for " + engine.getClass().getName() + " from " + processors); } } diff --git a/jetty-alpn/pom.xml b/jetty-alpn/pom.xml index 9d36b6fb05b..b20c9e58dc4 100644 --- a/jetty-alpn/pom.xml +++ b/jetty-alpn/pom.xml @@ -1,10 +1,8 @@ - + org.eclipse.jetty jetty-project - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 jetty-alpn-parent diff --git a/jetty-annotations/pom.xml b/jetty-annotations/pom.xml index 52080ae0f58..81627b04732 100644 --- a/jetty-annotations/pom.xml +++ b/jetty-annotations/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 jetty-annotations @@ -18,12 +18,12 @@ org.apache.felix maven-bundle-plugin true - - - org.objectweb.asm;version="[5.0,7)",* - osgi.serviceloader; filter:="(osgi.serviceloader=javax.servlet.ServletContainerInitializer)";resolution:=optional;cardinality:=multiple, osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)";resolution:=optional - - + + + org.objectweb.asm;version="5",* + osgi.serviceloader; filter:="(osgi.serviceloader=javax.servlet.ServletContainerInitializer)";resolution:=optional;cardinality:=multiple, osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)";resolution:=optional + + org.codehaus.mojo diff --git a/jetty-annotations/src/main/config/etc/jetty-annotations.xml b/jetty-annotations/src/main/config/etc/jetty-annotations.xml index 3eb3f6ba275..3265df2f532 100644 --- a/jetty-annotations/src/main/config/etc/jetty-annotations.xml +++ b/jetty-annotations/src/main/config/etc/jetty-annotations.xml @@ -1,5 +1,4 @@ - - + diff --git a/jetty-annotations/src/main/config/modules/annotations.mod b/jetty-annotations/src/main/config/modules/annotations.mod index ca8c3bad139..5c58290955c 100644 --- a/jetty-annotations/src/main/config/modules/annotations.mod +++ b/jetty-annotations/src/main/config/modules/annotations.mod @@ -13,3 +13,6 @@ lib/annotations/*.jar [xml] # Enable annotation scanning webapp configurations etc/jetty-annotations.xml + +[jpms] +add-modules:org.objectweb.asm diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AbstractDiscoverableAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AbstractDiscoverableAnnotationHandler.java index 07d3afbd140..220f5c8040e 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AbstractDiscoverableAnnotationHandler.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AbstractDiscoverableAnnotationHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -26,22 +26,18 @@ import org.eclipse.jetty.webapp.WebAppContext; * DiscoverableAnnotationHandler * * Base class for handling the discovery of an annotation. - * */ public abstract class AbstractDiscoverableAnnotationHandler extends AbstractHandler { protected WebAppContext _context; - public AbstractDiscoverableAnnotationHandler(WebAppContext context) { _context = context; } - - public void addAnnotation (DiscoveredAnnotation a) + public void addAnnotation(DiscoveredAnnotation a) { _context.getMetaData().addDiscoveredAnnotation(a); } - } diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java index bc2da221fe6..deb4531b1ff 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -39,7 +39,6 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; - import javax.servlet.ServletContainerInitializer; import javax.servlet.annotation.HandlesTypes; @@ -66,23 +65,22 @@ import org.eclipse.jetty.webapp.WebDescriptor; public class AnnotationConfiguration extends AbstractConfiguration { private static final Logger LOG = Log.getLogger(AnnotationConfiguration.class); - + public static final String SERVLET_CONTAINER_INITIALIZER_EXCLUSION_PATTERN = "org.eclipse.jetty.containerInitializerExclusionPattern"; public static final String SERVLET_CONTAINER_INITIALIZER_ORDER = "org.eclipse.jetty.containerInitializerOrder"; - public static final String CLASS_INHERITANCE_MAP = "org.eclipse.jetty.classInheritanceMap"; + public static final String CLASS_INHERITANCE_MAP = "org.eclipse.jetty.classInheritanceMap"; public static final String CONTAINER_INITIALIZERS = "org.eclipse.jetty.containerInitializers"; public static final String CONTAINER_INITIALIZER_STARTER = "org.eclipse.jetty.containerInitializerStarter"; public static final String MULTI_THREADED = "org.eclipse.jetty.annotations.multiThreaded"; public static final String MAX_SCAN_WAIT = "org.eclipse.jetty.annotations.maxWait"; - - - public static final int DEFAULT_MAX_SCAN_WAIT = 60; /* time in sec */ + + public static final int DEFAULT_MAX_SCAN_WAIT = 60; /* time in sec */ public static final boolean DEFAULT_MULTI_THREADED = true; - - protected List _discoverableAnnotationHandlers = new ArrayList(); + + protected final List _discoverableAnnotationHandlers = new ArrayList<>(); protected ClassInheritanceHandler _classInheritanceHandler; - protected List _containerInitializerAnnotationHandlers = new ArrayList(); - + protected final List _containerInitializerAnnotationHandlers = new ArrayList<>(); + protected List _parserTasks; protected CounterStatistic _containerPathStats; @@ -90,49 +88,47 @@ public class AnnotationConfiguration extends AbstractConfiguration protected CounterStatistic _webInfClassesStats; protected Pattern _sciExcludePattern; protected ServiceLoader _loadedInitializers = null; + /** * TimeStatistic * * Simple class to capture elapsed time of an operation. - * */ - public class TimeStatistic + public class TimeStatistic { public long _start = 0; public long _end = 0; - - public void start () + + public void start() { _start = System.nanoTime(); } - - public void end () + + public void end() { _end = System.nanoTime(); } - + public long getStart() { return _start; } - - public long getEnd () + + public long getEnd() { return _end; } - - public long getElapsed () + + public long getElapsed() { - return (_end > _start?(_end-_start):0); + return (_end > _start ? (_end - _start) : 0); } } - - + /** * ParserTask * * Task to executing scanning of a resource for annotations. - * */ public class ParserTask implements Callable { @@ -141,80 +137,79 @@ public class AnnotationConfiguration extends AbstractConfiguration protected final Set _handlers; protected final Resource _resource; protected TimeStatistic _stat; - - public ParserTask (AnnotationParser parser, Sethandlers, Resource resource) + + public ParserTask(AnnotationParser parser, Set handlers, Resource resource) { _parser = parser; _handlers = handlers; _resource = resource; } - + public void setStatistic(TimeStatistic stat) { - _stat = stat; + _stat = stat; } @Override public Void call() throws Exception - { + { if (_stat != null) _stat.start(); if (_parser != null) - _parser.parse(_handlers, _resource); + _parser.parse(_handlers, _resource); if (_stat != null) _stat.end(); return null; } - + public TimeStatistic getStatistic() { return _stat; } - + public Resource getResource() { return _resource; - } + } } - - + /** * ServletContainerInitializerOrdering - * - * A list of classnames of ServletContainerInitializers in the order in which - * they are to be called back. One name only in the list can be "*", which is a + *

Applies an ordering to the {@link ServletContainerInitializer}s for the context, using + * the value of the "org.eclipse.jetty.containerInitializerOrder" context attribute. + * The attribute value is a list of classnames of ServletContainerInitializers in the order in which + * they are to be called. One name only in the list can be "*", which is a * wildcard which matches any other ServletContainerInitializer name not already - * matched. + * matched.

*/ - public class ServletContainerInitializerOrdering + public class ServletContainerInitializerOrdering { private Map _indexMap = new HashMap(); private Integer _star = null; private String _ordering = null; - - public ServletContainerInitializerOrdering (String ordering) + + public ServletContainerInitializerOrdering(String ordering) { if (ordering != null) { _ordering = ordering; - + String[] tmp = StringUtil.csvSplit(ordering); - - for (int i=0; i { private ServletContainerInitializerOrdering _ordering; - - - public ServletContainerInitializerComparator (ServletContainerInitializerOrdering ordering) + + public ServletContainerInitializerComparator(ServletContainerInitializerOrdering ordering) { _ordering = ordering; } @@ -295,107 +290,90 @@ public class AnnotationConfiguration extends AbstractConfiguration @Override public int compare(ServletContainerInitializer sci1, ServletContainerInitializer sci2) { - String c1 = (sci1 != null? sci1.getClass().getName() : null); - String c2 = (sci2 != null? sci2.getClass().getName() : null); + String c1 = (sci1 != null ? sci1.getClass().getName() : null); + String c2 = (sci2 != null ? sci2.getClass().getName() : null); if (c1 == null && c2 == null) return 0; - + int i1 = _ordering.getIndexOf(c1); if (i1 < 0 && _ordering.hasWildcard()) i1 = _ordering.getWildcardIndex(); int i2 = _ordering.getIndexOf(c2); if (i2 < 0 && _ordering.hasWildcard()) i2 = _ordering.getWildcardIndex(); - + return Integer.compare(i1, i2); } } - + @Override public void preConfigure(final WebAppContext context) throws Exception { String tmp = (String)context.getAttribute(SERVLET_CONTAINER_INITIALIZER_EXCLUSION_PATTERN); - _sciExcludePattern = (tmp==null?null:Pattern.compile(tmp)); + _sciExcludePattern = (tmp == null ? null : Pattern.compile(tmp)); } - public void addDiscoverableAnnotationHandler(AbstractDiscoverableAnnotationHandler handler) { _discoverableAnnotationHandlers.add(handler); } - @Override - public void deconfigure(WebAppContext context) throws Exception - { - context.removeAttribute(CLASS_INHERITANCE_MAP); - context.removeAttribute(CONTAINER_INITIALIZERS); - ServletContainerInitializersStarter starter = (ServletContainerInitializersStarter)context.getAttribute(CONTAINER_INITIALIZER_STARTER); - if (starter != null) - { - context.removeBean(starter); - context.removeAttribute(CONTAINER_INITIALIZER_STARTER); - } - - if (_loadedInitializers != null) - _loadedInitializers.reload(); - } - - /** + /** * @see org.eclipse.jetty.webapp.AbstractConfiguration#configure(org.eclipse.jetty.webapp.WebAppContext) */ @Override public void configure(WebAppContext context) throws Exception { - context.getObjectFactory().addDecorator(new AnnotationDecorator(context)); + context.getObjectFactory().addDecorator(new AnnotationDecorator(context)); - if (!context.getMetaData().isMetaDataComplete()) - { - //If metadata isn't complete, if this is a servlet 3 webapp or isConfigDiscovered is true, we need to search for annotations - if (context.getServletContext().getEffectiveMajorVersion() >= 3 || context.isConfigurationDiscovered()) - { - _discoverableAnnotationHandlers.add(new WebServletAnnotationHandler(context)); - _discoverableAnnotationHandlers.add(new WebFilterAnnotationHandler(context)); - _discoverableAnnotationHandlers.add(new WebListenerAnnotationHandler(context)); - } - } + if (!context.getMetaData().isMetaDataComplete()) + { + //If metadata isn't complete, if this is a servlet 3 webapp or isConfigDiscovered is true, we need to search for annotations + if (context.getServletContext().getEffectiveMajorVersion() >= 3 || context.isConfigurationDiscovered()) + { + _discoverableAnnotationHandlers.add(new WebServletAnnotationHandler(context)); + _discoverableAnnotationHandlers.add(new WebFilterAnnotationHandler(context)); + _discoverableAnnotationHandlers.add(new WebListenerAnnotationHandler(context)); + } + } - //Regardless of metadata, if there are any ServletContainerInitializers with @HandlesTypes, then we need to scan all the - //classes so we can call their onStartup() methods correctly - createServletContainerInitializerAnnotationHandlers(context, getNonExcludedInitializers(context)); + //Regardless of metadata, if there are any ServletContainerInitializers with @HandlesTypes, then we need to scan all the + //classes so we can call their onStartup() methods correctly + createServletContainerInitializerAnnotationHandlers(context, getNonExcludedInitializers(context)); - if (!_discoverableAnnotationHandlers.isEmpty() || _classInheritanceHandler != null || !_containerInitializerAnnotationHandlers.isEmpty()) - scanForAnnotations(context); + if (!_discoverableAnnotationHandlers.isEmpty() || _classInheritanceHandler != null || !_containerInitializerAnnotationHandlers.isEmpty()) + scanForAnnotations(context); - // Resolve container initializers - List initializers = - (List)context.getAttribute(AnnotationConfiguration.CONTAINER_INITIALIZERS); - if (initializers != null && initializers.size()>0) - { - Map> map = ( Map>) context.getAttribute(AnnotationConfiguration.CLASS_INHERITANCE_MAP); - for (ContainerInitializer i : initializers) - i.resolveClasses(context,map); - } + // Resolve container initializers + List initializers = + (List)context.getAttribute(AnnotationConfiguration.CONTAINER_INITIALIZERS); + if (initializers != null && initializers.size() > 0) + { + Map> map = (Map>)context.getAttribute(AnnotationConfiguration.CLASS_INHERITANCE_MAP); + for (ContainerInitializer i : initializers) + { + i.resolveClasses(context, map); + } + } } - - /** + /** * @see org.eclipse.jetty.webapp.AbstractConfiguration#postConfigure(org.eclipse.jetty.webapp.WebAppContext) */ @Override public void postConfigure(WebAppContext context) throws Exception { Map> classMap = (ClassInheritanceMap)context.getAttribute(CLASS_INHERITANCE_MAP); - List initializers = (List)context.getAttribute(CONTAINER_INITIALIZERS); - - context.removeAttribute(CLASS_INHERITANCE_MAP); if (classMap != null) classMap.clear(); - - context.removeAttribute(CONTAINER_INITIALIZERS); + context.removeAttribute(CLASS_INHERITANCE_MAP); + + List initializers = (List)context.getAttribute(CONTAINER_INITIALIZERS); if (initializers != null) initializers.clear(); - + context.removeAttribute(CONTAINER_INITIALIZERS); + if (_discoverableAnnotationHandlers != null) _discoverableAnnotationHandlers.clear(); @@ -408,40 +386,46 @@ public class AnnotationConfiguration extends AbstractConfiguration _parserTasks.clear(); _parserTasks = null; } - + + ServletContainerInitializersStarter starter = (ServletContainerInitializersStarter)context.getAttribute(CONTAINER_INITIALIZER_STARTER); + if (starter != null) + { + context.removeBean(starter); + context.removeAttribute(CONTAINER_INITIALIZER_STARTER); + } + + if (_loadedInitializers != null) + _loadedInitializers.reload(); + super.postConfigure(context); } - - - + /** * Perform scanning of classes for annotations - * + * * @param context the context for the scan * @throws Exception if unable to scan */ - protected void scanForAnnotations (WebAppContext context) - throws Exception + protected void scanForAnnotations(WebAppContext context) + throws Exception { int javaPlatform = 0; Object target = context.getAttribute(JavaVersion.JAVA_TARGET_PLATFORM); - if (target!=null) + if (target != null) javaPlatform = Integer.parseInt(target.toString()); AnnotationParser parser = createAnnotationParser(javaPlatform); _parserTasks = new ArrayList(); - long start = 0; - + long start = 0; if (LOG.isDebugEnabled()) - LOG.debug("Annotation scanning commencing: webxml={}, metadatacomplete={}, configurationDiscovered={}, multiThreaded={}, maxScanWait={}", - context.getServletContext().getEffectiveMajorVersion(), - context.getMetaData().isMetaDataComplete(), - context.isConfigurationDiscovered(), - isUseMultiThreading(context), - getMaxScanWait(context)); + LOG.debug("Annotation scanning commencing: webxml={}, metadatacomplete={}, configurationDiscovered={}, multiThreaded={}, maxScanWait={}", + context.getServletContext().getEffectiveMajorVersion(), + context.getMetaData().isMetaDataComplete(), + context.isConfigurationDiscovered(), + isUseMultiThreading(context), + getMaxScanWait(context)); - parseContainerPath(context, parser); //email from Rajiv Mordani jsrs 315 7 April 2010 // If there is a then the ordering should be @@ -449,16 +433,16 @@ public class AnnotationConfiguration extends AbstractConfiguration // In case there is no others then it is // WEB-INF/classes + order of the elements. parseWebInfClasses(context, parser); - parseWebInfLib (context, parser); - + parseWebInfLib(context, parser); + start = System.nanoTime(); - + //execute scan, either effectively synchronously (1 thread only), or asynchronously (limited by number of processors available) - final Semaphore task_limit = (isUseMultiThreading(context)? new Semaphore(ProcessorUtils.availableProcessors()):new Semaphore( 1)); + final Semaphore task_limit = (isUseMultiThreading(context) ? new Semaphore(ProcessorUtils.availableProcessors()) : new Semaphore(1)); final CountDownLatch latch = new CountDownLatch(_parserTasks.size()); final MultiException me = new MultiException(); - - for (final ParserTask p:_parserTasks) + + for (final ParserTask p : _parserTasks) { task_limit.acquire(); context.getServer().getThreadPool().execute(new Runnable() @@ -466,48 +450,48 @@ public class AnnotationConfiguration extends AbstractConfiguration @Override public void run() { - try - { - p.call(); - } - catch (Exception e) - { - me.add(e); - } - finally - { - task_limit.release(); - latch.countDown(); - } - } + try + { + p.call(); + } + catch (Exception e) + { + me.add(e); + } + finally + { + task_limit.release(); + latch.countDown(); + } + } }); } - + boolean timeout = !latch.await(getMaxScanWait(context), TimeUnit.SECONDS); - long elapsedMs = TimeUnit.MILLISECONDS.convert(System.nanoTime()-start, TimeUnit.NANOSECONDS); - - LOG.info("Scanning elapsed time={}ms",elapsedMs); - + long elapsedMs = TimeUnit.MILLISECONDS.convert(System.nanoTime() - start, TimeUnit.NANOSECONDS); + + LOG.info("Scanning elapsed time={}ms", elapsedMs); + if (LOG.isDebugEnabled()) { - for (ParserTask p:_parserTasks) + for (ParserTask p : _parserTasks) + { LOG.debug("Scanned {} in {}ms", p.getResource(), TimeUnit.MILLISECONDS.convert(p.getStatistic().getElapsed(), TimeUnit.NANOSECONDS)); + } LOG.debug("Scanned {} container path jars, {} WEB-INF/lib jars, {} WEB-INF/classes dirs in {}ms for context {}", - (_containerPathStats==null?-1:_containerPathStats.getTotal()), - (_webInfLibStats==null?-1:_webInfLibStats.getTotal()), - (_webInfClassesStats==null?-1:_webInfClassesStats.getTotal()), - elapsedMs, - context); + (_containerPathStats == null ? -1 : _containerPathStats.getTotal()), + (_webInfLibStats == null ? -1 : _webInfLibStats.getTotal()), + (_webInfClassesStats == null ? -1 : _webInfClassesStats.getTotal()), + elapsedMs, + context); } if (timeout) me.add(new Exception("Timeout scanning annotations")); - me.ifExceptionThrow(); + me.ifExceptionThrow(); } - - /** * @param javaPlatform The java platform to scan for. * @return a new AnnotationParser. This method can be overridden to use a different implementation of @@ -517,9 +501,10 @@ public class AnnotationConfiguration extends AbstractConfiguration { return new AnnotationParser(javaPlatform); } - + /** * Check if we should use multiple threads to scan for annotations or not + * * @param context the context of the multi threaded setting * @return true if multi threading is enabled on the context, server, or via a System property. * @see #MULTI_THREADED @@ -542,16 +527,14 @@ public class AnnotationConfiguration extends AbstractConfiguration return Boolean.parseBoolean(System.getProperty(MULTI_THREADED, Boolean.toString(DEFAULT_MULTI_THREADED))); } - - /** * Work out how long we should wait for the async scanning to occur. - * + * * @param context the context of the max scan wait setting * @return the max scan wait setting on the context, or server, or via a System property. * @see #MAX_SCAN_WAIT */ - protected int getMaxScanWait (WebAppContext context) + protected int getMaxScanWait(WebAppContext context) { //try context attribute to get max time in sec to wait for scan completion Object o = context.getAttribute(MAX_SCAN_WAIT); @@ -568,8 +551,8 @@ public class AnnotationConfiguration extends AbstractConfiguration //try system property to get max time in sec to wait for scan completion return Integer.getInteger(MAX_SCAN_WAIT, DEFAULT_MAX_SCAN_WAIT).intValue(); } - - /** + + /** * @see org.eclipse.jetty.webapp.AbstractConfiguration#cloneConfigure(org.eclipse.jetty.webapp.WebAppContext, org.eclipse.jetty.webapp.WebAppContext) */ @Override @@ -578,8 +561,7 @@ public class AnnotationConfiguration extends AbstractConfiguration context.getObjectFactory().addDecorator(new AnnotationDecorator(context)); } - public void createServletContainerInitializerAnnotationHandlers (WebAppContext context, List scis) - throws Exception + public void createServletContainerInitializerAnnotationHandlers(WebAppContext context, List scis) { if (scis == null || scis.isEmpty()) return; // nothing to do @@ -592,14 +574,17 @@ public class AnnotationConfiguration extends AbstractConfiguration HandlesTypes annotation = service.getClass().getAnnotation(HandlesTypes.class); ContainerInitializer initializer = null; if (annotation != null) - { + { //There is a HandlesTypes annotation on the on the ServletContainerInitializer Class[] classes = annotation.value(); if (classes != null) { - if (LOG.isDebugEnabled()){LOG.debug("HandlesTypes {} on initializer {}",Arrays.asList(classes),service.getClass());} - + if (LOG.isDebugEnabled()) + { + LOG.debug("HandlesTypes {} on initializer {}", Arrays.asList(classes), service.getClass()); + } + initializer = new ContainerInitializer(service, classes); //If we haven't already done so, we need to register a handler that will @@ -612,33 +597,35 @@ public class AnnotationConfiguration extends AbstractConfiguration _classInheritanceHandler = new ClassInheritanceHandler(map); } - for (Class c: classes) + for (Class c : classes) { //The value of one of the HandlesTypes classes is actually an Annotation itself so //register a handler for it if (c.isAnnotation()) { - if (LOG.isDebugEnabled()) LOG.debug("Registering annotation handler for "+c.getName()); - _containerInitializerAnnotationHandlers.add(new ContainerInitializerAnnotationHandler(initializer, c)); + if (LOG.isDebugEnabled()) + LOG.debug("Registering annotation handler for " + c.getName()); + _containerInitializerAnnotationHandlers.add(new ContainerInitializerAnnotationHandler(initializer, c)); } } } else { initializer = new ContainerInitializer(service, null); - if (LOG.isDebugEnabled()) LOG.debug("No classes in HandlesTypes on initializer "+service.getClass()); + if (LOG.isDebugEnabled()) + LOG.debug("No classes in HandlesTypes on initializer " + service.getClass()); } } else { initializer = new ContainerInitializer(service, null); - if (LOG.isDebugEnabled()) LOG.debug("No HandlesTypes annotation on initializer "+service.getClass()); + if (LOG.isDebugEnabled()) + LOG.debug("No HandlesTypes annotation on initializer " + service.getClass()); } - + initializers.add(initializer); } - - + //add a bean to the context which will call the servletcontainerinitializers when appropriate ServletContainerInitializersStarter starter = (ServletContainerInitializersStarter)context.getAttribute(CONTAINER_INITIALIZER_STARTER); if (starter != null) @@ -648,69 +635,75 @@ public class AnnotationConfiguration extends AbstractConfiguration context.addBean(starter, true); } - public Resource getJarFor (ServletContainerInitializer service) - throws MalformedURLException, IOException + public Resource getJarFor(ServletContainerInitializer service) + throws IOException { URI uri = TypeUtil.getLocationOfClass(service.getClass()); if (uri == null) return null; return Resource.newResource(uri); } - + /** * Check to see if the ServletContainerIntializer loaded via the ServiceLoader came * from a jar that is excluded by the fragment ordering. See ServletSpec 3.0 p.85. - * + * * @param context the context for the jars * @param sci the servlet container initializer - * @param sciResource the resource for the servlet container initializer + * @param sciResource the resource for the servlet container initializer * @return true if excluded - * @throws Exception if unable to determine exclusion */ - public boolean isFromExcludedJar (WebAppContext context, ServletContainerInitializer sci, Resource sciResource) - throws Exception + public boolean isFromExcludedJar(WebAppContext context, ServletContainerInitializer sci, Resource sciResource) { if (sci == null) throw new IllegalArgumentException("ServletContainerInitializer null"); if (context == null) throw new IllegalArgumentException("WebAppContext null"); - - + + //if we don't know where its from it can't be excluded + if (sciResource == null) + { + if (LOG.isDebugEnabled()) + LOG.debug("!Excluded {} null resource", sci); + return false; + } + + //A ServletContainerInitialier that came from WEB-INF/classes or equivalent cannot be excluded by an ordering + if (isFromWebInfClasses(context, sciResource)) + { + if (LOG.isDebugEnabled()) + LOG.debug("!Excluded {} from web-inf/classes", sci); + return false; + } + //A ServletContainerInitializer that came from the container's classpath cannot be excluded by an ordering //of WEB-INF/lib jars if (isFromContainerClassPath(context, sci)) { - if (LOG.isDebugEnabled()) + if (LOG.isDebugEnabled()) LOG.debug("!Excluded {} from container classpath", sci); return false; } - + //If no ordering, nothing is excluded if (context.getMetaData().getOrdering() == null) { - if (LOG.isDebugEnabled()) + if (LOG.isDebugEnabled()) LOG.debug("!Excluded {} no ordering", sci); return false; } - + List orderedJars = context.getMetaData().getOrderedWebInfJars(); //there is an ordering, but there are no jars resulting from the ordering, everything excluded if (orderedJars.isEmpty()) { - if (LOG.isDebugEnabled()) + if (LOG.isDebugEnabled()) LOG.debug("Excluded {} empty ordering", sci); return true; } - if (sciResource == null) - { - //not from a jar therefore not from WEB-INF so not excludable - if (LOG.isDebugEnabled()) - LOG.debug("!Excluded {} not from jar", sci); - return false; - } - + //Check if it is excluded by an ordering URI loadingJarURI = sciResource.getURI(); boolean found = false; Iterator itor = orderedJars.iterator(); @@ -720,15 +713,15 @@ public class AnnotationConfiguration extends AbstractConfiguration found = r.getURI().equals(loadingJarURI); } - if (LOG.isDebugEnabled()) - LOG.debug("{}Excluded {} found={}",found?"!":"",sci,found); + if (LOG.isDebugEnabled()) + LOG.debug("{}Excluded {} found={}", found ? "!" : "", sci, found); return !found; } /** - * Test if the ServletContainerIntializer is excluded by the + * Test if the ServletContainerIntializer is excluded by the * o.e.j.containerInitializerExclusionPattern - * + * * @param sci the ServletContainerIntializer * @return true if the ServletContainerIntializer is excluded */ @@ -737,46 +730,85 @@ public class AnnotationConfiguration extends AbstractConfiguration //no exclusion pattern, no SCI is excluded by it if (_sciExcludePattern == null) return false; - + //test if name of class matches the regex - if (LOG.isDebugEnabled()) - LOG.debug("Checking {} against containerInitializerExclusionPattern",sci.getClass().getName()); + if (LOG.isDebugEnabled()) + LOG.debug("Checking {} against containerInitializerExclusionPattern", sci.getClass().getName()); return _sciExcludePattern.matcher(sci.getClass().getName()).matches(); } - - + /** * Test if the ServletContainerInitializer is from the container classpath - * + * * @param context the context for the webapp classpath * @param sci the ServletContainerIntializer * @return true if ServletContainerIntializer is from container classpath */ - public boolean isFromContainerClassPath (WebAppContext context, ServletContainerInitializer sci) + public boolean isFromContainerClassPath(WebAppContext context, ServletContainerInitializer sci) { if (sci == null) return false; - return sci.getClass().getClassLoader()==context.getClassLoader().getParent(); + + ClassLoader sciLoader = sci.getClass().getClassLoader(); + + //if loaded by bootstrap loader, then its the container classpath + if (sciLoader == null) + return true; + + //if there is no context classloader, then its the container classpath + if (context.getClassLoader() == null) + return true; + + ClassLoader loader = sciLoader; + while (loader != null) + { + if (loader == context.getClassLoader()) + return false; //the webapp classloader is in the ancestry of the classloader for the sci + else + loader = loader.getParent(); + } + + return true; + } + + /** + * Test if the ServletContainerInitializer is from WEB-INF/classes + * + * @param context the webapp to test + * @param sci a Resource representing the SCI + * @return true if the sci Resource is inside a WEB-INF/classes directory, false otherwise + */ + public boolean isFromWebInfClasses(WebAppContext context, Resource sci) + { + for (Resource dir : context.getMetaData().getWebInfClassesDirs()) + { + if (dir.equals(sci)) + { + return true; + } + } + return false; } /** * Get SCIs that are not excluded from consideration - * @param context the web app context + * + * @param context the web app context * @return the list of non-excluded servlet container initializers - * @throws Exception if unable to get list + * @throws Exception if unable to get list */ - public List getNonExcludedInitializers (WebAppContext context) - throws Exception + public List getNonExcludedInitializers(WebAppContext context) + throws Exception { ArrayList nonExcludedInitializers = new ArrayList(); - + //We use the ServiceLoader mechanism to find the ServletContainerInitializer classes to inspect long start = 0; ClassLoader old = Thread.currentThread().getContextClassLoader(); - + try - { + { if (LOG.isDebugEnabled()) start = System.nanoTime(); Thread.currentThread().setContextClassLoader(context.getClassLoader()); @@ -786,19 +818,18 @@ public class AnnotationConfiguration extends AbstractConfiguration { Thread.currentThread().setContextClassLoader(old); } - + if (LOG.isDebugEnabled()) - LOG.debug("Service loaders found in {}ms", (TimeUnit.MILLISECONDS.convert((System.nanoTime()-start), TimeUnit.NANOSECONDS))); - - - Map sciResourceMap = new HashMap(); + LOG.debug("Service loaders found in {}ms", (TimeUnit.MILLISECONDS.convert((System.nanoTime() - start), TimeUnit.NANOSECONDS))); + + Map sciResourceMap = new HashMap(); ServletContainerInitializerOrdering initializerOrdering = getInitializerOrdering(context); //Get initial set of SCIs that aren't from excluded jars or excluded by the containerExclusionPattern, or excluded //because containerInitializerOrdering omits it - for (ServletContainerInitializer sci:_loadedInitializers) - { - if (matchesExclusionPattern(sci)) + for (ServletContainerInitializer sci : _loadedInitializers) + { + if (matchesExclusionPattern(sci)) { if (LOG.isDebugEnabled()) LOG.debug("{} excluded by pattern", sci); @@ -806,23 +837,23 @@ public class AnnotationConfiguration extends AbstractConfiguration } Resource sciResource = getJarFor(sci); - if (isFromExcludedJar(context, sci, sciResource)) - { + if (isFromExcludedJar(context, sci, sciResource)) + { if (LOG.isDebugEnabled()) LOG.debug("{} is from excluded jar", sci); continue; } - + //check containerInitializerOrdering doesn't exclude it String name = sci.getClass().getName(); - if (initializerOrdering != null - && (!initializerOrdering.hasWildcard() && initializerOrdering.getIndexOf(name) < 0)) + if (initializerOrdering != null && + (!initializerOrdering.hasWildcard() && initializerOrdering.getIndexOf(name) < 0)) { if (LOG.isDebugEnabled()) LOG.debug("{} is excluded by ordering", sci); continue; } - + sciResourceMap.put(sci, sciResource); } @@ -830,7 +861,7 @@ public class AnnotationConfiguration extends AbstractConfiguration if (initializerOrdering != null && !initializerOrdering.isDefaultOrder()) { if (LOG.isDebugEnabled()) - LOG.debug("Ordering ServletContainerInitializers with "+initializerOrdering); + LOG.debug("Ordering ServletContainerInitializers with " + initializerOrdering); //There is an ordering that is not just "*". //Arrange ServletContainerInitializers according to the ordering of classnames given, irrespective of coming from container or webapp classpaths @@ -842,39 +873,61 @@ public class AnnotationConfiguration extends AbstractConfiguration //No jetty-specific ordering specified, or just the wildcard value "*" specified. //Fallback to ordering the ServletContainerInitializers according to: //container classpath first, WEB-INF/classes then WEB-INF/lib (obeying any web.xml jar ordering) - - //no web.xml ordering defined, add SCIs in any order + + //First add in all SCIs that can't be excluded + int lastContainerSCI = -1; + for (Map.Entry entry : sciResourceMap.entrySet()) + { + if (entry.getKey().getClass().getClassLoader() == context.getClassLoader().getParent()) + { + nonExcludedInitializers.add(++lastContainerSCI, entry.getKey()); //add all container SCIs before any webapp SCIs + } + else if (entry.getValue() == null) //can't work out provenance of SCI, so can't be ordered/excluded + { + nonExcludedInitializers.add(entry.getKey()); //add at end of list + } + else + { + for (Resource dir : context.getMetaData().getWebInfClassesDirs()) + { + if (dir.equals(entry.getValue()))//from WEB-INF/classes so can't be ordered/excluded + { + nonExcludedInitializers.add(entry.getKey()); + } + } + } + } + + //throw out the ones we've already accounted for + for (ServletContainerInitializer s : nonExcludedInitializers) + { + sciResourceMap.remove(s); + } + if (context.getMetaData().getOrdering() == null) { if (LOG.isDebugEnabled()) LOG.debug("No web.xml ordering, ServletContainerInitializers in random order"); + //add the rest of the scis nonExcludedInitializers.addAll(sciResourceMap.keySet()); } else { if (LOG.isDebugEnabled()) - LOG.debug("Ordering ServletContainerInitializers with ordering {}",context.getMetaData().getOrdering()); - for (Map.Entry entry:sciResourceMap.entrySet()) - { - //add in SCIs from the container classpath - if (entry.getKey().getClass().getClassLoader()==context.getClassLoader().getParent()) - nonExcludedInitializers.add(entry.getKey()); - else if (entry.getValue() == null) //add in SCIs not in a jar, as they must be from WEB-INF/classes and can't be ordered - nonExcludedInitializers.add(entry.getKey()); - } - + LOG.debug("Ordering ServletContainerInitializers with ordering {}", context.getMetaData().getOrdering()); + //add SCIs according to the ordering of its containing jar - for (Resource webInfJar:context.getMetaData().getOrderedWebInfJars()) + for (Resource webInfJar : context.getMetaData().getOrderedWebInfJars()) { - for (Map.Entry entry:sciResourceMap.entrySet()) + for (Map.Entry entry : sciResourceMap.entrySet()) { - if (webInfJar.equals(entry.getValue())) + if (webInfJar.equals(entry.getValue())) nonExcludedInitializers.add(entry.getKey()); } } } } - + //final pass over the non-excluded SCIs if the webapp version is < 3, in which case //we will only call SCIs that are on the server's classpath if (context.getServletContext().getEffectiveMajorVersion() < 3 && !context.isConfigurationDiscovered()) @@ -887,51 +940,51 @@ public class AnnotationConfiguration extends AbstractConfiguration { if (LOG.isDebugEnabled()) LOG.debug("Ignoring SCI {}: old web.xml version {}.{}", sci.getClass().getName(), - context.getServletContext().getEffectiveMajorVersion(), - context.getServletContext().getEffectiveMinorVersion()); + context.getServletContext().getEffectiveMajorVersion(), + context.getServletContext().getEffectiveMinorVersion()); it.remove(); } } } - if (LOG.isDebugEnabled()) + if (LOG.isDebugEnabled()) { - int i=0; - for (ServletContainerInitializer sci:nonExcludedInitializers) - LOG.debug("ServletContainerInitializer: {} {} from {}",(++i), sci.getClass().getName(), sciResourceMap.get(sci)); - } - + int i = 0; + for (ServletContainerInitializer sci : nonExcludedInitializers) + { + LOG.debug("ServletContainerInitializer: {} {} from {}", (++i), sci.getClass().getName(), sciResourceMap.get(sci)); + } + } + return nonExcludedInitializers; } - /** * Jetty-specific extension that allows an ordering to be applied across ALL ServletContainerInitializers. - * - * @param context the context for the initializer ordering configuration + * + * @param context the context for the initializer ordering configuration * @return the ordering of the ServletContainerIntializer's */ - public ServletContainerInitializerOrdering getInitializerOrdering (WebAppContext context) + public ServletContainerInitializerOrdering getInitializerOrdering(WebAppContext context) { if (context == null) return null; - + String tmp = (String)context.getAttribute(SERVLET_CONTAINER_INITIALIZER_ORDER); if (tmp == null || "".equals(tmp.trim())) return null; - + return new ServletContainerInitializerOrdering(tmp); } - /** * Scan jars on container path. - * + * * @param context the context for the scan * @param parser the parser to scan with * @throws Exception if unable to scan */ - public void parseContainerPath (final WebAppContext context, final AnnotationParser parser) throws Exception + public void parseContainerPath(final WebAppContext context, final AnnotationParser parser) throws Exception { //always parse for discoverable annotations as well as class hierarchy and servletcontainerinitializer related annotations final Set handlers = new HashSet(); @@ -949,26 +1002,25 @@ public class AnnotationConfiguration extends AbstractConfiguration if (_parserTasks != null) { ParserTask task = new ParserTask(parser, handlers, r); - _parserTasks.add(task); + _parserTasks.add(task); if (LOG.isDebugEnabled()) { _containerPathStats.increment(); task.setStatistic(new TimeStatistic()); } } - } + } } - /** * Scan jars in WEB-INF/lib - * + * * @param context the context for the scan * @param parser the annotation parser to use * @throws Exception if unable to scan and/or parse */ - public void parseWebInfLib (final WebAppContext context, final AnnotationParser parser) throws Exception - { + public void parseWebInfLib(final WebAppContext context, final AnnotationParser parser) throws Exception + { List frags = context.getMetaData().getFragments(); //email from Rajiv Mordani jsrs 315 7 April 2010 @@ -1001,7 +1053,7 @@ public class AnnotationConfiguration extends AbstractConfiguration // but yet we still need to do the scanning for the classes on behalf of the servletcontainerinitializers //if a jar has no web-fragment.xml we scan it (because it is not excluded by the ordering) //or if it has a fragment we scan it if it is not metadata complete - if (f == null || !isMetaDataComplete(f) || _classInheritanceHandler != null || !_containerInitializerAnnotationHandlers.isEmpty()) + if (f == null || !isMetaDataComplete(f) || _classInheritanceHandler != null || !_containerInitializerAnnotationHandlers.isEmpty()) { //register the classinheritance handler if there is one if (_classInheritanceHandler != null) @@ -1016,8 +1068,8 @@ public class AnnotationConfiguration extends AbstractConfiguration if (_parserTasks != null) { - ParserTask task = new ParserTask(parser, handlers,r); - _parserTasks.add (task); + ParserTask task = new ParserTask(parser, handlers, r); + _parserTasks.add(task); if (LOG.isDebugEnabled()) { _webInfLibStats.increment(); @@ -1028,16 +1080,15 @@ public class AnnotationConfiguration extends AbstractConfiguration } } - /** * Scan classes in WEB-INF/classes - * + * * @param context the context for the scan * @param parser the annotation parser to use * @throws Exception if unable to scan and/or parse */ - public void parseWebInfClasses (final WebAppContext context, final AnnotationParser parser) - throws Exception + public void parseWebInfClasses(final WebAppContext context, final AnnotationParser parser) + throws Exception { Set handlers = new HashSet(); handlers.addAll(_discoverableAnnotationHandlers); @@ -1063,25 +1114,23 @@ public class AnnotationConfiguration extends AbstractConfiguration } } - - /** * Get the web-fragment.xml from a jar - * + * * @param jar the jar to look in for a fragment * @param frags the fragments previously found * @return true if the fragment if found, or null of not found * @throws Exception if unable to determine the the fragment contains */ - public FragmentDescriptor getFragmentFromJar (Resource jar, List frags) - throws Exception + public FragmentDescriptor getFragmentFromJar(Resource jar, List frags) + throws Exception { //check if the jar has a web-fragment.xml FragmentDescriptor d = null; - for (FragmentDescriptor frag: frags) + for (FragmentDescriptor frag : frags) { Resource fragResource = frag.getResource(); //eg jar:file:///a/b/c/foo.jar!/META-INF/web-fragment.xml - if (Resource.isContainedIn(fragResource,jar)) + if (Resource.isContainedIn(fragResource, jar)) { d = frag; break; @@ -1090,20 +1139,18 @@ public class AnnotationConfiguration extends AbstractConfiguration return d; } - public boolean isMetaDataComplete (WebDescriptor d) + public boolean isMetaDataComplete(WebDescriptor d) { - return (d!=null && d.getMetaDataComplete() == MetaDataComplete.True); + return (d != null && d.getMetaDataComplete() == MetaDataComplete.True); } public static class ClassInheritanceMap extends ConcurrentHashMap> { - + @Override public String toString() { - return String.format("ClassInheritanceMap@%x{size=%d}",hashCode(),size()); + return String.format("ClassInheritanceMap@%x{size=%d}", hashCode(), size()); } } } - - diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationDecorator.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationDecorator.java index 48c9b2bd117..ed9a16e8bce 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationDecorator.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationDecorator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -30,10 +30,10 @@ public class AnnotationDecorator implements Decorator public AnnotationDecorator(WebAppContext context) { - registerHandlers(context); + registerHandlers(context); } - - public void registerHandlers (WebAppContext context) + + public void registerHandlers(WebAppContext context) { _introspector.registerHandler(new ResourceAnnotationHandler(context)); _introspector.registerHandler(new ResourcesAnnotationHandler(context)); @@ -54,9 +54,10 @@ public class AnnotationDecorator implements Decorator *
  • PreDestroy
  • *
  • ServletSecurity?
  • * + * * @param o the object ot introspect */ - protected void introspect (Object o) + protected void introspect(Object o) { _introspector.introspect(o.getClass()); } @@ -64,13 +65,13 @@ public class AnnotationDecorator implements Decorator @Override public Object decorate(Object o) { - introspect(o); - return o; + introspect(o); + return o; } @Override public void destroy(Object o) { - + } } diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationIntrospector.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationIntrospector.java index 7a24a989fc5..76351c8bcd2 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationIntrospector.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationIntrospector.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,18 +19,20 @@ package org.eclipse.jetty.annotations; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; /** * AnnotationIntrospector - * - * + * Introspects a class to find various types of + * annotations as defined by the servlet specification. */ public class AnnotationIntrospector -{ - protected List _handlers = new ArrayList(); - - +{ + private final Set> _introspectedClasses = new HashSet<>(); + private final List _handlers = new ArrayList(); + /** * IntrospectableAnnotationHandler * @@ -38,73 +40,81 @@ public class AnnotationIntrospector */ public interface IntrospectableAnnotationHandler { - public void handle(Class clazz); + void handle(Class clazz); } - - - + /** * AbstractIntrospectableAnnotationHandler * * Base class for handlers that introspect a class to find a particular annotation. * A handler can optionally introspect the parent hierarchy of a class. */ - public static abstract class AbstractIntrospectableAnnotationHandler implements IntrospectableAnnotationHandler + public abstract static class AbstractIntrospectableAnnotationHandler implements IntrospectableAnnotationHandler { private boolean _introspectAncestors; - + public abstract void doHandle(Class clazz); - - + public AbstractIntrospectableAnnotationHandler(boolean introspectAncestors) { _introspectAncestors = introspectAncestors; } - + @Override public void handle(Class clazz) { Class c = clazz; - + //process the whole inheritance hierarchy for the class - while (c!=null && (!c.equals(Object.class))) + while (c != null && (!c.equals(Object.class))) { doHandle(c); if (!_introspectAncestors) break; - + c = c.getSuperclass(); - } + } } } - - public void registerHandler (IntrospectableAnnotationHandler handler) + + public void registerHandler(IntrospectableAnnotationHandler handler) { _handlers.add(handler); } - - public void introspect (Class clazz) + + public void introspect(Class clazz) { if (_handlers == null) return; if (clazz == null) return; - - for (IntrospectableAnnotationHandler handler:_handlers) + + synchronized (_introspectedClasses) { - try + //Synchronize on the set of already introspected classes. + //This ensures that only 1 thread can be introspecting, and that + //thread must have fully finished generating the products of + //introspection before another thread is allowed in. + //We remember the classes that we have introspected to avoid + //reprocessing the same class. + if (_introspectedClasses.add(clazz)) { - handler.handle(clazz); - } - catch (RuntimeException e) - { - throw e; - } - catch (Exception e) - { - throw new RuntimeException(e); + for (IntrospectableAnnotationHandler handler : _handlers) + { + try + { + handler.handle(clazz); + } + catch (RuntimeException e) + { + throw e; + } + catch (Exception e) + { + throw new RuntimeException(e); + } + } } } - } } diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java index b6d9d35ceff..8f2ebc50662 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -24,7 +24,6 @@ import java.io.InputStream; import java.net.URI; import java.net.URL; import java.nio.file.Path; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -36,8 +35,11 @@ import java.util.concurrent.ConcurrentHashMap; import org.eclipse.jetty.util.JavaVersion; import org.eclipse.jetty.util.Loader; +import org.eclipse.jetty.util.ManifestUtils; import org.eclipse.jetty.util.MultiException; import org.eclipse.jetty.util.MultiReleaseJarFile; +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; import org.eclipse.jetty.util.resource.Resource; @@ -53,8 +55,8 @@ import org.objectweb.asm.Opcodes; *

    * Use asm to scan classes for annotations. A SAX-style parsing is done. * Handlers are registered which will be called back when various types of - * entity are encountered, eg a class, a method, a field. - *

    + * entity are encountered, eg a class, a method, a field. + *

    * Handlers are not called back in any particular order and are assumed * to be order-independent. *

    @@ -69,65 +71,67 @@ import org.objectweb.asm.Opcodes; public class AnnotationParser { private static final Logger LOG = Log.getLogger(AnnotationParser.class); - protected static int ASM_OPCODE_VERSION = Opcodes.ASM6; //compatibility of api - protected static String ASM_OPCODE_VERSION_STR = "ASM6"; - + private static final int ASM_OPCODE_VERSION = Opcodes.ASM7; //compatibility of api + private static final String ASM_OPCODE_VERSION_STR = "ASM7"; + /** * Map of classnames scanned and the first location from which scan occurred */ protected Map _parsedClassNames = new ConcurrentHashMap<>(); private final int _javaPlatform; private int _asmVersion; - + /** * Determine the runtime version of asm. + * * @return the org.objectweb.asm.Opcode matching the runtime version of asm. */ - public static int asmVersion () + public static int asmVersion() { int asmVersion = ASM_OPCODE_VERSION; - Package asm = Opcodes.class.getPackage(); - if (asm == null) - LOG.warn("Unknown asm runtime version, assuming version {}", ASM_OPCODE_VERSION_STR); + String version = ManifestUtils.getVersion(Opcodes.class).orElse(null); + if (version == null) + { + LOG.warn("Unknown ASM version, assuming {}", ASM_OPCODE_VERSION_STR); + } else { - String s = asm.getImplementationVersion(); - if (s==null) - LOG.info("Unknown asm implementation version, assuming version {}", ASM_OPCODE_VERSION_STR); - else + int dot = version.indexOf('.'); + version = version.substring(0, (dot < 0 ? version.length() : dot)).trim(); + try { - int dot = s.indexOf('.'); - s = s.substring(0, (dot < 0 ? s.length() : dot)).trim(); - try + int v = Integer.parseInt(version); + switch (v) { - int v = Integer.parseInt(s); - switch (v) + case 4: { - case 4: - { - asmVersion = Opcodes.ASM4; - break; - } - case 5: - { - asmVersion = Opcodes.ASM5; - break; - } - case 6: - { - asmVersion = Opcodes.ASM6; - break; - } - default: - { - LOG.warn("Unrecognized runtime asm version, assuming {}", ASM_OPCODE_VERSION_STR); - } + asmVersion = Opcodes.ASM4; + break; + } + case 5: + { + asmVersion = Opcodes.ASM5; + break; + } + case 6: + { + asmVersion = Opcodes.ASM6; + break; + } + case 7: + { + asmVersion = Opcodes.ASM7; + break; + } + default: + { + LOG.warn("Unrecognized ASM version, assuming {}", ASM_OPCODE_VERSION_STR); } } - catch (NumberFormatException e) - { - LOG.warn("Unable to parse runtime asm version, assuming version {}", ASM_OPCODE_VERSION_STR); - } + } + catch (NumberFormatException e) + { + LOG.warn("Unable to parse ASM version, assuming {}", ASM_OPCODE_VERSION_STR); } } return asmVersion; @@ -135,54 +139,56 @@ public class AnnotationParser /** * Convert internal name to simple name - * + * * @param name the internal name * @return the simple name */ - public static String normalize (String name) + public static String normalize(String name) { - if (name==null) + if (name == null) return null; if (name.startsWith("L") && name.endsWith(";")) - name = name.substring(1, name.length()-1); + name = name.substring(1, name.length() - 1); if (name.endsWith(".class")) - name = name.substring(0, name.length()-".class".length()); + name = name.substring(0, name.length() - ".class".length()); - return name.replace('/', '.'); + return StringUtil.replace(name, '/', '.'); } - + /** * Convert internal names to simple names. - * + * * @param list the list of internal names * @return the list of simple names */ - public static String[] normalize (String[] list) + public static String[] normalize(String[] list) { if (list == null) - return null; + return null; String[] normalList = new String[list.length]; - int i=0; + int i = 0; for (String s : list) + { normalList[i++] = normalize(s); + } return normalList; } /** * Immutable information gathered by parsing class header. */ - public class ClassInfo + public class ClassInfo { final Resource _containingResource; final String _className; final int _version; final int _access; final String _signature; - final String _superName; + final String _superName; final String[] _interfaces; - + public ClassInfo(Resource resource, String className, int version, int access, String signature, String superName, String[] interfaces) { super(); @@ -237,12 +243,12 @@ public class AnnotationParser public class MethodInfo { final ClassInfo _classInfo; - final String _methodName; + final String _methodName; final int _access; - final String _desc; + final String _desc; final String _signature; final String[] _exceptions; - + public MethodInfo(ClassInfo classInfo, String methodName, int access, String desc, String signature, String[] exceptions) { super(); @@ -296,7 +302,7 @@ public class AnnotationParser final String _fieldType; final String _signature; final Object _value; - + public FieldInfo(ClassInfo classInfo, String fieldName, int access, String fieldType, String signature, Object value) { super(); @@ -338,24 +344,29 @@ public class AnnotationParser return _value; } } - + /** * Signature for all handlers that respond to parsing class files. */ - public static interface Handler + public interface Handler { - public void handle(ClassInfo classInfo); - public void handle(MethodInfo methodInfo); - public void handle (FieldInfo fieldInfo); - public void handle (ClassInfo info, String annotationName); - public void handle (MethodInfo info, String annotationName); - public void handle (FieldInfo info, String annotationName); + void handle(ClassInfo classInfo); + + void handle(MethodInfo methodInfo); + + void handle(FieldInfo fieldInfo); + + void handle(ClassInfo info, String annotationName); + + void handle(MethodInfo info, String annotationName); + + void handle(FieldInfo info, String annotationName); } - + /** * Convenience base class to provide no-ops for all Handler methods. */ - public static abstract class AbstractHandler implements Handler + public abstract static class AbstractHandler implements Handler { @Override public void handle(ClassInfo classInfo) @@ -395,7 +406,7 @@ public class AnnotationParser { final MethodInfo _mi; final Set _handlers; - + public MyMethodVisitor(final Set handlers, final ClassInfo classInfo, final int access, @@ -407,7 +418,7 @@ public class AnnotationParser { super(asmVersion); _handlers = handlers; - _mi = new MethodInfo(classInfo, name, access, methodDesc,signature, exceptions); + _mi = new MethodInfo(classInfo, name, access, methodDesc, signature, exceptions); } /** @@ -417,8 +428,10 @@ public class AnnotationParser public AnnotationVisitor visitAnnotation(String desc, boolean visible) { String annotationName = normalize(desc); - for (Handler h:_handlers) + for (Handler h : _handlers) + { h.handle(_mi, annotationName); + } return null; } } @@ -428,7 +441,7 @@ public class AnnotationParser * We are only interested in visiting annotations on Fields. */ public class MyFieldVisitor extends FieldVisitor - { + { final FieldInfo _fieldInfo; final Set _handlers; @@ -454,7 +467,9 @@ public class AnnotationParser { String annotationName = normalize(desc); for (Handler h : _handlers) - h.handle(_fieldInfo, annotationName); + { + h.handle(_fieldInfo, annotationName); + } return null; } @@ -469,7 +484,7 @@ public class AnnotationParser final Resource _containingResource; final Set _handlers; ClassInfo _ci; - + public MyClassVisitor(Set handlers, Resource containingResource, int asmVersion) { super(asmVersion); @@ -479,27 +494,31 @@ public class AnnotationParser } @Override - public void visit (final int version, - final int access, - final String name, - final String signature, - final String superName, - final String[] interfaces) - { + public void visit(final int version, + final int access, + final String name, + final String signature, + final String superName, + final String[] interfaces) + { _ci = new ClassInfo(_containingResource, normalize(name), version, access, signature, normalize(superName), normalize(interfaces)); - for (Handler h:_handlers) - h.handle(_ci); + for (Handler h : _handlers) + { + h.handle(_ci); + } } /** * Visit an annotation on a Class */ @Override - public AnnotationVisitor visitAnnotation (String desc, boolean visible) + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { String annotationName = normalize(desc); for (Handler h : _handlers) + { h.handle(_ci, annotationName); + } return null; } @@ -507,11 +526,11 @@ public class AnnotationParser * Visit a method to extract its annotations */ @Override - public MethodVisitor visitMethod (final int access, - final String name, - final String methodDesc, - final String signature, - final String[] exceptions) + public MethodVisitor visitMethod(final int access, + final String name, + final String methodDesc, + final String signature, + final String[] exceptions) { return new MyMethodVisitor(_handlers, _ci, access, name, methodDesc, signature, exceptions, _asmVersion); } @@ -520,11 +539,11 @@ public class AnnotationParser * Visit a field to extract its annotations */ @Override - public FieldVisitor visitField (final int access, - final String fieldName, - final String fieldType, - final String signature, - final Object value) + public FieldVisitor visitField(final int access, + final String fieldName, + final String fieldType, + final String signature, + final Object value) { return new MyFieldVisitor(_handlers, _ci, access, fieldName, fieldType, signature, value, _asmVersion); } @@ -541,70 +560,66 @@ public class AnnotationParser public AnnotationParser(int javaPlatform) { _asmVersion = asmVersion(); - if (javaPlatform==0) + if (javaPlatform == 0) javaPlatform = JavaVersion.VERSION.getPlatform(); _javaPlatform = javaPlatform; } - - + public AnnotationParser(int javaPlatform, int asmVersion) { - if (javaPlatform==0) + if (javaPlatform == 0) javaPlatform = JavaVersion.VERSION.getPlatform(); _javaPlatform = javaPlatform; - if (asmVersion==0) + if (asmVersion == 0) asmVersion = ASM_OPCODE_VERSION; _asmVersion = asmVersion; } - + /** * Add a class as having been parsed. - * + * * @param classname the name of the class * @param location the fully qualified location of the class */ - public void addParsedClass (String classname, Resource location) + public void addParsedClass(String classname, Resource location) { - Resource existing = _parsedClassNames.putIfAbsent(classname, location); + Resource existing = _parsedClassNames.putIfAbsent(classname, location); if (existing != null) LOG.warn("{} scanned from multiple locations: {}, {}", classname, existing, location); } - /** * Get the locations of the given classname. There may be more than one * location if there are duplicates of the same class. - * + * * @param classname the name of the class * @return an immutable list of locations - * * @deprecated List of duplicate locations no longer stored */ @Deprecated - public List getParsedLocations (String classname) + public List getParsedLocations(String classname) { return Collections.emptyList(); } /** * Parse a given class - * + * * @param handlers the set of handlers to find class * @param className the class name to parse * @throws Exception if unable to parse */ - public void parse (Set handlers, String className) throws Exception + public void parse(Set handlers, String className) throws Exception { if (className == null) return; - String tmp = className; - className = className.replace('.', '/')+".class"; - URL resource = Loader.getResource(className); - if (resource!= null) + String classRef = TypeUtil.toClassReference(className); + URL resource = Loader.getResource(classRef); + if (resource != null) { Resource r = Resource.newResource(resource); - addParsedClass(tmp, r); + addParsedClass(className, r); try (InputStream is = r.getInputStream()) { scanClass(handlers, null, is); @@ -614,24 +629,24 @@ public class AnnotationParser /** * Parse the given class, optionally walking its inheritance hierarchy - * - * @param handlers the handlers to look for class in + * + * @param handlers the handlers to look for class in * @param clazz the class to look for - * @param visitSuperClasses if true, also visit super classes for parse + * @param visitSuperClasses if true, also visit super classes for parse * @throws Exception if unable to parse class */ - public void parse (Set handlers, Class clazz, boolean visitSuperClasses) throws Exception + public void parse(Set handlers, Class clazz, boolean visitSuperClasses) throws Exception { Class cz = clazz; while (cz != Object.class) { - String nameAsResource = cz.getName().replace('.', '/')+".class"; + String nameAsResource = TypeUtil.toClassReference(cz); URL resource = Loader.getResource(nameAsResource); - if (resource!= null) + if (resource != null) { Resource r = Resource.newResource(resource); addParsedClass(clazz.getName(), r); - try (InputStream is = r.getInputStream()) + try (InputStream is = r.getInputStream()) { scanClass(handlers, null, is); } @@ -646,12 +661,12 @@ public class AnnotationParser /** * Parse the given classes - * - * @param handlers the set of handlers to look for class in + * + * @param handlers the set of handlers to look for class in * @param classNames the class name * @throws Exception if unable to parse */ - public void parse (Set handlers, String[] classNames) throws Exception + public void parse(Set handlers, String[] classNames) throws Exception { if (classNames == null) return; @@ -661,26 +676,25 @@ public class AnnotationParser /** * Parse the given classes - * - * @param handlers the set of handlers to look for class in + * + * @param handlers the set of handlers to look for class in * @param classNames the class names * @throws Exception if unable to parse */ - public void parse (Set handlers, List classNames) throws Exception + public void parse(Set handlers, List classNames) throws Exception { MultiException me = new MultiException(); - for (String s:classNames) + for (String className : classNames) { try { - String name = s; - s = s.replace('.', '/')+".class"; - URL resource = Loader.getResource(s); - if (resource!= null) + String classRef = TypeUtil.toClassReference(className); + URL resource = Loader.getResource(classRef); + if (resource != null) { Resource r = Resource.newResource(resource); - addParsedClass(name, r); + addParsedClass(className, r); try (InputStream is = r.getInputStream()) { scanClass(handlers, null, is); @@ -689,7 +703,7 @@ public class AnnotationParser } catch (Exception e) { - me.add(new RuntimeException("Error scanning class "+s, e)); + me.add(new RuntimeException("Error scanning class " + className, e)); } } me.ifExceptionThrow(); @@ -697,94 +711,97 @@ public class AnnotationParser /** * Parse all classes in a directory - * - * @param handlers the set of handlers to look for classes in + * + * @param handlers the set of handlers to look for classes in * @param root the resource directory to look for classes * @throws Exception if unable to parse */ - protected void parseDir (Set handlers, Resource root) throws Exception + protected void parseDir(Set handlers, Resource root) throws Exception { if (!root.isDirectory() || !root.exists() || root.getName().startsWith(".")) return; if (LOG.isDebugEnabled()) LOG.debug("Scanning dir {}", root); - + File rootFile = root.getFile(); - + MultiException me = new MultiException(); Collection resources = root.getAllResources(); if (resources != null) { - for (Resource r:resources) + for (Resource r : resources) { if (r.isDirectory()) continue; - File file = r.getFile(); - if (isValidClassFileName((file==null?null:file.getName()))) + File file = r.getFile(); + if (isValidClassFileName((file == null ? null : file.getName()))) { Path classpath = rootFile.toPath().relativize(file.toPath()); String str = classpath.toString(); - str = str.substring(0, str.lastIndexOf(".class")).replace('/', '.').replace('\\', '.'); - + str = str.substring(0, str.lastIndexOf(".class")); + str = StringUtil.replace(str, File.separatorChar, '.'); + try { if (LOG.isDebugEnabled()) LOG.debug("Scanning class {}", r); addParsedClass(str, r); - try (InputStream is=r.getInputStream()) + try (InputStream is = r.getInputStream()) { scanClass(handlers, Resource.newResource(file.getParentFile()), is); } - } + } catch (Exception ex) { - if (LOG.isDebugEnabled()) LOG.debug("Error scanning file "+file, ex); - me.add(new RuntimeException("Error scanning file "+file,ex)); + if (LOG.isDebugEnabled()) + LOG.debug("Error scanning file " + file, ex); + me.add(new RuntimeException("Error scanning file " + file, ex)); } } else { - if (LOG.isDebugEnabled()) LOG.debug("Skipping scan on invalid file {}", file); + if (LOG.isDebugEnabled()) + LOG.debug("Skipping scan on invalid file {}", file); } } } - + me.ifExceptionThrow(); } /** - * Parse classes in the supplied classloader. + * Parse classes in the supplied classloader. * Only class files in jar files will be scanned. - * - * @param handlers the handlers to look for classes in + * + * @param handlers the handlers to look for classes in * @param loader the classloader for the classes * @param visitParents if true, visit parent classloaders too * @param nullInclusive if true, an empty pattern means all names match, if false, none match * @throws Exception if unable to parse */ @Deprecated - public void parse (final Set handlers, ClassLoader loader, boolean visitParents, boolean nullInclusive) throws Exception + public void parse(final Set handlers, ClassLoader loader, boolean visitParents, boolean nullInclusive) throws Exception { throw new UnsupportedOperationException(); } /** * Parse classes in the supplied uris. - * - * @param handlers the handlers to look for classes in + * + * @param handlers the handlers to look for classes in * @param uris the uris for the jars * @throws Exception if unable to parse */ - public void parse (final Set handlers, final URI[] uris) throws Exception + public void parse(final Set handlers, final URI[] uris) throws Exception { - if (uris==null) + if (uris == null) return; MultiException me = new MultiException(); - - for (URI uri:uris) + + for (URI uri : uris) { try { @@ -792,7 +809,7 @@ public class AnnotationParser } catch (Exception e) { - me.add(new RuntimeException("Problem parsing classes from "+ uri, e)); + me.add(new RuntimeException("Problem parsing classes from " + uri, e)); } } me.ifExceptionThrow(); @@ -800,31 +817,31 @@ public class AnnotationParser /** * Parse a particular uri - * - * @param handlers the handlers to look for classes in - * @param uri the uri for the jar + * + * @param handlers the handlers to look for classes in + * @param uri the uri for the jar * @throws Exception if unable to parse */ - public void parse (final Set handlers, URI uri) throws Exception + public void parse(final Set handlers, URI uri) throws Exception { if (uri == null) return; - parse (handlers, Resource.newResource(uri)); + parse(handlers, Resource.newResource(uri)); } /** * Parse a resource - * - * @param handlers the handlers to look for classes in + * + * @param handlers the handlers to look for classes in * @param r the resource to parse * @throws Exception if unable to parse */ - public void parse (final Set handlers, Resource r) throws Exception + public void parse(final Set handlers, Resource r) throws Exception { if (r == null) return; - + if (r.exists() && r.isDirectory()) { parseDir(handlers, r); @@ -840,37 +857,38 @@ public class AnnotationParser if (fullname.endsWith(".class")) { - try (InputStream is=r.getInputStream()) + try (InputStream is = r.getInputStream()) { scanClass(handlers, null, is); return; } } - - if (LOG.isDebugEnabled()) LOG.warn("Resource not scannable for classes: {}", r); + + if (LOG.isDebugEnabled()) + LOG.warn("Resource not scannable for classes: {}", r); } /** * Parse a resource that is a jar file. - * - * @param handlers the handlers to look for classes in + * + * @param handlers the handlers to look for classes in * @param jarResource the jar resource to parse * @throws Exception if unable to parse */ - protected void parseJar (Set handlers, Resource jarResource) throws Exception + protected void parseJar(Set handlers, Resource jarResource) throws Exception { if (jarResource == null) return; - + if (jarResource.toString().endsWith(".jar")) { if (LOG.isDebugEnabled()) LOG.debug("Scanning jar {}", jarResource); MultiException me = new MultiException(); - try (MultiReleaseJarFile jarFile = new MultiReleaseJarFile(jarResource.getFile(),_javaPlatform,false)) + try (MultiReleaseJarFile jarFile = new MultiReleaseJarFile(jarResource.getFile(), _javaPlatform, false)) { - jarFile.stream().forEach(e-> + jarFile.stream().forEach(e -> { try { @@ -883,19 +901,19 @@ public class AnnotationParser }); } me.ifExceptionThrow(); - } + } } /** * Parse a single entry in a jar file - * - * @param handlers the handlers to look for classes in + * + * @param handlers the handlers to look for classes in * @param entry the entry in the potentially MultiRelease jar resource to parse * @param jar the jar file * @throws Exception if unable to parse */ - protected void parseJarEntry (Set handlers, Resource jar, MultiReleaseJarFile.VersionedJarEntry entry) - throws Exception + protected void parseJarEntry(Set handlers, Resource jar, MultiReleaseJarFile.VersionedJarEntry entry) + throws Exception { if (jar == null || entry == null) return; @@ -909,8 +927,8 @@ public class AnnotationParser //check file is a valid class file name if (isValidClassFileName(name) && isValidClassFilePath(name)) { - String shortName = name.replace('/', '.').substring(0,name.length()-6); - addParsedClass(shortName, Resource.newResource("jar:"+jar.getURI()+"!/"+entry.getNameInJar())); + String shortName = StringUtil.replace(name, '/', '.').substring(0, name.length() - 6); + addParsedClass(shortName, Resource.newResource("jar:" + jar.getURI() + "!/" + entry.getNameInJar())); if (LOG.isDebugEnabled()) LOG.debug("Scanning class from jar {}!/{}", jar, entry); try (InputStream is = entry.getInputStream()) @@ -922,22 +940,22 @@ public class AnnotationParser /** * Use ASM on a class - * - * @param handlers the handlers to look for classes in + * + * @param handlers the handlers to look for classes in * @param containingResource the dir or jar that the class is contained within, can be null if not known * @param is the input stream to parse * @throws IOException if unable to parse */ - protected void scanClass (Set handlers, Resource containingResource, InputStream is) throws IOException + protected void scanClass(Set handlers, Resource containingResource, InputStream is) throws IOException { ClassReader reader = new ClassReader(is); - reader.accept(new MyClassVisitor(handlers, containingResource, _asmVersion), ClassReader.SKIP_CODE|ClassReader.SKIP_DEBUG|ClassReader.SKIP_FRAMES); + reader.accept(new MyClassVisitor(handlers, containingResource, _asmVersion), ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); } - + /** * Remove any parsed class names. */ - public void resetParsedClasses () + public void resetParsedClasses() { _parsedClassNames.clear(); } @@ -950,39 +968,43 @@ public class AnnotationParser *

  • it isn't a dot file or in a hidden directory
  • *
  • the name of the class at least begins with a valid identifier for a class name
  • * + * * @param name the class file name * @return whether the class file name is valid */ - private boolean isValidClassFileName (String name) + private boolean isValidClassFileName(String name) { //no name cannot be valid - if (name == null || name.length()==0) + if (name == null || name.length() == 0) return false; //skip anything that is not a class file String lc = name.toLowerCase(Locale.ENGLISH); if (!lc.endsWith(".class")) { - if (LOG.isDebugEnabled()) LOG.debug("Not a class: {}",name); + if (LOG.isDebugEnabled()) + LOG.debug("Not a class: {}", name); return false; } - + if (lc.equals("module-info.class")) { - if (LOG.isDebugEnabled()) LOG.debug("Skipping module-info.class"); + if (LOG.isDebugEnabled()) + LOG.debug("Skipping module-info.class"); return false; } //skip any classfiles that are not a valid java identifier - int c0 = 0; - int ldir = name.lastIndexOf('/', name.length()-6); - c0 = (ldir > -1 ? ldir+1 : c0); + int c0 = 0; + int ldir = name.lastIndexOf('/', name.length() - 6); + c0 = (ldir > -1 ? ldir + 1 : c0); if (!Character.isJavaIdentifierStart(name.charAt(c0))) { - if (LOG.isDebugEnabled()) LOG.debug("Not a java identifier: {}",name); + if (LOG.isDebugEnabled()) + LOG.debug("Not a java identifier: {}", name); return false; } - + return true; } @@ -992,16 +1014,17 @@ public class AnnotationParser * @param path the class file path * @return whether the class file path is valid */ - private boolean isValidClassFilePath (String path) + private boolean isValidClassFilePath(String path) { //no path is not valid - if (path == null || path.length()==0) + if (path == null || path.length() == 0) return false; // skip any classfiles that are in a hidden directory if (path.startsWith(".") || path.contains("/.")) { - if (LOG.isDebugEnabled()) LOG.debug("Contains hidden dirs: " + path); + if (LOG.isDebugEnabled()) + LOG.debug("Contains hidden dirs: " + path); return false; } diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ClassInheritanceHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ClassInheritanceHandler.java index b1096cf7952..a0e9c2bd947 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ClassInheritanceHandler.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ClassInheritanceHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -35,10 +35,9 @@ import org.eclipse.jetty.util.log.Logger; public class ClassInheritanceHandler extends AbstractHandler { private static final Logger LOG = Log.getLogger(ClassInheritanceHandler.class); - + Map> _inheritanceMap; - - + public ClassInheritanceHandler(Map> map) { _inheritanceMap = map; @@ -52,8 +51,8 @@ public class ClassInheritanceHandler extends AbstractHandler //Don't scan Object if ("java.lang.Object".equals(classInfo.getClassName())) return; - - for (int i=0; classInfo.getInterfaces() != null && i < classInfo.getInterfaces().length;i++) + + for (int i = 0; classInfo.getInterfaces() != null && i < classInfo.getInterfaces().length; i++) { addToInheritanceMap(classInfo.getInterfaces()[i], classInfo.getClassName()); } @@ -66,12 +65,12 @@ public class ClassInheritanceHandler extends AbstractHandler catch (Exception e) { LOG.warn(e); - } + } } - - private void addToInheritanceMap (String interfaceOrSuperClassName, String implementingOrExtendingClassName) + + private void addToInheritanceMap(String interfaceOrSuperClassName, String implementingOrExtendingClassName) { - + //As it is likely that the interfaceOrSuperClassName is already in the map, try getting it first Set implementingClasses = _inheritanceMap.get(interfaceOrSuperClassName); //If it isn't in the map, then add it in, but test to make sure that someone else didn't get in @@ -83,7 +82,7 @@ public class ClassInheritanceHandler extends AbstractHandler if (tmp != null) implementingClasses = tmp; } - + implementingClasses.add(implementingOrExtendingClassName); } } diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ContainerInitializerAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ContainerInitializerAnnotationHandler.java index 5fd74b4b579..c84910344ad 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ContainerInitializerAnnotationHandler.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ContainerInitializerAnnotationHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,10 +16,8 @@ // ======================================================================== // - package org.eclipse.jetty.annotations; - import org.eclipse.jetty.annotations.AnnotationParser.AbstractHandler; import org.eclipse.jetty.annotations.AnnotationParser.ClassInfo; import org.eclipse.jetty.annotations.AnnotationParser.FieldInfo; @@ -29,16 +27,16 @@ import org.eclipse.jetty.plus.annotation.ContainerInitializer; /** * ContainerInitializerAnnotationHandler *

    - * Discovers classes that contain the specified annotation, either at class or - * method level. The specified annotation is derived from an @HandlesTypes on - * a ServletContainerInitializer class. + * Discovers classes that contain the specified annotation, either at class or + * method level. The specified annotation is derived from an @HandlesTypes on + * a ServletContainerInitializer class. */ public class ContainerInitializerAnnotationHandler extends AbstractHandler { final ContainerInitializer _initializer; final Class _annotation; - public ContainerInitializerAnnotationHandler (ContainerInitializer initializer, Class annotation) + public ContainerInitializerAnnotationHandler(ContainerInitializer initializer, Class annotation) { _initializer = initializer; _annotation = annotation; @@ -46,34 +44,34 @@ public class ContainerInitializerAnnotationHandler extends AbstractHandler /** * Handle finding a class that is annotated with the annotation we were constructed with. - * + * * @see org.eclipse.jetty.annotations.AnnotationParser.Handler#handle(org.eclipse.jetty.annotations.AnnotationParser.ClassInfo, String) */ @Override public void handle(ClassInfo info, String annotationName) { if (annotationName == null || !_annotation.getName().equals(annotationName)) - return; - - _initializer.addAnnotatedTypeName(info.getClassName()); + return; + + _initializer.addAnnotatedTypeName(info.getClassName()); } /** * Handle finding a field that is annotated with the annotation we were constructed with. - * + * * @see org.eclipse.jetty.annotations.AnnotationParser.Handler#handle(org.eclipse.jetty.annotations.AnnotationParser.FieldInfo, String) */ @Override public void handle(FieldInfo info, String annotationName) - { + { if (annotationName == null || !_annotation.getName().equals(annotationName)) return; _initializer.addAnnotatedTypeName(info.getClassInfo().getClassName()); } /** - * Handle finding a method that is annotated with the annotation we were constructed with. - * + * Handle finding a method that is annotated with the annotation we were constructed with. + * * @see org.eclipse.jetty.annotations.AnnotationParser.Handler#handle(org.eclipse.jetty.annotations.AnnotationParser.MethodInfo, String) */ @Override @@ -81,10 +79,9 @@ public class ContainerInitializerAnnotationHandler extends AbstractHandler { if (annotationName == null || !_annotation.getName().equals(annotationName)) return; - _initializer.addAnnotatedTypeName(info.getClassInfo().getClassName()); + _initializer.addAnnotatedTypeName(info.getClassInfo().getClassName()); } - public ContainerInitializer getContainerInitializer() { return _initializer; diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/DeclareRolesAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/DeclareRolesAnnotationHandler.java index daba6494b12..0c5fc003aba 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/DeclareRolesAnnotationHandler.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/DeclareRolesAnnotationHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,7 +18,6 @@ package org.eclipse.jetty.annotations; - import javax.annotation.security.DeclareRoles; import javax.servlet.Servlet; @@ -44,7 +43,6 @@ public class DeclareRolesAnnotationHandler extends AbstractIntrospectableAnnotat _context = context; } - /** * @see org.eclipse.jetty.annotations.AnnotationIntrospector.AbstractIntrospectableAnnotationHandler#doHandle(java.lang.Class) */ @@ -60,7 +58,7 @@ public class DeclareRolesAnnotationHandler extends AbstractIntrospectableAnnotat return; } - DeclareRoles declareRoles = (DeclareRoles) clazz.getAnnotation(DeclareRoles.class); + DeclareRoles declareRoles = (DeclareRoles)clazz.getAnnotation(DeclareRoles.class); if (declareRoles == null) return; @@ -68,9 +66,10 @@ public class DeclareRolesAnnotationHandler extends AbstractIntrospectableAnnotat if (roles != null && roles.length > 0) { - for (String r:roles) + for (String r : roles) + { ((ConstraintSecurityHandler)_context.getSecurityHandler()).addRole(r); + } } } - } diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/MultiPartConfigAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/MultiPartConfigAnnotationHandler.java index 72d171eed0a..920a807c44a 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/MultiPartConfigAnnotationHandler.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/MultiPartConfigAnnotationHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -30,8 +30,6 @@ import org.eclipse.jetty.webapp.WebAppContext; /** * MultiPartConfigAnnotationHandler - * - * */ public class MultiPartConfigAnnotationHandler extends AbstractIntrospectableAnnotationHandler { @@ -40,10 +38,11 @@ public class MultiPartConfigAnnotationHandler extends AbstractIntrospectableAnno public MultiPartConfigAnnotationHandler(WebAppContext context) { //TODO verify that MultipartConfig is not inheritable - super(false); + super(false); _context = context; } - /** + + /** * @see org.eclipse.jetty.annotations.AnnotationIntrospector.AbstractIntrospectableAnnotationHandler#doHandle(java.lang.Class) */ @Override @@ -51,46 +50,27 @@ public class MultiPartConfigAnnotationHandler extends AbstractIntrospectableAnno { if (!Servlet.class.isAssignableFrom(clazz)) return; - - MultipartConfig multi = (MultipartConfig) clazz.getAnnotation(MultipartConfig.class); + + MultipartConfig multi = (MultipartConfig)clazz.getAnnotation(MultipartConfig.class); if (multi == null) return; - + MetaData metaData = _context.getMetaData(); - + //TODO: The MultipartConfigElement needs to be set on the ServletHolder's Registration. //How to identify the correct Servlet? If the Servlet has no WebServlet annotation on it, does it mean that this MultipartConfig //annotation applies to all declared instances in web.xml/programmatically? //Assuming TRUE for now. - - ServletHolder holder = getServletHolderForClass(clazz); - if (holder != null) + for (ServletHolder holder : _context.getServletHandler().getServlets(clazz)) { - Descriptor d = metaData.getOriginDescriptor(holder.getName()+".servlet.multipart-config"); + Descriptor d = metaData.getOriginDescriptor(holder.getName() + ".servlet.multipart-config"); //if a descriptor has already set the value for multipart config, do not //let the annotation override it if (d == null) { - metaData.setOrigin(holder.getName()+".servlet.multipart-config",multi,clazz); + metaData.setOrigin(holder.getName() + ".servlet.multipart-config", multi, clazz); holder.getRegistration().setMultipartConfig(new MultipartConfigElement(multi)); } } } - - private ServletHolder getServletHolderForClass (Class clazz) - { - ServletHolder holder = null; - ServletHolder[] holders = _context.getServletHandler().getServlets(); - if (holders != null) - { - for (ServletHolder h : holders) - { - if (h.getClassName() != null && h.getClassName().equals(clazz.getName())) - { - holder = h; - } - } - } - return holder; - } } diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/PostConstructAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/PostConstructAnnotationHandler.java index 4c1ac135f1c..d75602bdcd7 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/PostConstructAnnotationHandler.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/PostConstructAnnotationHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,7 +20,6 @@ package org.eclipse.jetty.annotations; import java.lang.reflect.Method; import java.lang.reflect.Modifier; - import javax.annotation.PostConstruct; import org.eclipse.jetty.annotations.AnnotationIntrospector.AbstractIntrospectableAnnotationHandler; @@ -34,13 +33,12 @@ public class PostConstructAnnotationHandler extends AbstractIntrospectableAnnota { protected WebAppContext _context; - public PostConstructAnnotationHandler (WebAppContext wac) + public PostConstructAnnotationHandler(WebAppContext wac) { super(true); _context = wac; } - @Override public void doHandle(Class clazz) { @@ -48,19 +46,19 @@ public class PostConstructAnnotationHandler extends AbstractIntrospectableAnnota if (supportsPostConstruct(clazz)) { Method[] methods = clazz.getDeclaredMethods(); - for (int i=0; i> ENV_ENTRY_TYPES = - Arrays.asList(new Class[] {String.class, Character.class, Integer.class, Boolean.class, Double.class, Byte.class, Short.class, Long.class, Float.class}); - + + protected static final List> ENV_ENTRY_TYPES = + Arrays.asList(new Class[] + { + String.class, Character.class, Integer.class, Boolean.class, Double.class, Byte.class, Short.class, Long.class, + Float.class + }); protected WebAppContext _context; - - public ResourceAnnotationHandler (WebAppContext wac) + public ResourceAnnotationHandler(WebAppContext wac) { super(true); _context = wac; } - /** - * Class level Resource annotations declare a name in the - * environment that will be looked up at runtime. They do - * not specify an injection. + * Class level Resource annotations declare a name in the + * environment that will be looked up at runtime. They do + * not specify an injection. */ @Override public void doHandle(Class clazz) @@ -69,64 +69,68 @@ public class ResourceAnnotationHandler extends AbstractIntrospectableAnnotationH handleClass(clazz); Method[] methods = clazz.getDeclaredMethods(); - for (int i=0; i clazz) - { - Resource resource = (Resource)clazz.getAnnotation(Resource.class); - if (resource != null) - { - String name = resource.name(); - String mappedName = resource.mappedName(); + public void handleClass(Class clazz) + { + Resource resource = clazz.getAnnotation(Resource.class); + if (resource != null) + { + String name = resource.name(); + String mappedName = resource.mappedName(); - if (name==null || name.trim().equals("")) - throw new IllegalStateException ("Class level Resource annotations must contain a name (Common Annotations Spec Section 2.3)"); + if (name == null || name.trim().equals("")) + throw new IllegalStateException("Class level Resource annotations must contain a name (Common Annotations Spec Section 2.3)"); - try - { - if (!org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_context, name,mappedName)) - if (!org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_context.getServer(), name,mappedName)) - throw new IllegalStateException("No resource at "+(mappedName==null?name:mappedName)); - } - catch (NamingException e) - { - LOG.warn(e); - } - } + try + { + if (!org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_context, name, mappedName)) + if (!org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_context.getServer(), name, mappedName)) + throw new IllegalStateException("No resource at " + (mappedName == null ? name : mappedName)); + } + catch (NamingException e) + { + LOG.warn(e); + } + } } public void handleField(Class clazz, Field field) { - Resource resource = (Resource)field.getAnnotation(Resource.class); + Resource resource = field.getAnnotation(Resource.class); if (resource != null) { //JavaEE Spec 5.2.3: Field cannot be static if (Modifier.isStatic(field.getModifiers())) { - LOG.warn("Skipping Resource annotation on "+clazz.getName()+"."+field.getName()+": cannot be static"); + LOG.warn("Skipping Resource annotation on " + clazz.getName() + "." + field.getName() + ": cannot be static"); return; } //JavaEE Spec 5.2.3: Field cannot be final if (Modifier.isFinal(field.getModifiers())) { - LOG.warn("Skipping Resource annotation on "+clazz.getName()+"."+field.getName()+": cannot be final"); + LOG.warn("Skipping Resource annotation on " + clazz.getName() + "." + field.getName() + ": cannot be final"); return; } //work out default name - String name = clazz.getCanonicalName()+"/"+field.getName(); + String name = clazz.getName() + "/" + field.getName(); //allow @Resource name= to override the field name - name = (resource.name()!=null && !resource.name().trim().equals("")? resource.name(): name); - String mappedName = (resource.mappedName()!=null && !resource.mappedName().trim().equals("")?resource.mappedName():null); + name = (resource.name() != null && !resource.name().trim().equals("") ? resource.name() : name); + String mappedName = (resource.mappedName() != null && !resource.mappedName().trim().equals("") ? resource.mappedName() : null); //get the type of the Field Class type = field.getType(); @@ -134,7 +138,7 @@ public class ResourceAnnotationHandler extends AbstractIntrospectableAnnotationH //If a descriptor has specified at least 1 injection target for this //resource, then it overrides this annotation MetaData metaData = _context.getMetaData(); - if (metaData.getOriginDescriptor("resource-ref."+name+".injection") != null) + if (metaData.getOriginDescriptor("resource-ref." + name + ".injection") != null) { //at least 1 injection was specified for this resource by a descriptor, so //it overrides this annotation @@ -159,15 +163,15 @@ public class ResourceAnnotationHandler extends AbstractIntrospectableAnnotationH if (!bound) bound = org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_context.getServer(), name, mappedName); if (!bound) - bound = org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(null, name, mappedName); + bound = org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(null, name, mappedName); if (!bound) { //see if there is an env-entry value been bound try { InitialContext ic = new InitialContext(); - String nameInEnvironment = (mappedName!=null?mappedName:name); - ic.lookup("java:comp/env/"+nameInEnvironment); + String nameInEnvironment = (mappedName != null ? mappedName : name); + ic.lookup("java:comp/env/" + nameInEnvironment); bound = true; } catch (NameNotFoundException e) @@ -178,16 +182,13 @@ public class ResourceAnnotationHandler extends AbstractIntrospectableAnnotationH //Check there is a JNDI entry for this annotation if (bound) { - LOG.debug("Bound "+(mappedName==null?name:mappedName) + " as "+ name); + LOG.debug("Bound " + (mappedName == null ? name : mappedName) + " as " + name); // Make the Injection for it if the binding succeeded - injection = new Injection(); - injection.setTarget(clazz, field, type); - injection.setJndiName(name); - injection.setMappingName(mappedName); + injection = new Injection(clazz, field, type, name, mappedName); injections.add(injection); //TODO - an @Resource is equivalent to a resource-ref, resource-env-ref, message-destination - metaData.setOrigin("resource-ref."+name+".injection",resource,clazz); + metaData.setOrigin("resource-ref." + name + ".injection", resource, clazz); } else if (!isEnvEntryType(type)) { @@ -195,7 +196,7 @@ public class ResourceAnnotationHandler extends AbstractIntrospectableAnnotationH //an error, it just means that perhaps the code will use a default value instead // JavaEE Spec. sec 5.4.1.3 - throw new IllegalStateException("No resource at "+(mappedName==null?name:mappedName)); + throw new IllegalStateException("No resource at " + (mappedName == null ? name : mappedName)); } } catch (NamingException e) @@ -210,20 +211,19 @@ public class ResourceAnnotationHandler extends AbstractIntrospectableAnnotationH } } - /** * Process a Resource annotation on a Method. *

    * This will generate a JNDI entry, and an Injection to be * processed when an instance of the class is created. - * - * @param clazz the class to process + * + * @param clazz the class to process * @param method the method to process */ public void handleMethod(Class clazz, Method method) { - Resource resource = (Resource)method.getAnnotation(Resource.class); + Resource resource = method.getAnnotation(Resource.class); if (resource != null) { /* @@ -246,7 +246,7 @@ public class ResourceAnnotationHandler extends AbstractIntrospectableAnnotationH //JavaEE Spec 5.2.3: Method cannot be static if (Modifier.isStatic(method.getModifiers())) { - LOG.warn("Skipping Resource annotation on "+clazz.getName()+"."+method.getName()+": cannot be static"); + LOG.warn("Skipping Resource annotation on " + clazz.getName() + "." + method.getName() + ": cannot be static"); return; } @@ -254,30 +254,29 @@ public class ResourceAnnotationHandler extends AbstractIntrospectableAnnotationH // only 1 parameter if (!method.getName().startsWith("set")) { - LOG.warn("Skipping Resource annotation on "+clazz.getName()+"."+method.getName()+": invalid java bean, does not start with 'set'"); + LOG.warn("Skipping Resource annotation on " + clazz.getName() + "." + method.getName() + ": invalid java bean, does not start with 'set'"); return; } if (method.getParameterCount() != 1) { - LOG.warn("Skipping Resource annotation on "+clazz.getName()+"."+method.getName()+": invalid java bean, not single argument to method"); + LOG.warn("Skipping Resource annotation on " + clazz.getName() + "." + method.getName() + ": invalid java bean, not single argument to method"); return; } if (Void.TYPE != method.getReturnType()) { - LOG.warn("Skipping Resource annotation on "+clazz.getName()+"."+method.getName()+": invalid java bean, not void"); + LOG.warn("Skipping Resource annotation on " + clazz.getName() + "." + method.getName() + ": invalid java bean, not void"); return; } - //default name is the javabean property name String name = method.getName().substring(3); - name = name.substring(0,1).toLowerCase(Locale.ENGLISH)+name.substring(1); - name = clazz.getCanonicalName()+"/"+name; + name = name.substring(0, 1).toLowerCase(Locale.ENGLISH) + name.substring(1); + name = clazz.getName() + "/" + name; - name = (resource.name()!=null && !resource.name().trim().equals("")? resource.name(): name); - String mappedName = (resource.mappedName()!=null && !resource.mappedName().trim().equals("")?resource.mappedName():null); + name = (resource.name() != null && !resource.name().trim().equals("") ? resource.name() : name); + String mappedName = (resource.mappedName() != null && !resource.mappedName().trim().equals("") ? resource.mappedName() : null); Class paramType = method.getParameterTypes()[0]; Class resourceType = resource.type(); @@ -286,7 +285,7 @@ public class ResourceAnnotationHandler extends AbstractIntrospectableAnnotationH //If a descriptor has specified at least 1 injection target for this //resource, then it overrides this annotation MetaData metaData = _context.getMetaData(); - if (metaData.getOriginDescriptor("resource-ref."+name+".injection") != null) + if (metaData.getOriginDescriptor("resource-ref." + name + ".injection") != null) { //at least 1 injection was specified for this resource by a descriptor, so //it overrides this annotation @@ -324,8 +323,8 @@ public class ResourceAnnotationHandler extends AbstractIntrospectableAnnotationH try { InitialContext ic = new InitialContext(); - String nameInEnvironment = (mappedName!=null?mappedName:name); - ic.lookup("java:comp/env/"+nameInEnvironment); + String nameInEnvironment = (mappedName != null ? mappedName : name); + ic.lookup("java:comp/env/" + nameInEnvironment); bound = true; } catch (NameNotFoundException e) @@ -336,15 +335,12 @@ public class ResourceAnnotationHandler extends AbstractIntrospectableAnnotationH if (bound) { - LOG.debug("Bound "+(mappedName==null?name:mappedName) + " as "+ name); + LOG.debug("Bound " + (mappedName == null ? name : mappedName) + " as " + name); // Make the Injection for it - injection = new Injection(); - injection.setTarget(clazz, method,paramType,resourceType); - injection.setJndiName(name); - injection.setMappingName(mappedName); + injection = new Injection(clazz, method, paramType, resourceType, name, mappedName); injections.add(injection); //TODO - an @Resource is equivalent to a resource-ref, resource-env-ref, message-destination - metaData.setOrigin("resource-ref."+name+".injection",resource,clazz); + metaData.setOrigin("resource-ref." + name + ".injection", resource, clazz); } else if (!isEnvEntryType(paramType)) { @@ -352,7 +348,7 @@ public class ResourceAnnotationHandler extends AbstractIntrospectableAnnotationH //if this is an env-entry type resource and there is no value bound for it, it isn't //an error, it just means that perhaps the code will use a default value instead // JavaEE Spec. sec 5.4.1.3 - throw new IllegalStateException("No resource at "+(mappedName==null?name:mappedName)); + throw new IllegalStateException("No resource at " + (mappedName == null ? name : mappedName)); } } catch (NamingException e) @@ -364,42 +360,38 @@ public class ResourceAnnotationHandler extends AbstractIntrospectableAnnotationH throw new IllegalStateException(e); } } - } } - + /** * Check if the given Class is one that the specification allows to have a Resource annotation. - * + * * @param c the class * @return true if Resource annotation permitted, false otherwise */ - public boolean supportsResourceInjection (Class c) + public boolean supportsResourceInjection(Class c) { - if (javax.servlet.Servlet.class.isAssignableFrom(c) || - javax.servlet.Filter.class.isAssignableFrom(c) || - javax.servlet.ServletContextListener.class.isAssignableFrom(c) || - javax.servlet.ServletContextAttributeListener.class.isAssignableFrom(c) || - javax.servlet.ServletRequestListener.class.isAssignableFrom(c) || - javax.servlet.ServletRequestAttributeListener.class.isAssignableFrom(c) || - javax.servlet.http.HttpSessionListener.class.isAssignableFrom(c) || - javax.servlet.http.HttpSessionAttributeListener.class.isAssignableFrom(c) || - javax.servlet.http.HttpSessionIdListener.class.isAssignableFrom(c) || - javax.servlet.AsyncListener.class.isAssignableFrom(c) || - javax.servlet.http.HttpUpgradeHandler.class.isAssignableFrom(c)) - return true; - - return false; + return javax.servlet.Servlet.class.isAssignableFrom(c) || + javax.servlet.Filter.class.isAssignableFrom(c) || + javax.servlet.ServletContextListener.class.isAssignableFrom(c) || + javax.servlet.ServletContextAttributeListener.class.isAssignableFrom(c) || + javax.servlet.ServletRequestListener.class.isAssignableFrom(c) || + javax.servlet.ServletRequestAttributeListener.class.isAssignableFrom(c) || + javax.servlet.http.HttpSessionListener.class.isAssignableFrom(c) || + javax.servlet.http.HttpSessionAttributeListener.class.isAssignableFrom(c) || + javax.servlet.http.HttpSessionIdListener.class.isAssignableFrom(c) || + javax.servlet.AsyncListener.class.isAssignableFrom(c) || + javax.servlet.http.HttpUpgradeHandler.class.isAssignableFrom(c); } - - + /** - * Check if the class is one of the basic java types permitted as + * Check if the class is one of the basic java types permitted as * env-entries. + * * @param clazz the class to check * @return true if class is permitted by the spec to be an env-entry value */ - public boolean isEnvEntryType (Class clazz) + public boolean isEnvEntryType(Class clazz) { return ENV_ENTRY_TYPES.contains(clazz); } diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ResourcesAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ResourcesAnnotationHandler.java index 9132a337f82..98dc9ef5e7d 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ResourcesAnnotationHandler.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ResourcesAnnotationHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -31,35 +31,34 @@ public class ResourcesAnnotationHandler extends AbstractIntrospectableAnnotation { private static final Logger LOG = Log.getLogger(ResourcesAnnotationHandler.class); - protected WebAppContext _wac; - public ResourcesAnnotationHandler (WebAppContext wac) + public ResourcesAnnotationHandler(WebAppContext wac) { super(true); _wac = wac; } - + @Override - public void doHandle (Class clazz) + public void doHandle(Class clazz) { - Resources resources = (Resources)clazz.getAnnotation(Resources.class); + Resources resources = clazz.getAnnotation(Resources.class); if (resources != null) { Resource[] resArray = resources.value(); - if (resArray==null||resArray.length==0) + if (resArray == null || resArray.length == 0) { - LOG.warn ("Skipping empty or incorrect Resources annotation on "+clazz.getName()); + LOG.warn("Skipping empty or incorrect Resources annotation on " + clazz.getName()); return; } - for (int j=0;j initializers = (List)_context.getAttribute(AnnotationConfiguration.CONTAINER_INITIALIZERS); if (initializers == null) return; - + for (ContainerInitializer i : initializers) { try { if (LOG.isDebugEnabled()) - LOG.debug("Calling ServletContainerInitializer "+i.getTarget().getClass().getName()); + LOG.debug("Calling ServletContainerInitializer " + i.getTarget().getClass().getName()); i.callStartup(_context); } catch (Exception e) diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletSecurityAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletSecurityAnnotationHandler.java index a4395036faf..5d8f739dcc1 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletSecurityAnnotationHandler.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletSecurityAnnotationHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,7 +20,6 @@ package org.eclipse.jetty.annotations; import java.util.ArrayList; import java.util.List; - import javax.servlet.ServletSecurityElement; import javax.servlet.annotation.ServletSecurity; import javax.servlet.annotation.ServletSecurity.EmptyRoleSemantic; @@ -78,66 +77,65 @@ public class ServletSecurityAnnotationHandler extends AbstractIntrospectableAnno return; } - ServletSecurity servletSecurity = (ServletSecurity)clazz.getAnnotation(ServletSecurity.class); - if (servletSecurity == null) - return; + ServletSecurity servletSecurity = (ServletSecurity)clazz.getAnnotation(ServletSecurity.class); + if (servletSecurity == null) + return; - //If there are already constraints defined (ie from web.xml) that match any - //of the url patterns defined for this servlet, then skip the security annotation. + //If there are already constraints defined (ie from web.xml) that match any + //of the url patterns defined for this servlet, then skip the security annotation. - List servletMappings = getServletMappings(clazz.getCanonicalName()); - List constraintMappings = ((ConstraintAware)_context.getSecurityHandler()).getConstraintMappings(); + List servletMappings = getServletMappings(clazz.getCanonicalName()); + List constraintMappings = ((ConstraintAware)_context.getSecurityHandler()).getConstraintMappings(); - if (constraintsExist(servletMappings, constraintMappings)) - { - LOG.warn("Constraints already defined for "+clazz.getName()+", skipping ServletSecurity annotation"); - return; - } + if (constraintsExist(servletMappings, constraintMappings)) + { + LOG.warn("Constraints already defined for " + clazz.getName() + ", skipping ServletSecurity annotation"); + return; + } - //Make a fresh list - constraintMappings = new ArrayList(); + //Make a fresh list + constraintMappings = new ArrayList(); - ServletSecurityElement securityElement = new ServletSecurityElement(servletSecurity); - for (ServletMapping sm : servletMappings) - { - for (String url : sm.getPathSpecs()) - { - _context.getMetaData().setOrigin("constraint.url."+url,servletSecurity,clazz); - constraintMappings.addAll(ConstraintSecurityHandler.createConstraintsWithMappingsForPath(clazz.getName(), url, securityElement)); - } - } + ServletSecurityElement securityElement = new ServletSecurityElement(servletSecurity); + for (ServletMapping sm : servletMappings) + { + for (String url : sm.getPathSpecs()) + { + _context.getMetaData().setOrigin("constraint.url." + url, servletSecurity, clazz); + constraintMappings.addAll(ConstraintSecurityHandler.createConstraintsWithMappingsForPath(clazz.getName(), url, securityElement)); + } + } - //set up the security constraints produced by the annotation - ConstraintAware securityHandler = (ConstraintAware)_context.getSecurityHandler(); + //set up the security constraints produced by the annotation + ConstraintAware securityHandler = (ConstraintAware)_context.getSecurityHandler(); - for (ConstraintMapping m:constraintMappings) - securityHandler.addConstraintMapping(m); - - //Servlet Spec 3.1 requires paths with uncovered http methods to be reported - securityHandler.checkPathsWithUncoveredHttpMethods(); + for (ConstraintMapping m : constraintMappings) + { + securityHandler.addConstraintMapping(m); + } + + //Servlet Spec 3.1 requires paths with uncovered http methods to be reported + securityHandler.checkPathsWithUncoveredHttpMethods(); } - - /** * Make a jetty Constraint object, which represents the <auth-constraint> and * <user-data-constraint> elements, based on the security annotation. - * + * * @param servlet the servlet * @param rolesAllowed the roles allowed * @param permitOrDeny the role / permission semantic * @param transport the transport guarantee * @return the constraint */ - protected Constraint makeConstraint (Class servlet, String[] rolesAllowed, EmptyRoleSemantic permitOrDeny, TransportGuarantee transport) + protected Constraint makeConstraint(Class servlet, String[] rolesAllowed, EmptyRoleSemantic permitOrDeny, TransportGuarantee transport) { return ConstraintSecurityHandler.createConstraint(servlet.getName(), rolesAllowed, permitOrDeny, transport); } - - /** * Get the ServletMappings for the servlet's class. + * * @param className the class name * @return the servlet mappings for the class */ @@ -150,22 +148,20 @@ public class ServletSecurityAnnotationHandler extends AbstractIntrospectableAnno //Check the name of the servlet that this mapping applies to, and then find the ServletHolder for it to find it's class ServletHolder holder = _context.getServletHandler().getServlet(mapping.getServletName()); if (holder.getClassName() != null && holder.getClassName().equals(className)) - results.add(mapping); + results.add(mapping); } return results; } - - /** * Check if there are already <security-constraint> elements defined that match the url-patterns for * the servlet. - * + * * @param servletMappings the servlet mappings * @param constraintMappings the constraint mappings * @return true if constraint exists */ - protected boolean constraintsExist (List servletMappings, List constraintMappings) + protected boolean constraintsExist(List servletMappings, List constraintMappings) { boolean exists = false; @@ -181,20 +177,19 @@ public class ServletSecurityAnnotationHandler extends AbstractIntrospectableAnno //Check through the constraints to see if there are any whose pathSpecs (url mappings) //match the servlet. If so, then we already have constraints defined for this servlet, //and we will not be processing the annotation (ie web.xml or programmatic override). - for (int i=0; constraintMappings != null && i < constraintMappings.size() && !exists; i++) - { - for (int j=0; j < pathSpecs.length; j++) - { - //TODO decide if we need to check the origin - if (pathSpecs[j].equals(constraintMappings.get(i).getPathSpec())) - { - exists = true; - break; - } - } - } + for (int i = 0; constraintMappings != null && i < constraintMappings.size() && !exists; i++) + { + for (int j = 0; j < pathSpecs.length; j++) + { + //TODO decide if we need to check the origin + if (pathSpecs[j].equals(constraintMappings.get(i).getPathSpec())) + { + exists = true; + break; + } + } + } } return exists; } - } diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebFilterAnnotation.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebFilterAnnotation.java index c7de61c8263..2813a3aabfc 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebFilterAnnotation.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebFilterAnnotation.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,7 +20,6 @@ package org.eclipse.jetty.annotations; import java.util.ArrayList; import java.util.EnumSet; - import javax.servlet.DispatcherType; import javax.servlet.Filter; import javax.servlet.annotation.WebFilter; @@ -49,7 +48,7 @@ public class WebFilterAnnotation extends DiscoveredAnnotation { super(context, className); } - + public WebFilterAnnotation(WebAppContext context, String className, Resource resource) { super(context, className, resource); @@ -66,15 +65,14 @@ public class WebFilterAnnotation extends DiscoveredAnnotation Class clazz = getTargetClass(); if (clazz == null) { - LOG.warn(_className+" cannot be loaded"); + LOG.warn(_className + " cannot be loaded"); return; } - //Servlet Spec 8.1.2 if (!Filter.class.isAssignableFrom(clazz)) { - LOG.warn(clazz.getName()+" is not assignable from javax.servlet.Filter"); + LOG.warn(clazz.getName() + " is not assignable from javax.servlet.Filter"); return; } MetaData metaData = _context.getMetaData(); @@ -83,11 +81,11 @@ public class WebFilterAnnotation extends DiscoveredAnnotation if (filterAnnotation.value().length > 0 && filterAnnotation.urlPatterns().length > 0) { - LOG.warn(clazz.getName()+" defines both @WebFilter.value and @WebFilter.urlPatterns"); + LOG.warn(clazz.getName() + " defines both @WebFilter.value and @WebFilter.urlPatterns"); return; } - String name = (filterAnnotation.filterName().equals("")?clazz.getName():filterAnnotation.filterName()); + String name = (filterAnnotation.filterName().equals("") ? clazz.getName() : filterAnnotation.filterName()); String[] urlPatterns = filterAnnotation.value(); if (urlPatterns.length == 0) urlPatterns = filterAnnotation.urlPatterns(); @@ -96,19 +94,19 @@ public class WebFilterAnnotation extends DiscoveredAnnotation if (holder == null) { //Filter with this name does not already exist, so add it - holder = _context.getServletHandler().newFilterHolder(new Source (Source.Origin.ANNOTATION, clazz.getName())); + holder = _context.getServletHandler().newFilterHolder(new Source(Source.Origin.ANNOTATION, clazz.getName())); holder.setName(name); holder.setHeldClass(clazz); - metaData.setOrigin(name+".filter.filter-class",filterAnnotation,clazz); + metaData.setOrigin(name + ".filter.filter-class", filterAnnotation, clazz); holder.setDisplayName(filterAnnotation.displayName()); - metaData.setOrigin(name+".filter.display-name",filterAnnotation,clazz); + metaData.setOrigin(name + ".filter.display-name", filterAnnotation, clazz); - for (WebInitParam ip: filterAnnotation.initParams()) + for (WebInitParam ip : filterAnnotation.initParams()) { holder.setInitParameter(ip.name(), ip.value()); - metaData.setOrigin(name+".filter.init-param."+ip.name(),ip,clazz); + metaData.setOrigin(name + ".filter.init-param." + ip.name(), ip, clazz); } FilterMapping mapping = new FilterMapping(); @@ -117,7 +115,7 @@ public class WebFilterAnnotation extends DiscoveredAnnotation if (urlPatterns.length > 0) { ArrayList paths = new ArrayList(); - for (String s:urlPatterns) + for (String s : urlPatterns) { paths.add(ServletPathSpec.normalize(s)); } @@ -140,10 +138,10 @@ public class WebFilterAnnotation extends DiscoveredAnnotation dispatcherSet.add(d); } mapping.setDispatcherTypes(dispatcherSet); - metaData.setOrigin(name+".filter.mappings",filterAnnotation,clazz); + metaData.setOrigin(name + ".filter.mappings", filterAnnotation, clazz); holder.setAsyncSupported(filterAnnotation.asyncSupported()); - metaData.setOrigin(name+".filter.async-supported",filterAnnotation,clazz); + metaData.setOrigin(name + ".filter.async-supported", filterAnnotation, clazz); _context.getServletHandler().addFilter(holder); _context.getServletHandler().addFilterMapping(mapping); @@ -155,13 +153,13 @@ public class WebFilterAnnotation extends DiscoveredAnnotation //they override the annotation. If it already has DispatcherType set, that //also overrides the annotation. Init-params are additive, but web.xml overrides //init-params of the same name. - for (WebInitParam ip: filterAnnotation.initParams()) + for (WebInitParam ip : filterAnnotation.initParams()) { //if (holder.getInitParameter(ip.name()) == null) - if (metaData.getOrigin(name+".filter.init-param."+ip.name())==Origin.NotSet) + if (metaData.getOrigin(name + ".filter.init-param." + ip.name()) == Origin.NotSet) { holder.setInitParameter(ip.name(), ip.value()); - metaData.setOrigin(name+".filter.init-param."+ip.name(),ip,clazz); + metaData.setOrigin(name + ".filter.init-param." + ip.name(), ip, clazz); } } @@ -169,7 +167,7 @@ public class WebFilterAnnotation extends DiscoveredAnnotation boolean mappingExists = false; if (mappings != null) { - for (FilterMapping m:mappings) + for (FilterMapping m : mappings) { if (m.getFilterName().equals(name)) { @@ -188,7 +186,7 @@ public class WebFilterAnnotation extends DiscoveredAnnotation if (urlPatterns.length > 0) { ArrayList paths = new ArrayList(); - for (String s:urlPatterns) + for (String s : urlPatterns) { paths.add(ServletPathSpec.normalize(s)); } @@ -211,9 +209,8 @@ public class WebFilterAnnotation extends DiscoveredAnnotation } mapping.setDispatcherTypes(dispatcherSet); _context.getServletHandler().addFilterMapping(mapping); - metaData.setOrigin(name+".filter.mappings",filterAnnotation,clazz); + metaData.setOrigin(name + ".filter.mappings", filterAnnotation, clazz); } } } - } diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebFilterAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebFilterAnnotationHandler.java index 1718a4feb2c..c9b52069c87 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebFilterAnnotationHandler.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebFilterAnnotationHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -27,42 +27,39 @@ import org.eclipse.jetty.webapp.WebAppContext; /** * WebFilterAnnotationHandler - * - * */ public class WebFilterAnnotationHandler extends AbstractDiscoverableAnnotationHandler { private static final Logger LOG = Log.getLogger(WebFilterAnnotationHandler.class); - public WebFilterAnnotationHandler (WebAppContext context) + public WebFilterAnnotationHandler(WebAppContext context) { super(context); } - - + @Override public void handle(ClassInfo info, String annotationName) { if (annotationName == null || !"javax.servlet.annotation.WebFilter".equals(annotationName)) return; - + WebFilterAnnotation wfAnnotation = new WebFilterAnnotation(_context, info.getClassName(), info.getContainingResource()); addAnnotation(wfAnnotation); } @Override public void handle(FieldInfo info, String annotationName) - { + { if (annotationName == null || !"javax.servlet.annotation.WebFilter".equals(annotationName)) return; - LOG.warn ("@WebFilter not applicable for fields: "+info.getClassInfo().getClassName()+"."+info.getFieldName()); + LOG.warn("@WebFilter not applicable for fields: " + info.getClassInfo().getClassName() + "." + info.getFieldName()); } @Override public void handle(MethodInfo info, String annotationName) - { + { if (annotationName == null || !"javax.servlet.annotation.WebFilter".equals(annotationName)) return; - LOG.warn ("@WebFilter not applicable for methods: "+info.getClassInfo().getClassName()+"."+info.getMethodName()+" "+info.getSignature()); + LOG.warn("@WebFilter not applicable for methods: " + info.getClassInfo().getClassName() + "." + info.getMethodName() + " " + info.getSignature()); } } diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotation.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotation.java index 5478d5637ab..f00341d0e1b 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotation.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotation.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,7 +19,6 @@ package org.eclipse.jetty.annotations; import java.util.EventListener; - import javax.servlet.ServletContextAttributeListener; import javax.servlet.ServletContextListener; import javax.servlet.ServletRequestAttributeListener; @@ -49,7 +48,7 @@ public class WebListenerAnnotation extends DiscoveredAnnotation { super(context, className); } - + public WebListenerAnnotation(WebAppContext context, String className, Resource resource) { super(context, className, resource); @@ -65,32 +64,30 @@ public class WebListenerAnnotation extends DiscoveredAnnotation if (clazz == null) { - LOG.warn(_className+" cannot be loaded"); + LOG.warn(_className + " cannot be loaded"); return; } try { if (ServletContextListener.class.isAssignableFrom(clazz) || - ServletContextAttributeListener.class.isAssignableFrom(clazz) || - ServletRequestListener.class.isAssignableFrom(clazz) || - ServletRequestAttributeListener.class.isAssignableFrom(clazz) || - HttpSessionListener.class.isAssignableFrom(clazz) || - HttpSessionAttributeListener.class.isAssignableFrom(clazz) || - HttpSessionIdListener.class.isAssignableFrom(clazz)) + ServletContextAttributeListener.class.isAssignableFrom(clazz) || + ServletRequestListener.class.isAssignableFrom(clazz) || + ServletRequestAttributeListener.class.isAssignableFrom(clazz) || + HttpSessionListener.class.isAssignableFrom(clazz) || + HttpSessionAttributeListener.class.isAssignableFrom(clazz) || + HttpSessionIdListener.class.isAssignableFrom(clazz)) { - MetaData metaData = _context.getMetaData(); - if (metaData.getOrigin(clazz.getName()+".listener") == Origin.NotSet) + MetaData metaData = _context.getMetaData(); + if (metaData.getOrigin(clazz.getName() + ".listener") == Origin.NotSet) { - java.util.EventListener listener = (java.util.EventListener)_context.getServletContext().createInstance(clazz); ListenerHolder h = _context.getServletHandler().newListenerHolder(new Source(Source.Origin.ANNOTATION, clazz.getName())); - h.setListener(listener); + h.setHeldClass(clazz); _context.getServletHandler().addListener(h); - _context.addEventListener(listener); } } else - LOG.warn(clazz.getName()+" does not implement one of the servlet listener interfaces"); + LOG.warn(clazz.getName() + " does not implement one of the servlet listener interfaces"); } catch (Exception e) { diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotationHandler.java index 441d1441627..b091ef70fb7 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotationHandler.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotationHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -29,17 +29,17 @@ public class WebListenerAnnotationHandler extends AbstractDiscoverableAnnotation { private static final Logger LOG = Log.getLogger(WebListenerAnnotationHandler.class); - public WebListenerAnnotationHandler (WebAppContext context) + public WebListenerAnnotationHandler(WebAppContext context) { - super(context); + super(context); } - + @Override public void handle(ClassInfo info, String annotationName) { if (annotationName == null || !"javax.servlet.annotation.WebListener".equals(annotationName)) return; - + WebListenerAnnotation wlAnnotation = new WebListenerAnnotation(_context, info.getClassName(), info.getContainingResource()); addAnnotation(wlAnnotation); } @@ -49,7 +49,7 @@ public class WebListenerAnnotationHandler extends AbstractDiscoverableAnnotation { if (annotationName == null || !"javax.servlet.annotation.WebListener".equals(annotationName)) return; - LOG.warn ("@WebListener is not applicable to fields: "+info.getClassInfo().getClassName()+"."+info.getFieldName()); + LOG.warn("@WebListener is not applicable to fields: " + info.getClassInfo().getClassName() + "." + info.getFieldName()); } @Override @@ -57,6 +57,6 @@ public class WebListenerAnnotationHandler extends AbstractDiscoverableAnnotation { if (annotationName == null || !"javax.servlet.annotation.WebListener".equals(annotationName)) return; - LOG.warn ("@WebListener is not applicable to methods: "+info.getClassInfo().getClassName()+"."+info.getMethodName()+" "+info.getSignature()); + LOG.warn("@WebListener is not applicable to methods: " + info.getClassInfo().getClassName() + "." + info.getMethodName() + " " + info.getSignature()); } } diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotation.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotation.java index 940adba4f07..d1cb770998a 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotation.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotation.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -21,14 +21,12 @@ package org.eclipse.jetty.annotations; import java.util.ArrayList; import java.util.Collections; import java.util.List; - import javax.servlet.Servlet; import javax.servlet.annotation.WebInitParam; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import org.eclipse.jetty.http.pathmap.ServletPathSpec; -import org.eclipse.jetty.servlet.Holder; import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.servlet.ServletMapping; import org.eclipse.jetty.servlet.Source; @@ -44,20 +42,17 @@ import org.eclipse.jetty.webapp.WebAppContext; /** * WebServletAnnotation - * - * */ public class WebServletAnnotation extends DiscoveredAnnotation { private static final Logger LOG = Log.getLogger(WebServletAnnotation.class); - public WebServletAnnotation (WebAppContext context, String className) + public WebServletAnnotation(WebAppContext context, String className) { super(context, className); } - - public WebServletAnnotation (WebAppContext context, String className, Resource resource) + public WebServletAnnotation(WebAppContext context, String className, Resource resource) { super(context, className, resource); } @@ -73,22 +68,22 @@ public class WebServletAnnotation extends DiscoveredAnnotation if (clazz == null) { - LOG.warn(_className+" cannot be loaded"); + LOG.warn(_className + " cannot be loaded"); return; } //Servlet Spec 8.1.1 if (!HttpServlet.class.isAssignableFrom(clazz)) { - LOG.warn(clazz.getName()+" is not assignable from javax.servlet.http.HttpServlet"); + LOG.warn(clazz.getName() + " is not assignable from javax.servlet.http.HttpServlet"); return; } - WebServlet annotation = (WebServlet)clazz.getAnnotation(WebServlet.class); + WebServlet annotation = clazz.getAnnotation(WebServlet.class); if (annotation.urlPatterns().length > 0 && annotation.value().length > 0) { - LOG.warn(clazz.getName()+ " defines both @WebServlet.value and @WebServlet.urlPatterns"); + LOG.warn(clazz.getName() + " defines both @WebServlet.value and @WebServlet.urlPatterns"); return; } @@ -98,16 +93,18 @@ public class WebServletAnnotation extends DiscoveredAnnotation if (urlPatterns.length == 0) { - LOG.warn(clazz.getName()+ " defines neither @WebServlet.value nor @WebServlet.urlPatterns"); + LOG.warn(clazz.getName() + " defines neither @WebServlet.value nor @WebServlet.urlPatterns"); return; } //canonicalize the patterns ArrayList urlPatternList = new ArrayList(); for (String p : urlPatterns) + { urlPatternList.add(ServletPathSpec.normalize(p)); + } - String servletName = (annotation.name().equals("")?clazz.getName():annotation.name()); + String servletName = (annotation.name().equals("") ? clazz.getName() : annotation.name()); MetaData metaData = _context.getMetaData(); ServletMapping mapping = null; //the new mapping @@ -134,33 +131,32 @@ public class WebServletAnnotation extends DiscoveredAnnotation //No servlet of this name has already been defined, either by a descriptor //or another annotation (which would be impossible). Source source = new Source(Source.Origin.ANNOTATION, clazz.getName()); - + holder = _context.getServletHandler().newServletHolder(source); holder.setHeldClass(clazz); - metaData.setOrigin(servletName+".servlet.servlet-class",annotation,clazz); + metaData.setOrigin(servletName + ".servlet.servlet-class", annotation, clazz); holder.setName(servletName); holder.setDisplayName(annotation.displayName()); - metaData.setOrigin(servletName+".servlet.display-name",annotation,clazz); + metaData.setOrigin(servletName + ".servlet.display-name", annotation, clazz); holder.setInitOrder(annotation.loadOnStartup()); - metaData.setOrigin(servletName+".servlet.load-on-startup",annotation,clazz); + metaData.setOrigin(servletName + ".servlet.load-on-startup", annotation, clazz); holder.setAsyncSupported(annotation.asyncSupported()); - metaData.setOrigin(servletName+".servlet.async-supported",annotation,clazz); + metaData.setOrigin(servletName + ".servlet.async-supported", annotation, clazz); - for (WebInitParam ip:annotation.initParams()) + for (WebInitParam ip : annotation.initParams()) { holder.setInitParameter(ip.name(), ip.value()); - metaData.setOrigin(servletName+".servlet.init-param."+ip.name(),ip,clazz); + metaData.setOrigin(servletName + ".servlet.init-param." + ip.name(), ip, clazz); } _context.getServletHandler().addServlet(holder); - mapping = new ServletMapping(source); mapping.setServletName(holder.getName()); - mapping.setPathSpecs( LazyList.toStringArray(urlPatternList)); + mapping.setPathSpecs(LazyList.toStringArray(urlPatternList)); } else { @@ -175,16 +171,15 @@ public class WebServletAnnotation extends DiscoveredAnnotation //check if the existing servlet has each init-param from the annotation //if not, add it - for (WebInitParam ip:annotation.initParams()) + for (WebInitParam ip : annotation.initParams()) { - if (metaData.getOrigin(servletName+".servlet.init-param."+ip.name())==Origin.NotSet) + if (metaData.getOrigin(servletName + ".servlet.init-param." + ip.name()) == Origin.NotSet) { holder.setInitParameter(ip.name(), ip.value()); - metaData.setOrigin(servletName+".servlet.init-param."+ip.name(),ip,clazz); + metaData.setOrigin(servletName + ".servlet.init-param." + ip.name(), ip, clazz); } } - //check the url-patterns //ServletSpec 3.0 p81 If a servlet already has url mappings from a //webxml or fragment descriptor the annotation is ignored. @@ -201,7 +196,6 @@ public class WebServletAnnotation extends DiscoveredAnnotation } } - //We also want to be able to replace mappings that were defined in webdefault.xml //that were for a different servlet eg a mapping in webdefault.xml for / to the jetty //default servlet should be able to be replaced by an annotation for / to a different @@ -217,7 +211,7 @@ public class WebServletAnnotation extends DiscoveredAnnotation //for each of the urls in the annotation, check if a mapping to same/different servlet exists // if mapping exists and is from a default descriptor, it can be replaced. NOTE: we do not // guard against duplicate path mapping here: that is the job of the ServletHandler - for (String p:urlPatternList) + for (String p : urlPatternList) { ServletMapping existingMapping = _context.getServletHandler().getServletMapping(p); if (existingMapping != null && existingMapping.isDefault()) @@ -227,36 +221,34 @@ public class WebServletAnnotation extends DiscoveredAnnotation if (updatedPaths == null || updatedPaths.length == 0) { boolean success = allMappings.remove(existingMapping); - if (LOG.isDebugEnabled()) LOG.debug("Removed empty mapping {} from defaults descriptor success:{}",existingMapping, success); + if (LOG.isDebugEnabled()) + LOG.debug("Removed empty mapping {} from defaults descriptor success:{}", existingMapping, success); } else { existingMapping.setPathSpecs(updatedPaths); - if (LOG.isDebugEnabled()) LOG.debug("Removed path {} from mapping {} from defaults descriptor ", p,existingMapping); + if (LOG.isDebugEnabled()) + LOG.debug("Removed path {} from mapping {} from defaults descriptor ", p, existingMapping); } } - _context.getMetaData().setOrigin(servletName+".servlet.mapping."+p, annotation, clazz); + _context.getMetaData().setOrigin(servletName + ".servlet.mapping." + p, annotation, clazz); } allMappings.add(mapping); _context.getServletHandler().setServletMappings(allMappings.toArray(new ServletMapping[allMappings.size()])); } } - - - /** - * @param name - * @return + * */ - private List getServletMappingsForServlet (String name) + private List getServletMappingsForServlet(String name) { ServletMapping[] allMappings = _context.getServletHandler().getServletMappings(); if (allMappings == null) return Collections.emptyList(); List mappings = new ArrayList(); - for (ServletMapping m:allMappings) + for (ServletMapping m : allMappings) { if (m.getServletName() != null && name.equals(m.getServletName())) { @@ -266,16 +258,14 @@ public class WebServletAnnotation extends DiscoveredAnnotation return mappings; } - /** - * @param mappings - * @return + * */ - private boolean containsNonDefaultMappings (List mappings) + private boolean containsNonDefaultMappings(List mappings) { if (mappings == null) return false; - for (ServletMapping m:mappings) + for (ServletMapping m : mappings) { if (!m.isDefault()) return true; diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotationHandler.java index b7e392a3904..fa8cfc046cc 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotationHandler.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotationHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -34,12 +34,11 @@ public class WebServletAnnotationHandler extends AbstractDiscoverableAnnotationH { private static final Logger LOG = Log.getLogger(WebServletAnnotationHandler.class); - public WebServletAnnotationHandler (WebAppContext context) + public WebServletAnnotationHandler(WebAppContext context) { super(context); } - /** * Handle discovering a WebServlet annotation. */ @@ -48,8 +47,8 @@ public class WebServletAnnotationHandler extends AbstractDiscoverableAnnotationH { if (annotationName == null || !"javax.servlet.annotation.WebServlet".equals(annotationName)) return; - - WebServletAnnotation annotation = new WebServletAnnotation (_context, info.getClassName(), info.getContainingResource()); + + WebServletAnnotation annotation = new WebServletAnnotation(_context, info.getClassName(), info.getContainingResource()); addAnnotation(annotation); } @@ -58,8 +57,8 @@ public class WebServletAnnotationHandler extends AbstractDiscoverableAnnotationH { if (annotationName == null || !"javax.servlet.annotation.WebServlet".equals(annotationName)) return; - - LOG.warn ("@WebServlet annotation not supported for fields"); + + LOG.warn("@WebServlet annotation not supported for fields"); } @Override @@ -67,7 +66,7 @@ public class WebServletAnnotationHandler extends AbstractDiscoverableAnnotationH { if (annotationName == null || !"javax.servlet.annotation.WebServlet".equals(annotationName)) return; - - LOG.warn ("@WebServlet annotation not supported for methods"); + + LOG.warn("@WebServlet annotation not supported for methods"); } } diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/package-info.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/package-info.java index f2f977059f1..036baf0b38e 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/package-info.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,4 +20,3 @@ * Jetty Annotations : Support for Servlet Annotations */ package org.eclipse.jetty.annotations; - diff --git a/jetty-annotations/src/test/jar/test-sci-for-container-path.jar b/jetty-annotations/src/test/jar/test-sci-for-container-path.jar new file mode 100644 index 00000000000..d6fa63a78d6 Binary files /dev/null and b/jetty-annotations/src/test/jar/test-sci-for-container-path.jar differ diff --git a/jetty-annotations/src/test/jar/test-sci-with-ordering.jar b/jetty-annotations/src/test/jar/test-sci-with-ordering.jar new file mode 100644 index 00000000000..7e1d8fc847b Binary files /dev/null and b/jetty-annotations/src/test/jar/test-sci-with-ordering.jar differ diff --git a/jetty-annotations/src/test/java/org/acme/ClassOne.java b/jetty-annotations/src/test/java/org/acme/ClassOne.java index 6c36e0c2510..41c94e75d5f 100644 --- a/jetty-annotations/src/test/java/org/acme/ClassOne.java +++ b/jetty-annotations/src/test/java/org/acme/ClassOne.java @@ -1,7 +1,6 @@ -package org.acme; // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -17,13 +16,10 @@ package org.acme; // ======================================================================== // - - +package org.acme; /** * ClassOne - * - * */ public class ClassOne { @@ -31,5 +27,4 @@ public class ClassOne public void one() { } - } diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ClassA.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ClassA.java index b77e04cc684..26691a57395 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ClassA.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ClassA.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,11 +18,8 @@ package org.eclipse.jetty.annotations; - /** * ClassA - * - * */ @Sample(1) public class ClassA @@ -34,27 +31,26 @@ public class ClassA private Integer j; private Integer k; - public static class Foo { - + } - + @Sample(7) private Integer m; - + @Sample(2) - public void a (Integer[] x) + public void a(Integer[] x) { System.err.println("ClassA.public"); } - + @Sample(3) protected void b(Foo[] f) { System.err.println("ClassA.protected"); } - + @Sample(4) void c(int[] x) { @@ -66,7 +62,7 @@ public class ClassA { System.err.println("ClassA.private"); } - + @Sample(6) protected void l() { @@ -77,22 +73,22 @@ public class ClassA { return this.e; } - + public Integer getF() { return this.f; } - + public Integer getG() { return this.g; } - + public Integer getJ() { return this.j; } - + public void x() { System.err.println("ClassA.x"); diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ClassB.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ClassB.java index b83a56ec793..3e8b6947bee 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ClassB.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ClassB.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,44 +18,38 @@ package org.eclipse.jetty.annotations; - - /** * ClassB - * - * */ -@Sample(value=50) +@Sample(value = 50) @Multi({"do", "re", "mi"}) public class ClassB extends ClassA implements InterfaceD { //test override of public scope method - @Sample(value=51) + @Sample(value = 51) @Multi({"fa", "so", "la"}) public void a() { - System.err.println("ClassB.public"); + System.err.println("ClassB.public"); } - + //test override of package scope method - @Sample(value=52) + @Sample(value = 52) void c() { System.err.println("ClassB.package"); } - + @Override public void l() { System.err.println("Overridden method l has no annotation"); } - - + //test no annotation public void z() { System.err.println("ClassB.z"); } - } diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/FilterC.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/FilterC.java index 2f61d74d6b4..42202e5972b 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/FilterC.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/FilterC.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,7 +19,6 @@ package org.eclipse.jetty.annotations; import java.io.IOException; - import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.annotation.Resource; @@ -37,15 +36,17 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; -@WebFilter(filterName="CFilter", dispatcherTypes={DispatcherType.REQUEST}, urlPatterns = {"/*"}, initParams={@WebInitParam(name="a", value="99")}, asyncSupported=false) +@WebFilter(filterName = "CFilter", dispatcherTypes = {DispatcherType.REQUEST}, urlPatterns = {"/*"}, initParams = { + @WebInitParam(name = "a", value = "99") + }, asyncSupported = false) @RunAs("admin") public class FilterC implements Filter { - @Resource (mappedName="foo") + @Resource(mappedName = "foo") private Double foo; @PreDestroy - public void pre () + public void pre() { } @@ -56,16 +57,15 @@ public class FilterC implements Filter } - @Override public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) - throws IOException, ServletException + throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest)arg0; HttpServletResponse response = (HttpServletResponse)arg1; HttpSession session = request.getSession(true); String val = request.getParameter("action"); - if (val!=null) + if (val != null) session.setAttribute("action", val); arg2.doFilter(request, response); } diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/InterfaceD.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/InterfaceD.java index 8f9a772bb8f..5ad229843a1 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/InterfaceD.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/InterfaceD.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,8 +20,6 @@ package org.eclipse.jetty.annotations; /** * InterfaceD - * - * */ public interface InterfaceD { diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ListenerC.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ListenerC.java index 7f33ae760b0..b2c426f7988 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ListenerC.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ListenerC.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -29,13 +29,12 @@ public class ListenerC implements ServletContextListener @Override public void contextDestroyed(ServletContextEvent arg0) { - + } @Override public void contextInitialized(ServletContextEvent arg0) { - - } + } } diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/Multi.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/Multi.java index d67ee5c6acf..353a982fc57 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/Multi.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/Multi.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -25,9 +25,7 @@ import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) -public @interface Multi +public @interface Multi { String[] value(); } - - diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/Sample.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/Sample.java index 4c3c5443a11..b46be21ece5 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/Sample.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/Sample.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -25,8 +25,7 @@ import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) -public @interface Sample +public @interface Sample { int value(); } - diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ServletC.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ServletC.java index 25124475ea5..52f7328fc7c 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ServletC.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ServletC.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,7 +19,6 @@ package org.eclipse.jetty.annotations; import java.io.IOException; - import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.annotation.Resource; @@ -37,17 +36,22 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @DeclareRoles({"alice"}) -@WebServlet(urlPatterns = { "/foo/*", "/bah/*" }, name="CServlet", initParams={@WebInitParam(name="x", value="y")}, loadOnStartup=2, asyncSupported=false) -@MultipartConfig(fileSizeThreshold=1000, maxFileSize=2000, maxRequestSize=3000) +@WebServlet(urlPatterns = {"/foo/*", "/bah/*"}, name = "CServlet", initParams = { + @WebInitParam(name = "x", value = "y") + }, loadOnStartup = 2, asyncSupported = false) +@MultipartConfig(fileSizeThreshold = 1000, maxFileSize = 2000, maxRequestSize = 3000) @RunAs("admin") -@ServletSecurity(value=@HttpConstraint(rolesAllowed={"fred", "bill", "dorothy"}), httpMethodConstraints={@HttpMethodConstraint(value="GET", rolesAllowed={"bob", "carol", "ted"})}) +@ServletSecurity(value = @HttpConstraint(rolesAllowed = {"fred", "bill", "dorothy"}), httpMethodConstraints = { + @HttpMethodConstraint(value = "GET", rolesAllowed = + {"bob", "carol", "ted"}) +}) public class ServletC extends HttpServlet { - @Resource (mappedName="foo", type=Double.class) + @Resource(mappedName = "foo", type = Double.class) private Double foo; @PreDestroy - public void pre () + public void pre() { } diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ServletD.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ServletD.java index c5e5c9e8c8e..924c7557021 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ServletD.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ServletD.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -22,10 +22,10 @@ import javax.servlet.annotation.WebInitParam; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; - - -@WebServlet(urlPatterns = { "/", "/bah/*" }, name="DServlet", initParams={@WebInitParam(name="x", value="y")}, loadOnStartup=1, asyncSupported=false) +@WebServlet(urlPatterns = {"/", "/bah/*"}, name = "DServlet", initParams = { + @WebInitParam(name = "x", value = "y") + }, loadOnStartup = 1, asyncSupported = false) public class ServletD extends HttpServlet { - + // no op } diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationConfiguration.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationConfiguration.java index 4a0b25f79ce..5ea2d91f06c 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationConfiguration.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationConfiguration.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,57 +18,51 @@ package org.eclipse.jetty.annotations; -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.assertTrue; - import java.io.File; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; +import java.util.Collections; import java.util.List; -import java.util.Set; - import javax.servlet.ServletContainerInitializer; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.webapp.FragmentDescriptor; +import org.eclipse.jetty.webapp.RelativeOrdering; import org.eclipse.jetty.webapp.WebAppContext; 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.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + /** * TestAnnotationConfiguration - * - * */ public class TestAnnotationConfiguration { - + public class TestableAnnotationConfiguration extends AnnotationConfiguration { - public void assertAnnotationDiscovery (boolean b) + public void assertAnnotationDiscovery(boolean b) { - + if (!b) assertTrue(_discoverableAnnotationHandlers.isEmpty()); else assertFalse(_discoverableAnnotationHandlers.isEmpty()); } } - - + @Test public void testAnnotationScanControl() throws Exception - { + { File web25 = MavenTestingUtils.getTestResourceFile("web25.xml"); File web31true = MavenTestingUtils.getTestResourceFile("web31true.xml"); File web31false = MavenTestingUtils.getTestResourceFile("web31false.xml"); - - + //check that a 2.5 webapp won't discover annotations TestableAnnotationConfiguration config25 = new TestableAnnotationConfiguration(); WebAppContext context25 = new WebAppContext(); @@ -80,131 +74,208 @@ public class TestAnnotationConfiguration context25.getServletContext().setEffectiveMinorVersion(5); config25.configure(context25); config25.assertAnnotationDiscovery(false); - + //check that a 2.5 webapp with configurationDiscovered will discover annotations TestableAnnotationConfiguration config25b = new TestableAnnotationConfiguration(); WebAppContext context25b = new WebAppContext(); context25b.setClassLoader(Thread.currentThread().getContextClassLoader()); context25b.setAttribute(AnnotationConfiguration.MULTI_THREADED, Boolean.FALSE); - context25b.setAttribute(AnnotationConfiguration.MAX_SCAN_WAIT, new Integer(0)); + context25b.setAttribute(AnnotationConfiguration.MAX_SCAN_WAIT, new Integer(0)); context25b.setConfigurationDiscovered(true); context25b.getMetaData().setWebXml(Resource.newResource(web25)); context25b.getServletContext().setEffectiveMajorVersion(2); context25b.getServletContext().setEffectiveMinorVersion(5); config25b.configure(context25b); config25b.assertAnnotationDiscovery(true); - + //check that a 3.x webapp with metadata true won't discover annotations TestableAnnotationConfiguration config31 = new TestableAnnotationConfiguration(); WebAppContext context31 = new WebAppContext(); context31.setClassLoader(Thread.currentThread().getContextClassLoader()); context31.setAttribute(AnnotationConfiguration.MULTI_THREADED, Boolean.FALSE); - context31.setAttribute(AnnotationConfiguration.MAX_SCAN_WAIT, new Integer(0)); + context31.setAttribute(AnnotationConfiguration.MAX_SCAN_WAIT, new Integer(0)); context31.getMetaData().setWebXml(Resource.newResource(web31true)); context31.getServletContext().setEffectiveMajorVersion(3); context31.getServletContext().setEffectiveMinorVersion(1); config31.configure(context31); config31.assertAnnotationDiscovery(false); - + //check that a 3.x webapp with metadata false will discover annotations TestableAnnotationConfiguration config31b = new TestableAnnotationConfiguration(); WebAppContext context31b = new WebAppContext(); context31b.setClassLoader(Thread.currentThread().getContextClassLoader()); context31b.setAttribute(AnnotationConfiguration.MULTI_THREADED, Boolean.FALSE); - context31b.setAttribute(AnnotationConfiguration.MAX_SCAN_WAIT, new Integer(0)); + context31b.setAttribute(AnnotationConfiguration.MAX_SCAN_WAIT, new Integer(0)); context31b.getMetaData().setWebXml(Resource.newResource(web31false)); context31b.getServletContext().setEffectiveMajorVersion(3); context31b.getServletContext().setEffectiveMinorVersion(1); config31b.configure(context31b); config31b.assertAnnotationDiscovery(true); } - + @Test - public void testSCIControl () - throws Exception - { + public void testSCIControl() + throws Exception + { File web25 = MavenTestingUtils.getTestResourceFile("web25.xml"); File web31false = MavenTestingUtils.getTestResourceFile("web31false.xml"); File web31true = MavenTestingUtils.getTestResourceFile("web31true.xml"); - Set sciNames = new HashSet<>(Arrays.asList("org.eclipse.jetty.annotations.ServerServletContainerInitializer", "com.acme.initializer.FooInitializer")); - + //prepare an sci that will be on the webapp's classpath File jarDir = new File(MavenTestingUtils.getTestResourcesDir().getParentFile(), "jar"); File testSciJar = new File(jarDir, "test-sci.jar"); - assertTrue(testSciJar.exists()); - URLClassLoader webAppLoader = new URLClassLoader(new URL[] {testSciJar.toURI().toURL()}, Thread.currentThread().getContextClassLoader()); - - //test 3.1 webapp loads both server and app scis - AnnotationConfiguration config = new AnnotationConfiguration(); - WebAppContext context = new WebAppContext(); - context.setClassLoader(webAppLoader); - context.getMetaData().setWebXml(Resource.newResource(web31true)); - context.getServletContext().setEffectiveMajorVersion(3); - context.getServletContext().setEffectiveMinorVersion(1); - List scis = config.getNonExcludedInitializers(context); - assertNotNull(scis); - assertEquals(2, scis.size()); - assertTrue (sciNames.contains(scis.get(0).getClass().getName())); - assertTrue (sciNames.contains(scis.get(1).getClass().getName())); - - //test a 3.1 webapp with metadata-complete=false loads both server and webapp scis - config = new AnnotationConfiguration(); - context = new WebAppContext(); - context.setClassLoader(webAppLoader); - context.getMetaData().setWebXml(Resource.newResource(web31false)); - context.getServletContext().setEffectiveMajorVersion(3); - context.getServletContext().setEffectiveMinorVersion(1); - scis = config.getNonExcludedInitializers(context); - assertNotNull(scis); - assertEquals(2, scis.size()); - assertTrue (sciNames.contains(scis.get(0).getClass().getName())); - assertTrue (sciNames.contains(scis.get(1).getClass().getName())); - - - //test 2.5 webapp with configurationDiscovered=false loads only server scis - config = new AnnotationConfiguration(); - context = new WebAppContext(); - context.setClassLoader(webAppLoader); - context.getMetaData().setWebXml(Resource.newResource(web25)); - context.getServletContext().setEffectiveMajorVersion(2); - context.getServletContext().setEffectiveMinorVersion(5); - scis = config.getNonExcludedInitializers(context); - assertNotNull(scis); - assertEquals(1, scis.size()); - assertTrue ("org.eclipse.jetty.annotations.ServerServletContainerInitializer".equals(scis.get(0).getClass().getName())); - - //test 2.5 webapp with configurationDiscovered=true loads both server and webapp scis - config = new AnnotationConfiguration(); - context = new WebAppContext(); - context.setConfigurationDiscovered(true); - context.setClassLoader(webAppLoader); - context.getMetaData().setWebXml(Resource.newResource(web25)); - context.getServletContext().setEffectiveMajorVersion(2); - context.getServletContext().setEffectiveMinorVersion(5); - scis = config.getNonExcludedInitializers(context); - assertNotNull(scis); - assertEquals(2, scis.size()); - assertTrue (sciNames.contains(scis.get(0).getClass().getName())); - assertTrue (sciNames.contains(scis.get(1).getClass().getName())); + assertTrue(testSciJar.exists()); + + File testContainerSciJar = new File(jarDir, "test-sci-for-container-path.jar"); + URLClassLoader containerLoader = new URLClassLoader(new URL[]{ + testContainerSciJar.toURI().toURL() + }, Thread.currentThread().getContextClassLoader()); + URLClassLoader webAppLoader = new URLClassLoader(new URL[]{testSciJar.toURI().toURL()}, containerLoader); + Resource targetClasses = Resource.newResource(MavenTestingUtils.getTargetDir().toURI()).addPath("/test-classes"); + + ClassLoader old = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(containerLoader); + try + { + + AnnotationConfiguration config = new AnnotationConfiguration(); + WebAppContext context = new WebAppContext(); + List scis; + + //test 3.1 webapp loads both server and app scis + context.setClassLoader(webAppLoader); + context.getMetaData().addWebInfJar(Resource.newResource(testSciJar.toURI().toURL())); + context.getMetaData().setWebXml(Resource.newResource(web31true)); + context.getMetaData().setWebInfClassesDirs(Collections.singletonList(targetClasses)); + context.getServletContext().setEffectiveMajorVersion(3); + context.getServletContext().setEffectiveMinorVersion(1); + scis = config.getNonExcludedInitializers(context); + assertNotNull(scis); + assertEquals(3, scis.size()); + assertEquals("com.acme.ServerServletContainerInitializer", scis.get(0).getClass().getName()); //container path + assertEquals("org.eclipse.jetty.annotations.WebInfClassServletContainerInitializer", scis.get(1).getClass().getName()); //web-inf classes + assertEquals("com.acme.initializer.FooInitializer", scis.get(2).getClass().getName()); //web-inf jar no web-fragment + + //test a 3.1 webapp with metadata-complete=false loads both server and webapp scis + config = new AnnotationConfiguration(); + context = new WebAppContext(); + context.setClassLoader(webAppLoader); + context.getMetaData().setWebXml(Resource.newResource(web31false)); + context.getMetaData().setWebInfClassesDirs(Collections.singletonList(targetClasses)); + context.getMetaData().addWebInfJar(Resource.newResource(testSciJar.toURI().toURL())); + context.getServletContext().setEffectiveMajorVersion(3); + context.getServletContext().setEffectiveMinorVersion(1); + scis = config.getNonExcludedInitializers(context); + assertNotNull(scis); + assertEquals(3, scis.size()); + assertEquals("com.acme.ServerServletContainerInitializer", scis.get(0).getClass().getName()); //container path + assertEquals("org.eclipse.jetty.annotations.WebInfClassServletContainerInitializer", scis.get(1).getClass().getName()); //web-inf classes + assertEquals("com.acme.initializer.FooInitializer", scis.get(2).getClass().getName()); //web-inf jar no web-fragment + + //test a 3.1 webapp with RELATIVE ORDERING loads sci from equivalent of WEB-INF/classes as well as container path + File orderedFragmentJar = new File(jarDir, "test-sci-with-ordering.jar"); + assertTrue(orderedFragmentJar.exists()); + URLClassLoader orderedLoader = new URLClassLoader(new URL[]{ + orderedFragmentJar.toURI().toURL(), testSciJar.toURI().toURL() + }, Thread.currentThread().getContextClassLoader()); + config = new AnnotationConfiguration(); + context = new WebAppContext(); + context.setClassLoader(orderedLoader); + context.getMetaData().setWebXml(Resource.newResource(web31true)); + RelativeOrdering ordering = new RelativeOrdering(context.getMetaData()); + context.getMetaData().setOrdering(ordering); + context.getMetaData().addWebInfJar(Resource.newResource(orderedFragmentJar.toURI().toURL())); + context.getMetaData().addWebInfJar(Resource.newResource(testSciJar.toURI().toURL())); + context.getMetaData().setWebInfClassesDirs(Collections.singletonList(targetClasses)); + context.getMetaData().orderFragments(); + context.getServletContext().setEffectiveMajorVersion(3); + context.getServletContext().setEffectiveMinorVersion(1); + scis = config.getNonExcludedInitializers(context); + assertNotNull(scis); + assertEquals(4, scis.size()); + assertEquals("com.acme.ServerServletContainerInitializer", scis.get(0).getClass().getName()); //container path + assertEquals("org.eclipse.jetty.annotations.WebInfClassServletContainerInitializer", scis.get(1).getClass().getName()); //web-inf classes + assertEquals("com.acme.AcmeServletContainerInitializer", scis.get(2).getClass().getName()); //first in ordering + assertEquals("com.acme.initializer.FooInitializer", scis.get(3).getClass().getName()); //other in ordering + + //test 3.1 webapp with a specific SCI ordering + config = new AnnotationConfiguration(); + context = new WebAppContext(); + context.setClassLoader(webAppLoader); + context.getMetaData().setWebXml(Resource.newResource(web31false)); + context.getMetaData().setWebInfClassesDirs(Collections.singletonList(targetClasses)); + context.getMetaData().addWebInfJar(Resource.newResource(testSciJar.toURI().toURL())); + context.getServletContext().setEffectiveMajorVersion(3); + context.getServletContext().setEffectiveMinorVersion(1); + context.setAttribute("org.eclipse.jetty.containerInitializerOrder", "com.acme.initializer.FooInitializer,com.acme.ServerServletContainerInitializer, *"); + scis = config.getNonExcludedInitializers(context); + assertNotNull(scis); + assertEquals(3, scis.size()); + assertEquals("com.acme.initializer.FooInitializer", scis.get(0).getClass().getName()); //web-inf jar no web-fragment + assertEquals("com.acme.ServerServletContainerInitializer", scis.get(1).getClass().getName()); //container path + assertEquals("org.eclipse.jetty.annotations.WebInfClassServletContainerInitializer", scis.get(2).getClass().getName()); //web-inf classes + + //test 2.5 webapp with configurationDiscovered=false loads only server scis + config = new AnnotationConfiguration(); + context = new WebAppContext(); + context.setClassLoader(webAppLoader); + context.getMetaData().setWebXml(Resource.newResource(web25)); + context.getMetaData().setWebInfClassesDirs(Collections.singletonList(targetClasses)); + context.getMetaData().addWebInfJar(Resource.newResource(testSciJar.toURI().toURL())); + context.getServletContext().setEffectiveMajorVersion(2); + context.getServletContext().setEffectiveMinorVersion(5); + scis = config.getNonExcludedInitializers(context); + assertNotNull(scis); + for (ServletContainerInitializer s : scis) + { + //should not have any of the web-inf lib scis in here + assertFalse(s.getClass().getName().equals("com.acme.AcmeServletContainerInitializer")); + assertFalse(s.getClass().getName().equals("com.acme.initializer.FooInitializer")); + //NOTE: should also not have the web-inf classes scis in here either, but due to the + //way the test is set up, the sci we're pretending is in web-inf classes will actually + //NOT be loaded by the webapp's classloader, but rather by the junit classloader, so + //it looks as if it is a container class. + } + + //test 2.5 webapp with configurationDiscovered=true loads both server and webapp scis + config = new AnnotationConfiguration(); + context = new WebAppContext(); + context.setConfigurationDiscovered(true); + context.setClassLoader(webAppLoader); + context.getMetaData().setWebXml(Resource.newResource(web25)); + context.getMetaData().setWebInfClassesDirs(Collections.singletonList(targetClasses)); + context.getMetaData().addWebInfJar(Resource.newResource(testSciJar.toURI().toURL())); + context.getServletContext().setEffectiveMajorVersion(2); + context.getServletContext().setEffectiveMinorVersion(5); + scis = config.getNonExcludedInitializers(context); + assertNotNull(scis); + assertEquals(3, scis.size()); + assertEquals("com.acme.ServerServletContainerInitializer", scis.get(0).getClass().getName()); //container path + assertEquals("org.eclipse.jetty.annotations.WebInfClassServletContainerInitializer", scis.get(1).getClass().getName()); //web-inf classes + assertEquals("com.acme.initializer.FooInitializer", scis.get(2).getClass().getName()); //web-inf jar no web-fragment + } + finally + { + Thread.currentThread().setContextClassLoader(old); + } } - - + @Test public void testGetFragmentFromJar() throws Exception { String dir = MavenTestingUtils.getTargetTestingDir("getFragmentFromJar").getAbsolutePath(); File file = new File(dir); - file=new File(file.getCanonicalPath()); - URL url=file.toURI().toURL(); + file = new File(file.getCanonicalPath()); + URL url = file.toURI().toURL(); - Resource jar1 = Resource.newResource(url+"file.jar"); + Resource jar1 = Resource.newResource(url + "file.jar"); AnnotationConfiguration config = new AnnotationConfiguration(); WebAppContext wac = new WebAppContext(); List frags = new ArrayList(); - frags.add(new FragmentDescriptor(Resource.newResource("jar:"+url+"file.jar!/fooa.props"))); - frags.add(new FragmentDescriptor(Resource.newResource("jar:"+url+"file2.jar!/foob.props"))); + frags.add(new FragmentDescriptor(Resource.newResource("jar:" + url + "file.jar!/fooa.props"))); + frags.add(new FragmentDescriptor(Resource.newResource("jar:" + url + "file2.jar!/foob.props"))); assertNotNull(config.getFragmentFromJar(jar1, frags)); } diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationInheritance.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationInheritance.java index 6800a684f88..ac5f8551f0f 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationInheritance.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationInheritance.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,22 +18,12 @@ package org.eclipse.jetty.annotations; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.hasKey; -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.assertTrue; - import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; - import javax.naming.Context; import javax.naming.InitialContext; @@ -44,14 +34,22 @@ import org.eclipse.jetty.annotations.AnnotationParser.MethodInfo; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.hasKey; +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.assertTrue; + /** * */ public class TestAnnotationInheritance { List classNames = new ArrayList(); - - + class SampleHandler extends AbstractHandler { public final List annotatedClassNames = new ArrayList(); @@ -63,16 +61,16 @@ public class TestAnnotationInheritance { if (annotation == null || !"org.eclipse.jetty.annotations.Sample".equals(annotation)) return; - + annotatedClassNames.add(info.getClassName()); } @Override public void handle(FieldInfo info, String annotation) - { + { if (annotation == null || !"org.eclipse.jetty.annotations.Sample".equals(annotation)) return; - annotatedFields.add(info.getClassInfo().getClassName()+"."+info.getFieldName()); + annotatedFields.add(info.getClassInfo().getClassName() + "." + info.getFieldName()); } @Override @@ -80,13 +78,13 @@ public class TestAnnotationInheritance { if (annotation == null || !"org.eclipse.jetty.annotations.Sample".equals(annotation)) return; - annotatedMethods.add(info.getClassInfo().getClassName()+"."+info.getMethodName()); + annotatedMethods.add(info.getClassInfo().getClassName() + "." + info.getMethodName()); } - + @Override public String toString() { - return annotatedClassNames.toString()+annotatedMethods+annotatedFields; + return annotatedClassNames.toString() + annotatedMethods + annotatedFields; } } @@ -113,14 +111,14 @@ public class TestAnnotationInheritance assertEquals(2, handler.annotatedClassNames.size()); //check we got all annotated methods on each class - assertEquals (7, handler.annotatedMethods.size()); - assertTrue (handler.annotatedMethods.contains("org.eclipse.jetty.annotations.ClassA.a")); - assertTrue (handler.annotatedMethods.contains("org.eclipse.jetty.annotations.ClassA.b")); - assertTrue (handler.annotatedMethods.contains("org.eclipse.jetty.annotations.ClassA.c")); - assertTrue (handler.annotatedMethods.contains("org.eclipse.jetty.annotations.ClassA.d")); - assertTrue (handler.annotatedMethods.contains("org.eclipse.jetty.annotations.ClassA.l")); - assertTrue (handler.annotatedMethods.contains("org.eclipse.jetty.annotations.ClassB.a")); - assertTrue (handler.annotatedMethods.contains("org.eclipse.jetty.annotations.ClassB.c")); + assertEquals(7, handler.annotatedMethods.size()); + assertTrue(handler.annotatedMethods.contains("org.eclipse.jetty.annotations.ClassA.a")); + assertTrue(handler.annotatedMethods.contains("org.eclipse.jetty.annotations.ClassA.b")); + assertTrue(handler.annotatedMethods.contains("org.eclipse.jetty.annotations.ClassA.c")); + assertTrue(handler.annotatedMethods.contains("org.eclipse.jetty.annotations.ClassA.d")); + assertTrue(handler.annotatedMethods.contains("org.eclipse.jetty.annotations.ClassA.l")); + assertTrue(handler.annotatedMethods.contains("org.eclipse.jetty.annotations.ClassB.a")); + assertTrue(handler.annotatedMethods.contains("org.eclipse.jetty.annotations.ClassB.c")); //check we got all annotated fields on each class assertEquals(1, handler.annotatedFields.size()); @@ -138,14 +136,14 @@ public class TestAnnotationInheritance assertEquals(2, handler.annotatedClassNames.size()); //check we got all annotated methods on each class - assertEquals (7, handler.annotatedMethods.size()); - assertTrue (handler.annotatedMethods.contains("org.eclipse.jetty.annotations.ClassA.a")); - assertTrue (handler.annotatedMethods.contains("org.eclipse.jetty.annotations.ClassA.b")); - assertTrue (handler.annotatedMethods.contains("org.eclipse.jetty.annotations.ClassA.c")); - assertTrue (handler.annotatedMethods.contains("org.eclipse.jetty.annotations.ClassA.d")); - assertTrue (handler.annotatedMethods.contains("org.eclipse.jetty.annotations.ClassA.l")); - assertTrue (handler.annotatedMethods.contains("org.eclipse.jetty.annotations.ClassB.a")); - assertTrue (handler.annotatedMethods.contains("org.eclipse.jetty.annotations.ClassB.c")); + assertEquals(7, handler.annotatedMethods.size()); + assertTrue(handler.annotatedMethods.contains("org.eclipse.jetty.annotations.ClassA.a")); + assertTrue(handler.annotatedMethods.contains("org.eclipse.jetty.annotations.ClassA.b")); + assertTrue(handler.annotatedMethods.contains("org.eclipse.jetty.annotations.ClassA.c")); + assertTrue(handler.annotatedMethods.contains("org.eclipse.jetty.annotations.ClassA.d")); + assertTrue(handler.annotatedMethods.contains("org.eclipse.jetty.annotations.ClassA.l")); + assertTrue(handler.annotatedMethods.contains("org.eclipse.jetty.annotations.ClassB.a")); + assertTrue(handler.annotatedMethods.contains("org.eclipse.jetty.annotations.ClassB.c")); //check we got all annotated fields on each class assertEquals(1, handler.annotatedFields.size()); @@ -156,7 +154,7 @@ public class TestAnnotationInheritance public void testTypeInheritanceHandling() throws Exception { Map> map = new ConcurrentHashMap<>(); - + AnnotationParser parser = new AnnotationParser(); ClassInheritanceHandler handler = new ClassInheritanceHandler(map); @@ -183,6 +181,6 @@ public class TestAnnotationInheritance classes = map.get("org.eclipse.jetty.annotations.InterfaceD"); assertThat(classes, containsInAnyOrder("org.eclipse.jetty.annotations.ClassB", - Foo.class.getName())); + Foo.class.getName())); } } diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationParser.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationParser.java index a734191fe35..b27d1ed67dc 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationParser.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationParser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,20 +18,13 @@ package org.eclipse.jetty.annotations; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.isIn; -import static org.hamcrest.Matchers.notNullValue; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; @@ -50,11 +43,21 @@ import org.eclipse.jetty.toolchain.test.IO; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.toolchain.test.jupiter.WorkDir; import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension; +import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.resource.PathResource; import org.eclipse.jetty.util.resource.Resource; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.in; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + @ExtendWith(WorkDirExtension.class) public class TestAnnotationParser { @@ -77,8 +80,7 @@ public class TestAnnotationParser foundClasses.add(info.getClassName()); } } - - + public static class DuplicateClassScanHandler extends AnnotationParser.AbstractHandler { private Map> _classMap = new ConcurrentHashMap(); @@ -88,21 +90,19 @@ public class TestAnnotationParser { List list = new CopyOnWriteArrayList<>(); Resource r = info.getContainingResource(); - list.add((r==null?"":r.toString())); - + list.add((r == null ? "" : r.toString())); + List existing = _classMap.putIfAbsent(info.getClassName(), list); if (existing != null) { existing.addAll(list); } } - - + public List getParsedList(String classname) { return _classMap.get(classname); } - } public WorkDir testdir; @@ -110,13 +110,12 @@ public class TestAnnotationParser @Test public void testSampleAnnotation() throws Exception { - String[] classNames = new String[] - { "org.eclipse.jetty.annotations.ClassA" }; + String[] classNames = new String[]{"org.eclipse.jetty.annotations.ClassA"}; AnnotationParser parser = new AnnotationParser(); class SampleAnnotationHandler extends AnnotationParser.AbstractHandler { - private List methods = Arrays.asList("a","b","c","d","l"); + private List methods = Arrays.asList("a", "b", "c", "d", "l"); @Override public void handle(ClassInfo info, String annotation) @@ -124,26 +123,26 @@ public class TestAnnotationParser if (annotation == null || !"org.eclipse.jetty.annotations.Sample".equals(annotation)) return; - assertEquals("org.eclipse.jetty.annotations.ClassA",info.getClassName()); + assertEquals("org.eclipse.jetty.annotations.ClassA", info.getClassName()); } @Override public void handle(FieldInfo info, String annotation) - { + { if (annotation == null || !"org.eclipse.jetty.annotations.Sample".equals(annotation)) return; - assertEquals("m",info.getFieldName()); - assertEquals(org.objectweb.asm.Type.OBJECT,org.objectweb.asm.Type.getType(info.getFieldType()).getSort()); + assertEquals("m", info.getFieldName()); + assertEquals(org.objectweb.asm.Type.OBJECT, org.objectweb.asm.Type.getType(info.getFieldType()).getSort()); } @Override public void handle(MethodInfo info, String annotation) - { + { if (annotation == null || !"org.eclipse.jetty.annotations.Sample".equals(annotation)) return; - assertEquals("org.eclipse.jetty.annotations.ClassA",info.getClassInfo().getClassName()); - assertThat(info.getMethodName(), isIn(methods)); - assertEquals("org.eclipse.jetty.annotations.Sample",annotation); + assertEquals("org.eclipse.jetty.annotations.ClassA", info.getClassInfo().getClassName()); + assertThat(info.getMethodName(), is(in(methods))); + assertEquals("org.eclipse.jetty.annotations.Sample", annotation); } } @@ -157,8 +156,7 @@ public class TestAnnotationParser @Test public void testMultiAnnotation() throws Exception { - String[] classNames = new String[] - { "org.eclipse.jetty.annotations.ClassB" }; + String[] classNames = new String[]{"org.eclipse.jetty.annotations.ClassB"}; AnnotationParser parser = new AnnotationParser(); class MultiAnnotationHandler extends AnnotationParser.AbstractHandler @@ -166,7 +164,7 @@ public class TestAnnotationParser @Override public void handle(ClassInfo info, String annotation) { - if (annotation == null || ! "org.eclipse.jetty.annotations.Multi".equals(annotation)) + if (annotation == null || !"org.eclipse.jetty.annotations.Multi".equals(annotation)) return; assertTrue("org.eclipse.jetty.annotations.ClassB".equals(info.getClassName())); } @@ -174,14 +172,14 @@ public class TestAnnotationParser @Override public void handle(FieldInfo info, String annotation) { - assertTrue(annotation == null || ! "org.eclipse.jetty.annotations.Multi".equals(annotation), - "There should not be any"); + assertTrue(annotation == null || !"org.eclipse.jetty.annotations.Multi".equals(annotation), + "There should not be any"); } @Override public void handle(MethodInfo info, String annotation) - { - if (annotation == null || ! "org.eclipse.jetty.annotations.Multi".equals(annotation)) + { + if (annotation == null || !"org.eclipse.jetty.annotations.Multi".equals(annotation)) return; assertTrue("org.eclipse.jetty.annotations.ClassB".equals(info.getClassInfo().getClassName())); assertTrue("a".equals(info.getMethodName())); @@ -244,22 +242,21 @@ public class TestAnnotationParser FS.ensureEmpty(basedir); // Copy in class that is known to have annotations. - copyClass(ClassA.class,basedir); + copyClass(ClassA.class, basedir); // Setup Tracker TrackingAnnotationHandler tracker = new TrackingAnnotationHandler(Sample.class.getName()); // Setup annotation scanning AnnotationParser parser = new AnnotationParser(); - + // Parse parser.parse(Collections.singleton(tracker), basedir.toURI()); - + // Validate assertThat("Found Class", tracker.foundClasses, contains(ClassA.class.getName())); } - - + @Test public void testScanDuplicateClassesInJars() throws Exception { @@ -269,14 +266,13 @@ public class TestAnnotationParser DuplicateClassScanHandler handler = new DuplicateClassScanHandler(); Set handlers = Collections.singleton(handler); parser.parse(handlers, testJar); - parser.parse(handlers, testJar2); + parser.parse(handlers, testJar2); List locations = handler.getParsedList("org.acme.ClassOne"); assertNotNull(locations); assertEquals(2, locations.size()); assertTrue(!(locations.get(0).equals(locations.get(1)))); } - - + @Test public void testScanDuplicateClasses() throws Exception { @@ -286,36 +282,26 @@ public class TestAnnotationParser DuplicateClassScanHandler handler = new DuplicateClassScanHandler(); Set handlers = Collections.singleton(handler); parser.parse(handlers, testJar); - parser.parse(handlers, Resource.newResource(testClasses)); - Listlocations = handler.getParsedList("org.acme.ClassOne"); + parser.parse(handlers, Resource.newResource(testClasses)); + List locations = handler.getParsedList("org.acme.ClassOne"); assertNotNull(locations); assertEquals(2, locations.size()); assertTrue(!(locations.get(0).equals(locations.get(1)))); } - - private void copyClass(Class clazz, File basedir) throws IOException { - String classname = clazz.getName().replace('.',File.separatorChar) + ".class"; - URL url = this.getClass().getResource('/'+classname); - assertThat("URL for: " + classname,url,notNullValue()); + String classRef = TypeUtil.toClassReference(clazz); + URL url = this.getClass().getResource('/' + classRef); + assertThat("URL for: " + classRef, url, notNullValue()); - String classpath = classname.substring(0,classname.lastIndexOf(File.separatorChar)); - FS.ensureDirExists(new File(basedir,classpath)); + Path outputFile = basedir.toPath().resolve(classRef); + FS.ensureDirExists(outputFile.getParent()); - InputStream in = null; - OutputStream out = null; - try + try (InputStream in = url.openStream(); + OutputStream out = Files.newOutputStream(outputFile)) { - in = url.openStream(); - out = new FileOutputStream(new File(basedir,classname)); - IO.copy(in,out); - } - finally - { - IO.close(out); - IO.close(in); + IO.copy(in, out); } } } diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestSecurityAnnotationConversions.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestSecurityAnnotationConversions.java index 7be020b0721..3ff372e22ee 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestSecurityAnnotationConversions.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestSecurityAnnotationConversions.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,15 +18,8 @@ package org.eclipse.jetty.annotations; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - import java.util.Arrays; import java.util.List; - import javax.servlet.annotation.HttpConstraint; import javax.servlet.annotation.HttpMethodConstraint; import javax.servlet.annotation.ServletSecurity; @@ -43,30 +36,44 @@ import org.eclipse.jetty.util.security.Constraint; import org.eclipse.jetty.webapp.WebAppContext; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + public class TestSecurityAnnotationConversions { - @ServletSecurity(value=@HttpConstraint(value=EmptyRoleSemantic.DENY)) + @ServletSecurity(value = @HttpConstraint(value = EmptyRoleSemantic.DENY)) public static class DenyServlet extends HttpServlet - {} + { + } @ServletSecurity public static class PermitServlet extends HttpServlet - {} + { + } - @ServletSecurity(value=@HttpConstraint(value=EmptyRoleSemantic.PERMIT, transportGuarantee=TransportGuarantee.CONFIDENTIAL, rolesAllowed={"tom", "dick", "harry"})) + @ServletSecurity(value = @HttpConstraint(value = EmptyRoleSemantic.PERMIT, transportGuarantee = TransportGuarantee.CONFIDENTIAL, rolesAllowed = { + "tom", "dick", "harry" + })) public static class RolesServlet extends HttpServlet - {} + { + } - @ServletSecurity(value=@HttpConstraint(value=EmptyRoleSemantic.PERMIT, transportGuarantee=TransportGuarantee.CONFIDENTIAL, rolesAllowed={"tom", "dick", "harry"}), - httpMethodConstraints={@HttpMethodConstraint(value="GET")}) + @ServletSecurity(value = @HttpConstraint(value = EmptyRoleSemantic.PERMIT, transportGuarantee = TransportGuarantee.CONFIDENTIAL, rolesAllowed = { + "tom", "dick", "harry" + }), httpMethodConstraints = {@HttpMethodConstraint(value = "GET")}) public static class Method1Servlet extends HttpServlet - {} + { + } - @ServletSecurity(value=@HttpConstraint(value=EmptyRoleSemantic.PERMIT, transportGuarantee=TransportGuarantee.CONFIDENTIAL, rolesAllowed={"tom", "dick", "harry"}), - httpMethodConstraints={@HttpMethodConstraint(value="GET", transportGuarantee=TransportGuarantee.CONFIDENTIAL)}) + @ServletSecurity(value = @HttpConstraint(value = EmptyRoleSemantic.PERMIT, transportGuarantee = TransportGuarantee.CONFIDENTIAL, rolesAllowed = { + "tom", "dick", "harry" + }), httpMethodConstraints = {@HttpMethodConstraint(value = "GET", transportGuarantee = TransportGuarantee.CONFIDENTIAL)}) public static class Method2Servlet extends HttpServlet - {} - + { + } public void setUp() { @@ -76,7 +83,9 @@ public class TestSecurityAnnotationConversions public void testDenyAllOnClass() throws Exception { - WebAppContext wac = makeWebAppContext(DenyServlet.class.getCanonicalName(), "denyServlet", new String[]{"/foo/*", "*.foo"}); + WebAppContext wac = makeWebAppContext(DenyServlet.class.getCanonicalName(), "denyServlet", new String[]{ + "/foo/*", "*.foo" + }); //Assume we found 1 servlet with a @HttpConstraint with value=EmptyRoleSemantic.DENY security annotation ServletSecurityAnnotationHandler annotationHandler = new ServletSecurityAnnotationHandler(wac); @@ -108,22 +117,22 @@ public class TestSecurityAnnotationConversions public void testPermitAll() throws Exception { //Assume we found 1 servlet with a @ServletSecurity security annotation - WebAppContext wac = makeWebAppContext(PermitServlet.class.getCanonicalName(), "permitServlet", new String[]{"/foo/*", "*.foo"}); + WebAppContext wac = makeWebAppContext(PermitServlet.class.getCanonicalName(), "permitServlet", new String[]{ + "/foo/*", "*.foo" + }); ServletSecurityAnnotationHandler annotationHandler = new ServletSecurityAnnotationHandler(wac); AnnotationIntrospector introspector = new AnnotationIntrospector(); introspector.registerHandler(annotationHandler); - //set up the expected outcomes - no constraints at all as per Servlet Spec 3.1 pg 129 //1 ConstraintMapping per ServletMapping pathSpec - ConstraintMapping[] expectedMappings = new ConstraintMapping[]{}; - + introspector.introspect(PermitServlet.class); - compareResults (expectedMappings, ((ConstraintAware)wac.getSecurityHandler()).getConstraintMappings()); + compareResults(expectedMappings, ((ConstraintAware)wac.getSecurityHandler()).getConstraintMappings()); } @Test @@ -132,7 +141,9 @@ public class TestSecurityAnnotationConversions //Assume we found 1 servlet with annotation with roles defined and //and a TransportGuarantee - WebAppContext wac = makeWebAppContext(RolesServlet.class.getCanonicalName(), "rolesServlet", new String[]{"/foo/*", "*.foo"}); + WebAppContext wac = makeWebAppContext(RolesServlet.class.getCanonicalName(), "rolesServlet", new String[]{ + "/foo/*", "*.foo" + }); ServletSecurityAnnotationHandler annotationHandler = new ServletSecurityAnnotationHandler(wac); AnnotationIntrospector introspector = new AnnotationIntrospector(); @@ -155,16 +166,18 @@ public class TestSecurityAnnotationConversions expectedMappings[1].setPathSpec("*.foo"); introspector.introspect(RolesServlet.class); - compareResults (expectedMappings, ((ConstraintAware)wac.getSecurityHandler()).getConstraintMappings()); + compareResults(expectedMappings, ((ConstraintAware)wac.getSecurityHandler()).getConstraintMappings()); } @Test public void testMethodAnnotation() throws Exception { //ServletSecurity annotation with HttpConstraint of TransportGuarantee.CONFIDENTIAL, and a list of rolesAllowed, and - //a HttpMethodConstraint for GET method that permits all and has TransportGuarantee.NONE (ie is default) + //an HttpMethodConstraint for GET method that permits all and has TransportGuarantee.NONE (ie is default) - WebAppContext wac = makeWebAppContext(Method1Servlet.class.getCanonicalName(), "method1Servlet", new String[]{"/foo/*", "*.foo"}); + WebAppContext wac = makeWebAppContext(Method1Servlet.class.getCanonicalName(), "method1Servlet", new String[]{ + "/foo/*", "*.foo" + }); //set up the expected outcomes: - a Constraint for the RolesAllowed on the class //with userdata constraint of DC_CONFIDENTIAL @@ -202,7 +215,7 @@ public class TestSecurityAnnotationConversions ServletSecurityAnnotationHandler annotationHandler = new ServletSecurityAnnotationHandler(wac); introspector.registerHandler(annotationHandler); introspector.introspect(Method1Servlet.class); - compareResults (expectedMappings, ((ConstraintAware)wac.getSecurityHandler()).getConstraintMappings()); + compareResults(expectedMappings, ((ConstraintAware)wac.getSecurityHandler()).getConstraintMappings()); } @Test @@ -210,7 +223,9 @@ public class TestSecurityAnnotationConversions { //A ServletSecurity annotation that has HttpConstraint of CONFIDENTIAL with defined roles, but a //HttpMethodConstraint for GET that permits all, but also requires CONFIDENTIAL - WebAppContext wac = makeWebAppContext(Method2Servlet.class.getCanonicalName(), "method2Servlet", new String[]{"/foo/*", "*.foo"}); + WebAppContext wac = makeWebAppContext(Method2Servlet.class.getCanonicalName(), "method2Servlet", new String[]{ + "/foo/*", "*.foo" + }); AnnotationIntrospector introspector = new AnnotationIntrospector(); ServletSecurityAnnotationHandler annotationHandler = new ServletSecurityAnnotationHandler(wac); @@ -249,25 +264,25 @@ public class TestSecurityAnnotationConversions expectedMappings[3].setMethod("GET"); introspector.introspect(Method2Servlet.class); - compareResults (expectedMappings, ((ConstraintAware)wac.getSecurityHandler()).getConstraintMappings()); + compareResults(expectedMappings, ((ConstraintAware)wac.getSecurityHandler()).getConstraintMappings()); } - private void compareResults (ConstraintMapping[] expectedMappings, List actualMappings) + private void compareResults(ConstraintMapping[] expectedMappings, List actualMappings) { assertNotNull(actualMappings); assertEquals(expectedMappings.length, actualMappings.size()); - for (int k=0; k < actualMappings.size(); k++) + for (int k = 0; k < actualMappings.size(); k++) { ConstraintMapping am = actualMappings.get(k); - boolean matched = false; + boolean matched = false; - for (int i=0; i< expectedMappings.length && !matched; i++) + for (int i = 0; i < expectedMappings.length && !matched; i++) { ConstraintMapping em = expectedMappings[i]; if (em.getPathSpec().equals(am.getPathSpec())) { - if ((em.getMethod()==null && am.getMethod() == null) || em.getMethod() != null && em.getMethod().equals(am.getMethod())) + if ((em.getMethod() == null && am.getMethod() == null) || em.getMethod() != null && em.getMethod().equals(am.getMethod())) { matched = true; @@ -295,12 +310,11 @@ public class TestSecurityAnnotationConversions } if (!matched) - fail("No expected ConstraintMapping matching method:"+am.getMethod()+" pathSpec: "+am.getPathSpec()); + fail("No expected ConstraintMapping matching method:" + am.getMethod() + " pathSpec: " + am.getPathSpec()); } } - - private WebAppContext makeWebAppContext (String className, String servletName, String[] paths) + private WebAppContext makeWebAppContext(String className, String servletName, String[] paths) { WebAppContext wac = new WebAppContext(); diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestServletAnnotations.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestServletAnnotations.java index cdba04fc7d7..c8032f14b80 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestServletAnnotations.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestServletAnnotations.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,15 +18,6 @@ package org.eclipse.jetty.annotations; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.anyOf; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.is; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -40,6 +31,15 @@ import org.eclipse.jetty.webapp.DiscoveredAnnotation; import org.eclipse.jetty.webapp.WebAppContext; import org.junit.jupiter.api.Test; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.anyOf; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + /** * TestServletAnnotations */ @@ -77,7 +77,6 @@ public class TestServletAnnotations parser.parse(Collections.singleton(handler), classes); - assertEquals(1, results.size()); assertTrue(results.get(0) instanceof WebServletAnnotation); @@ -103,9 +102,8 @@ public class TestServletAnnotations assertEquals(2, paths.length); } - @Test - public void testWebServletAnnotationOverrideDefault () throws Exception + public void testWebServletAnnotationOverrideDefault() throws Exception { //if the existing servlet mapping TO A DIFFERENT SERVLET IS from a default descriptor we //DO allow the annotation to replace the mapping. @@ -132,16 +130,14 @@ public class TestServletAnnotations assertEquals(1, resultMappings.length); assertEquals(2, resultMappings[0].getPathSpecs().length); resultMappings[0].getServletName().equals("DServlet"); - for (String s:resultMappings[0].getPathSpecs()) + for (String s : resultMappings[0].getPathSpecs()) { assertThat(s, anyOf(is("/"), is("/bah/*"))); } } - - @Test - public void testWebServletAnnotationReplaceDefault () throws Exception + public void testWebServletAnnotationReplaceDefault() throws Exception { //if the existing servlet mapping TO A DIFFERENT SERVLET IS from a default descriptor we //DO allow the annotation to replace the mapping. @@ -170,31 +166,29 @@ public class TestServletAnnotations ServletMapping[] resultMappings = wac.getServletHandler().getServletMappings(); assertNotNull(resultMappings); assertEquals(2, resultMappings.length); - for (ServletMapping r:resultMappings) + for (ServletMapping r : resultMappings) { - if (r.getServletName().equals("default")) - { - assertEquals(1,r.getPathSpecs().length); - assertEquals("/other", r.getPathSpecs()[0]); - } - else if (r.getServletName().equals("DServlet")) - { - assertEquals(2,r.getPathSpecs().length); - for (String p:r.getPathSpecs()) - { - if (!p.equals("/") && !p.equals("/bah/*")) - fail("Unexpected path"); - } - } - else - fail("Unexpected servlet mapping: " + r); + if (r.getServletName().equals("default")) + { + assertEquals(1, r.getPathSpecs().length); + assertEquals("/other", r.getPathSpecs()[0]); + } + else if (r.getServletName().equals("DServlet")) + { + assertEquals(2, r.getPathSpecs().length); + for (String p : r.getPathSpecs()) + { + if (!p.equals("/") && !p.equals("/bah/*")) + fail("Unexpected path"); + } + } + else + fail("Unexpected servlet mapping: " + r); } - } - @Test - public void testWebServletAnnotationNotOverride () throws Exception + public void testWebServletAnnotationNotOverride() throws Exception { //if the existing servlet mapping TO A DIFFERENT SERVLET IS NOT from a default descriptor we //DO NOT allow the annotation to replace the mapping @@ -213,7 +207,7 @@ public class TestServletAnnotations ServletMapping[] resultMappings = wac.getServletHandler().getServletMappings(); assertEquals(2, resultMappings.length); - for (ServletMapping r:resultMappings) + for (ServletMapping r : resultMappings) { if (r.getServletName().equals("DServlet")) { @@ -229,7 +223,7 @@ public class TestServletAnnotations } @Test - public void testWebServletAnnotationIgnore () throws Exception + public void testWebServletAnnotationIgnore() throws Exception { //an existing servlet OF THE SAME NAME has even 1 non-default mapping we can't use //any of the url mappings in the annotation @@ -256,17 +250,16 @@ public class TestServletAnnotations ServletMapping[] resultMappings = wac.getServletHandler().getServletMappings(); assertEquals(2, resultMappings.length); - for (ServletMapping r:resultMappings) + for (ServletMapping r : resultMappings) { assertEquals(1, r.getPathSpecs().length); if (!r.getPathSpecs()[0].equals("/default") && !r.getPathSpecs()[0].equals("/other")) fail("Unexpected path in mapping: " + r); } - } @Test - public void testWebServletAnnotationNoMappings () throws Exception + public void testWebServletAnnotationNoMappings() throws Exception { //an existing servlet OF THE SAME NAME has no mappings, therefore all mappings in the annotation //should be accepted @@ -275,24 +268,21 @@ public class TestServletAnnotations servlet.setName("foo"); wac.getServletHandler().addServlet(servlet); - WebServletAnnotation annotation = new WebServletAnnotation(wac, "org.eclipse.jetty.annotations.ServletD", null); annotation.apply(); ServletMapping[] resultMappings = wac.getServletHandler().getServletMappings(); assertEquals(1, resultMappings.length); assertEquals(2, resultMappings[0].getPathSpecs().length); - for (String s:resultMappings[0].getPathSpecs()) + for (String s : resultMappings[0].getPathSpecs()) { assertThat(s, anyOf(is("/"), is("/bah/*"))); } } - - @Test - public void testDeclareRoles () - throws Exception + public void testDeclareRoles() + throws Exception { WebAppContext wac = new WebAppContext(); ConstraintSecurityHandler sh = new ConstraintSecurityHandler(); diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ServerServletContainerInitializer.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/WebInfClassServletContainerInitializer.java similarity index 85% rename from jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ServerServletContainerInitializer.java rename to jetty-annotations/src/test/java/org/eclipse/jetty/annotations/WebInfClassServletContainerInitializer.java index 3fbfadce4c5..21f08112dae 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ServerServletContainerInitializer.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/WebInfClassServletContainerInitializer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,32 +16,28 @@ // ======================================================================== // - package org.eclipse.jetty.annotations; import java.util.Set; - import javax.servlet.ServletContainerInitializer; import javax.servlet.ServletContext; import javax.servlet.ServletException; /** * ServerServletContainerInitializer - * - * */ -public class ServerServletContainerInitializer implements ServletContainerInitializer +public class WebInfClassServletContainerInitializer implements ServletContainerInitializer { /** - * + * */ - public ServerServletContainerInitializer() + public WebInfClassServletContainerInitializer() { // TODO Auto-generated constructor stub } - /** + /** * @see javax.servlet.ServletContainerInitializer#onStartup(java.util.Set, javax.servlet.ServletContext) */ @Override @@ -50,5 +46,4 @@ public class ServerServletContainerInitializer implements ServletContainerInitia // TODO Auto-generated method stub } - } diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/resources/ResourceA.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/resources/ResourceA.java index 733025a58b6..e5b91f72ce8 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/resources/ResourceA.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/resources/ResourceA.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,7 +19,6 @@ package org.eclipse.jetty.annotations.resources; import java.io.IOException; - import javax.annotation.Resource; import javax.servlet.ServletConfig; import javax.servlet.ServletException; @@ -28,8 +27,6 @@ import javax.servlet.ServletResponse; /** * ResourceA - * - * */ public class ResourceA implements javax.servlet.Servlet { @@ -37,25 +34,24 @@ public class ResourceA implements javax.servlet.Servlet private Integer h; private Integer k; - - @Resource(name="myf", mappedName="resB") //test giving both a name and mapped name from the environment + @Resource(name = "myf", mappedName = "resB") //test giving both a name and mapped name from the environment private Integer f;//test a non inherited field that needs injection - @Resource(mappedName="resA") //test the default naming scheme but using a mapped name from the environment + @Resource(mappedName = "resA") //test the default naming scheme but using a mapped name from the environment private Integer g; - @Resource(name="resA") //test using the given name as the name from the environment + @Resource(name = "resA") //test using the given name as the name from the environment private Integer j; - @Resource(mappedName="resB") //test using the default name on an inherited field + @Resource(mappedName = "resB") //test using the default name on an inherited field protected Integer n; //TODO - if it's inherited, is it supposed to use the classname of the class it is inherited by? - - @Resource(name="mye", mappedName="resA", type=Integer.class) + @Resource(name = "mye", mappedName = "resA", type = Integer.class) public void setE(Integer e) { - this.e=e; + this.e = e; } + public Integer getE() { return this.e; @@ -76,42 +72,48 @@ public class ResourceA implements javax.servlet.Servlet return this.j; } - @Resource(mappedName="resA") + @Resource(mappedName = "resA") public void setH(Integer h) { - this.h=h; + this.h = h; } - @Resource(name="resA") + @Resource(name = "resA") public void setK(Integer k) { - this.k=k; + this.k = k; } + public void x() { System.err.println("ResourceA.x"); } + @Override public void destroy() { } + @Override public ServletConfig getServletConfig() { return null; } + @Override public String getServletInfo() { return null; } + @Override public void init(ServletConfig arg0) throws ServletException { } + @Override public void service(ServletRequest arg0, ServletResponse arg1) - throws ServletException, IOException + throws ServletException, IOException { } } diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/resources/ResourceB.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/resources/ResourceB.java index 674bb14ef46..1af693b215c 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/resources/ResourceB.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/resources/ResourceB.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -17,26 +17,25 @@ // package org.eclipse.jetty.annotations.resources; + import javax.annotation.Resource; import javax.annotation.Resources; /** * ResourceB - * - * */ @Resources({ - @Resource(name="peach", mappedName="resA"), - @Resource(name="pear", mappedName="resB") + @Resource(name = "peach", mappedName = "resA"), + @Resource(name = "pear", mappedName = "resB") }) public class ResourceB extends ResourceA { - @Resource(mappedName="resB") + @Resource(mappedName = "resB") private Integer f;//test no inheritance of private fields - + @Resource private Integer p = new Integer(8); //test no injection because no value - + //test no annotation public void z() { diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/resources/TestResourceAnnotations.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/resources/TestResourceAnnotations.java index b6143c249dc..88e19a9a32a 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/resources/TestResourceAnnotations.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/resources/TestResourceAnnotations.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,12 +18,9 @@ package org.eclipse.jetty.annotations.resources; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; - import java.lang.reflect.Field; import java.util.List; - +import java.util.Set; import javax.naming.Context; import javax.naming.InitialContext; @@ -38,6 +35,9 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + public class TestResourceAnnotations { private Server server; @@ -68,8 +68,8 @@ public class TestResourceAnnotations } @Test - public void testResourceAnnotations () - throws Exception + public void testResourceAnnotations() + throws Exception { new org.eclipse.jetty.plus.jndi.EnvEntry(server, "resA", objA, false); new org.eclipse.jetty.plus.jndi.EnvEntry(server, "resB", objB, false); @@ -100,16 +100,16 @@ public class TestResourceAnnotations //we should have Injections assertNotNull(injections); - List resBInjections = injections.getInjections(ResourceB.class.getCanonicalName()); + Set resBInjections = injections.getInjections(ResourceB.class.getName()); assertNotNull(resBInjections); //only 1 field injection because the other has no Resource mapping assertEquals(1, resBInjections.size()); - Injection fi = resBInjections.get(0); - assertEquals ("f", fi.getTarget().getName()); + Injection fi = resBInjections.iterator().next(); + assertEquals("f", fi.getTarget().getName()); //3 method injections on class ResourceA, 4 field injections - List resAInjections = injections.getInjections(ResourceA.class.getCanonicalName()); + Set resAInjections = injections.getInjections(ResourceA.class.getName()); assertNotNull(resAInjections); assertEquals(7, resAInjections.size()); int fieldCount = 0; @@ -129,9 +129,9 @@ public class TestResourceAnnotations injections.inject(binst); //check injected values - Field f = ResourceB.class.getDeclaredField ("f"); + Field f = ResourceB.class.getDeclaredField("f"); f.setAccessible(true); - assertEquals(objB , f.get(binst)); + assertEquals(objB, f.get(binst)); //@Resource(mappedName="resA") //test the default naming scheme but using a mapped name from the environment f = ResourceA.class.getDeclaredField("g"); @@ -150,8 +150,8 @@ public class TestResourceAnnotations } @Test - public void testResourcesAnnotation () - throws Exception + public void testResourcesAnnotation() + throws Exception { new org.eclipse.jetty.plus.jndi.EnvEntry(server, "resA", objA, false); new org.eclipse.jetty.plus.jndi.EnvEntry(server, "resB", objB, false); diff --git a/jetty-annotations/src/test/resources/META-INF/services/javax.servlet.ServletContainerInitializer b/jetty-annotations/src/test/resources/META-INF/services/javax.servlet.ServletContainerInitializer index 8193f60e4a7..cc22e474171 100644 --- a/jetty-annotations/src/test/resources/META-INF/services/javax.servlet.ServletContainerInitializer +++ b/jetty-annotations/src/test/resources/META-INF/services/javax.servlet.ServletContainerInitializer @@ -1 +1 @@ -org.eclipse.jetty.annotations.ServerServletContainerInitializer \ No newline at end of file +org.eclipse.jetty.annotations.WebInfClassServletContainerInitializer \ No newline at end of file diff --git a/jetty-ant/pom.xml b/jetty-ant/pom.xml index fd54142b183..6e00ab6f1f1 100644 --- a/jetty-ant/pom.xml +++ b/jetty-ant/pom.xml @@ -2,15 +2,15 @@ org.eclipse.jetty jetty-project - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 jetty-ant jar Jetty :: Ant Plugin - + - org.eclipse.jetty.ant + ${project.groupId}.ant diff --git a/jetty-ant/src/main/java/org/eclipse/jetty/ant/AntWebAppContext.java b/jetty-ant/src/main/java/org/eclipse/jetty/ant/AntWebAppContext.java index 64f039fb2b9..f50b1523a50 100644 --- a/jetty-ant/src/main/java/org/eclipse/jetty/ant/AntWebAppContext.java +++ b/jetty-ant/src/main/java/org/eclipse/jetty/ant/AntWebAppContext.java @@ -33,7 +33,6 @@ import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.jar.Manifest; - import javax.servlet.Servlet; import org.apache.tools.ant.AntClassLoader; @@ -72,64 +71,71 @@ import org.eclipse.jetty.xml.XmlConfiguration; public class AntWebAppContext extends WebAppContext { private static final Logger LOG = Log.getLogger(WebAppContext.class); - - public final AntWebInfConfiguration antWebInfConfiguration = new AntWebInfConfiguration(); - public final WebXmlConfiguration webXmlConfiguration = new WebXmlConfiguration(); - public final MetaInfConfiguration metaInfConfiguration = new MetaInfConfiguration(); - public final FragmentConfiguration fragmentConfiguration = new FragmentConfiguration(); - public final EnvConfiguration envConfiguration = new EnvConfiguration(); - public final PlusConfiguration plusConfiguration = new PlusConfiguration(); - public final AnnotationConfiguration annotationConfiguration = new AnnotationConfiguration(); - public final JettyWebXmlConfiguration jettyWebXmlConfiguration = new JettyWebXmlConfiguration(); + public static final AntWebInfConfiguration ANT_WEB_INF_CONFIGURATION = new AntWebInfConfiguration(); + public static final WebXmlConfiguration WEB_XML_CONFIGURATION = new WebXmlConfiguration(); + public static final MetaInfConfiguration META_INF_CONFIGURATION = new MetaInfConfiguration(); + public static final FragmentConfiguration FRAGMENT_CONFIGURATION = new FragmentConfiguration(); + public static final EnvConfiguration ENV_CONFIGURATION = new EnvConfiguration(); + public static final PlusConfiguration PLUS_CONFIGURATION = new PlusConfiguration(); + public static final AnnotationConfiguration ANNOTATION_CONFIGURATION = new AnnotationConfiguration(); + public static final JettyWebXmlConfiguration JETTY_WEB_XML_CONFIGURATION = new JettyWebXmlConfiguration(); - public final Configuration[] DEFAULT_CONFIGURATIONS = - { - antWebInfConfiguration, - webXmlConfiguration, - metaInfConfiguration, - fragmentConfiguration, - envConfiguration, - plusConfiguration, - annotationConfiguration, - jettyWebXmlConfiguration + public static final Configuration[] DEFAULT_CONFIGURATIONS = + { + ANT_WEB_INF_CONFIGURATION, + WEB_XML_CONFIGURATION, + META_INF_CONFIGURATION, + FRAGMENT_CONFIGURATION, + ENV_CONFIGURATION, + PLUS_CONFIGURATION, + ANNOTATION_CONFIGURATION, + JETTY_WEB_XML_CONFIGURATION }; - - public final static String DEFAULT_CONTAINER_INCLUDE_JAR_PATTERN = - ".*/.*jsp-api-[^/]*\\.jar$|.*/.*jsp-[^/]*\\.jar$|.*/.*taglibs[^/]*\\.jar$|.*/.*jstl[^/]*\\.jar$|.*/.*jsf-impl-[^/]*\\.jar$|.*/.*javax.faces-[^/]*\\.jar$|.*/.*myfaces-impl-[^/]*\\.jar$"; + public static final String DEFAULT_CONTAINER_INCLUDE_JAR_PATTERN = + ".*/.*jsp-api-[^/]*\\.jar$|.*/.*jsp-[^/]*\\.jar$|.*/.*taglibs[^/]*\\.jar$|.*/.*jstl[^/]*\\.jar$|.*/.*jsf-impl-[^/]*\\.jar$|.*/.*javax.faces-[^/]*\\.jar$|.*/.*myfaces-impl-[^/]*\\.jar$"; - - /** Location of jetty-env.xml file. */ + /** + * Location of jetty-env.xml file. + */ private File jettyEnvXml; - - /** List of web application libraries. */ + + /** + * List of web application libraries. + */ private List libraries = new ArrayList(); - /** List of web application class directories. */ + /** + * List of web application class directories. + */ private List classes = new ArrayList(); - - /** context xml file to apply to the webapp */ + + /** + * context xml file to apply to the webapp + */ private File contextXml; - - /** List of extra scan targets for this web application. */ + + /** + * List of extra scan targets for this web application. + */ private FileSet scanTargets; - - /** context attributes to set **/ + + /** + * context attributes to set + **/ private Attributes attributes; - + private Project project; - + private List scanFiles; - - - /** Extra scan targets. */ + /** + * Extra scan targets. + */ private FileMatchingConfiguration extraScanTargetsConfiguration; - private FileMatchingConfiguration librariesConfiguration; - public static void dump(ClassLoader loader) { @@ -141,15 +147,16 @@ public class AntWebAppContext extends WebAppContext URL[] urls = ((URLClassLoader)loader).getURLs(); if (urls != null) { - for (URL u:urls) - System.err.println("\t"+u+"\n"); + for (URL u : urls) + { + System.err.println("\t" + u + "\n"); + } } } loader = loader.getParent(); } } - /** * AntURLClassLoader * @@ -159,11 +166,11 @@ public class AntWebAppContext extends WebAppContext public static class AntURLClassLoader extends URLClassLoader { private AntClassLoader antLoader; - + public AntURLClassLoader(AntClassLoader antLoader) { - super(new URL[] {}, antLoader); - this.antLoader = antLoader; + super(new URL[]{}, antLoader); + this.antLoader = antLoader; } @Override @@ -188,17 +195,17 @@ public class AntWebAppContext extends WebAppContext public URL[] getURLs() { Set urls = new HashSet(); - + //convert urls from antLoader String[] paths = antLoader.getClasspath().split(new String(new char[]{File.pathSeparatorChar})); if (paths != null) { - for (String p:paths) + for (String p : paths) { File f = new File(p); try { - urls.add(f.toURI().toURL()); + urls.add(f.toURI().toURL()); } catch (Exception e) { @@ -206,15 +213,17 @@ public class AntWebAppContext extends WebAppContext } } } - + //add in any that may have been added to us as a URL directly URL[] ourURLS = super.getURLs(); if (ourURLS != null) { - for (URL u:ourURLS) + for (URL u : ourURLS) + { urls.add(u); + } } - + return urls.toArray(new URL[urls.size()]); } @@ -327,12 +336,9 @@ public class AntWebAppContext extends WebAppContext super.clearAssertionStatus(); } } - - + /** * AntServletHolder - * - * */ public static class AntServletHolder extends ServletHolder { @@ -342,33 +348,29 @@ public class AntWebAppContext extends WebAppContext super(); } - public AntServletHolder(Class servlet) { super(servlet); } - public AntServletHolder(Servlet servlet) { super(servlet); } - public AntServletHolder(String name, Class servlet) { super(name, servlet); } - public AntServletHolder(String name, Servlet servlet) { super(name, servlet); } - protected String getSystemClassPath (ClassLoader loader) throws Exception + protected String getSystemClassPath(ClassLoader loader) throws Exception { - StringBuilder classpath=new StringBuilder(); + StringBuilder classpath = new StringBuilder(); while (loader != null) { if (loader instanceof URLClassLoader) @@ -376,13 +378,13 @@ public class AntWebAppContext extends WebAppContext URL[] urls = ((URLClassLoader)loader).getURLs(); if (urls != null) { - for (int i=0;i0) + if (classpath.length() > 0) classpath.append(File.pathSeparatorChar); classpath.append(file.getAbsolutePath()); } @@ -399,15 +401,10 @@ public class AntWebAppContext extends WebAppContext return classpath.toString(); } - } - - /** * AntServletHandler - * - * */ public static class AntServletHandler extends ServletHandler { @@ -417,11 +414,8 @@ public class AntWebAppContext extends WebAppContext { return new AntServletHolder(); } - } - - /** * Default constructor. Takes project as an argument * @@ -436,10 +430,10 @@ public class AntWebAppContext extends WebAppContext setAttribute(WebInfConfiguration.CONTAINER_JAR_PATTERN, DEFAULT_CONTAINER_INCLUDE_JAR_PATTERN); setParentLoaderPriority(true); } - /** * Adds a new Ant's attributes tag object if it have not been created yet. + * * @param atts the attributes */ public void addAttributes(Attributes atts) @@ -452,19 +446,15 @@ public class AntWebAppContext extends WebAppContext this.attributes = atts; } - public void addLib(FileSet lib) { libraries.add(lib); } - public void addClasses(FileSet classes) { this.classes.add(classes); } - - @Override protected ServletHandler newServletHandler() @@ -472,27 +462,22 @@ public class AntWebAppContext extends WebAppContext return new AntServletHandler(); } - public void setJettyEnvXml(File jettyEnvXml) { this.jettyEnvXml = jettyEnvXml; TaskLog.log("jetty-env.xml file: = " + (jettyEnvXml == null ? null : jettyEnvXml.getAbsolutePath())); } - public File getJettyEnvXml () + public File getJettyEnvXml() { return this.jettyEnvXml; } - - - public List getLibraries() { return librariesConfiguration.getBaseDirectories(); } - public void addScanTargets(FileSet scanTargets) { if (this.scanTargets != null) @@ -502,42 +487,39 @@ public class AntWebAppContext extends WebAppContext this.scanTargets = scanTargets; } - - public List getScanTargetFiles () + + public List getScanTargetFiles() { if (this.scanTargets == null) return null; - - + FileMatchingConfiguration configuration = new FileMatchingConfiguration(); configuration.addDirectoryScanner(scanTargets.getDirectoryScanner(project)); return configuration.getBaseDirectories(); } - + public List getScanFiles() { if (scanFiles == null) scanFiles = initScanFiles(); return scanFiles; } - - - public boolean isScanned (File file) + + public boolean isScanned(File file) { - List files = getScanFiles(); - if (files == null || files.isEmpty()) - return false; - return files.contains(file); + List files = getScanFiles(); + if (files == null || files.isEmpty()) + return false; + return files.contains(file); } - - - public List initScanFiles () + + public List initScanFiles() { List scanList = new ArrayList(); - + if (getDescriptor() != null) { - try (Resource r = Resource.newResource(getDescriptor());) + try (Resource r = Resource.newResource(getDescriptor())) { scanList.add(r.getFile()); } @@ -549,7 +531,7 @@ public class AntWebAppContext extends WebAppContext if (getJettyEnvXml() != null) { - try (Resource r = Resource.newResource(getJettyEnvXml());) + try (Resource r = Resource.newResource(getJettyEnvXml())) { scanList.add(r.getFile()); } @@ -561,10 +543,10 @@ public class AntWebAppContext extends WebAppContext if (getDefaultsDescriptor() != null) { - try (Resource r = Resource.newResource(getDefaultsDescriptor());) + try (Resource r = Resource.newResource(getDefaultsDescriptor())) { if (!WebAppContext.WEB_DEFAULTS_XML.equals(getDefaultsDescriptor())) - { + { scanList.add(r.getFile()); } } @@ -591,18 +573,16 @@ public class AntWebAppContext extends WebAppContext List cpFiles = getClassPathFiles(); if (cpFiles != null) scanList.addAll(cpFiles); - + //any extra scan targets @SuppressWarnings("unchecked") List scanFiles = (List)getScanTargetFiles(); if (scanFiles != null) scanList.addAll(scanFiles); - + return scanList; } - - - + @Override public void setWar(String path) { @@ -623,19 +603,18 @@ public class AntWebAppContext extends WebAppContext } } - /** - * + * */ @Override public void doStart() { try { - TaskLog.logWithTimestamp("Starting web application "+this.getDescriptor()); + TaskLog.logWithTimestamp("Starting web application " + this.getDescriptor()); if (jettyEnvXml != null && jettyEnvXml.exists()) - envConfiguration.setJettyEnvXml(Resource.toURL(jettyEnvXml)); - + ENV_CONFIGURATION.setJettyEnvXml(Resource.toURL(jettyEnvXml)); + ClassLoader parentLoader = this.getClass().getClassLoader(); if (parentLoader instanceof AntClassLoader) parentLoader = new AntURLClassLoader((AntClassLoader)parentLoader); @@ -643,18 +622,20 @@ public class AntWebAppContext extends WebAppContext setClassLoader(new WebAppClassLoader(parentLoader, this)); if (attributes != null && attributes.getAttributes() != null) { - for (Attribute a:attributes.getAttributes()) + for (Attribute a : attributes.getAttributes()) + { setAttribute(a.getName(), a.getValue()); + } } - + //apply a context xml file if one was supplied if (contextXml != null) { XmlConfiguration xmlConfiguration = new XmlConfiguration(Resource.toURL(contextXml)); - TaskLog.log("Applying context xml file "+contextXml); - xmlConfiguration.configure(this); + TaskLog.log("Applying context xml file " + contextXml); + xmlConfiguration.configure(this); } - + super.doStart(); } catch (Exception e) @@ -669,8 +650,8 @@ public class AntWebAppContext extends WebAppContext try { scanFiles = null; - TaskLog.logWithTimestamp("Stopping web application "+this); - Thread.currentThread().sleep(500L); + TaskLog.logWithTimestamp("Stopping web application " + this); + Thread.sleep(500L); super.doStop(); //remove all filters, servlets and listeners. They will be recreated //either via application of a context xml file or web.xml or annotation or servlet api @@ -690,8 +671,6 @@ public class AntWebAppContext extends WebAppContext } } - - /** * @return a list of classpath files (libraries and class directories). */ @@ -701,14 +680,14 @@ public class AntWebAppContext extends WebAppContext Iterator classesIterator = classes.iterator(); while (classesIterator.hasNext()) { - FileSet clazz = (FileSet) classesIterator.next(); + FileSet clazz = (FileSet)classesIterator.next(); classPathFiles.add(clazz.getDirectoryScanner(project).getBasedir()); } Iterator iterator = libraries.iterator(); while (iterator.hasNext()) { - FileSet library = (FileSet) iterator.next(); + FileSet library = (FileSet)iterator.next(); String[] includedFiles = library.getDirectoryScanner(project).getIncludedFiles(); File baseDir = library.getDirectoryScanner(project).getBasedir(); @@ -718,15 +697,13 @@ public class AntWebAppContext extends WebAppContext } } - return classPathFiles; } - /** * @return a FileMatchingConfiguration object describing the - * configuration of all libraries added to this particular web app - * (both classes and libraries). + * configuration of all libraries added to this particular web app + * (both classes and libraries). */ public FileMatchingConfiguration getLibrariesConfiguration() { @@ -735,30 +712,27 @@ public class AntWebAppContext extends WebAppContext Iterator classesIterator = classes.iterator(); while (classesIterator.hasNext()) { - FileSet clazz = (FileSet) classesIterator.next(); + FileSet clazz = (FileSet)classesIterator.next(); config.addDirectoryScanner(clazz.getDirectoryScanner(project)); } Iterator librariesIterator = libraries.iterator(); while (librariesIterator.hasNext()) { - FileSet library = (FileSet) librariesIterator.next(); + FileSet library = (FileSet)librariesIterator.next(); config.addDirectoryScanner(library.getDirectoryScanner(project)); } return config; } - public File getContextXml() { return contextXml; } - public void setContextXml(File contextXml) { this.contextXml = contextXml; } - } diff --git a/jetty-ant/src/main/java/org/eclipse/jetty/ant/AntWebInfConfiguration.java b/jetty-ant/src/main/java/org/eclipse/jetty/ant/AntWebInfConfiguration.java index 6ae07abc984..30e475ab478 100644 --- a/jetty-ant/src/main/java/org/eclipse/jetty/ant/AntWebInfConfiguration.java +++ b/jetty-ant/src/main/java/org/eclipse/jetty/ant/AntWebInfConfiguration.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -28,6 +28,7 @@ import java.util.regex.Pattern; import org.apache.tools.ant.AntClassLoader; import org.eclipse.jetty.util.PatternMatcher; +import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.webapp.WebAppClassLoader; import org.eclipse.jetty.webapp.WebAppContext; @@ -37,33 +38,31 @@ import org.eclipse.jetty.webapp.WebXmlConfiguration; public class AntWebInfConfiguration extends WebInfConfiguration { - @Override public void preConfigure(final WebAppContext context) throws Exception - { + { //Make a temp directory for the webapp if one is not already set resolveTempDirectory(context); - - //Extract webapp if necessary - unpack (context); - + //Extract webapp if necessary + unpack(context); + //Apply an initial ordering to the jars which governs which will be scanned for META-INF //info and annotations. The ordering is based on inclusion patterns. String tmp = (String)context.getAttribute(WEBINF_JAR_PATTERN); - Pattern webInfPattern = (tmp==null?null:Pattern.compile(tmp)); + Pattern webInfPattern = (tmp == null ? null : Pattern.compile(tmp)); tmp = (String)context.getAttribute(CONTAINER_JAR_PATTERN); - Pattern containerPattern = (tmp==null?null:Pattern.compile(tmp)); + Pattern containerPattern = (tmp == null ? null : Pattern.compile(tmp)); //Apply ordering to container jars - if no pattern is specified, we won't //match any of the container jars - PatternMatcher containerJarNameMatcher = new PatternMatcher () + PatternMatcher containerJarNameMatcher = new PatternMatcher() { @Override public void matched(URI uri) throws Exception { context.getMetaData().addContainerResource(Resource.newResource(uri)); - } + } }; ClassLoader loader = context.getClassLoader(); if (loader != null) @@ -71,38 +70,38 @@ public class AntWebInfConfiguration extends WebInfConfiguration loader = loader.getParent(); if (loader != null) { - URI[] containerUris = null; - + URI[] containerUris = null; + if (loader instanceof URLClassLoader) { URL[] urls = ((URLClassLoader)loader).getURLs(); if (urls != null) { containerUris = new URI[urls.length]; - int i=0; + int i = 0; for (URL u : urls) { - try + try { containerUris[i] = u.toURI(); } catch (URISyntaxException e) { - containerUris[i] = new URI(u.toString().replaceAll(" ", "%20")); - } + containerUris[i] = new URI(URIUtil.encodeSpaces(u.toString())); + } i++; } } } else if (loader instanceof AntClassLoader) { - AntClassLoader antLoader = (AntClassLoader)loader; + AntClassLoader antLoader = (AntClassLoader)loader; String[] paths = antLoader.getClasspath().split(new String(new char[]{File.pathSeparatorChar})); if (paths != null) { containerUris = new URI[paths.length]; - int i=0; - for (String p:paths) + int i = 0; + for (String p : paths) { File f = new File(p); containerUris[i] = f.toURI(); @@ -114,35 +113,34 @@ public class AntWebInfConfiguration extends WebInfConfiguration containerJarNameMatcher.match(containerPattern, containerUris, false); } } - + //Apply ordering to WEB-INF/lib jars - PatternMatcher webInfJarNameMatcher = new PatternMatcher () + PatternMatcher webInfJarNameMatcher = new PatternMatcher() { @Override public void matched(URI uri) throws Exception { context.getMetaData().addWebInfJar(Resource.newResource(uri)); - } + } }; List jars = findJars(context); - + //Convert to uris for matching URI[] uris = null; if (jars != null) { uris = new URI[jars.size()]; - int i=0; - for (Resource r: jars) + int i = 0; + for (Resource r : jars) { uris[i++] = r.getURI(); } } webInfJarNameMatcher.match(webInfPattern, uris, true); //null is inclusive, no pattern == all jars match - + //No pattern to appy to classes, just add to metadata context.getMetaData().setWebInfClassesDirs(findClassDirs(context)); } - /** * Adds classpath files into web application classloader, and @@ -158,11 +156,11 @@ public class AntWebInfConfiguration extends WebInfConfiguration List classPathFiles = ((AntWebAppContext)context).getClassPathFiles(); if (classPathFiles != null) { - for (File cpFile:classPathFiles) + for (File cpFile : classPathFiles) { if (cpFile.exists()) { - ((WebAppClassLoader) context.getClassLoader()).addClassPath(cpFile.getCanonicalPath()); + ((WebAppClassLoader)context.getClassLoader()).addClassPath(cpFile.getCanonicalPath()); } } } diff --git a/jetty-ant/src/main/java/org/eclipse/jetty/ant/AntWebXmlConfiguration.java b/jetty-ant/src/main/java/org/eclipse/jetty/ant/AntWebXmlConfiguration.java index 2022b1c2ea6..bd6af67b258 100644 --- a/jetty-ant/src/main/java/org/eclipse/jetty/ant/AntWebXmlConfiguration.java +++ b/jetty-ant/src/main/java/org/eclipse/jetty/ant/AntWebXmlConfiguration.java @@ -25,7 +25,6 @@ import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.webapp.WebXmlConfiguration; - /** * This configuration object provides additional way to inject application * properties into the configured web application. The list of classpath files, @@ -36,15 +35,16 @@ public class AntWebXmlConfiguration extends WebXmlConfiguration { private static final Logger LOG = Log.getLogger(WebXmlConfiguration.class); - - - /** List of classpath files. */ + /** + * List of classpath files. + */ private List classPathFiles; - /** Web application root directory. */ + /** + * Web application root directory. + */ private File webAppBaseDir; - public AntWebXmlConfiguration() { super(); @@ -59,7 +59,4 @@ public class AntWebXmlConfiguration extends WebXmlConfiguration { this.webAppBaseDir = webAppBaseDir; } - - - } diff --git a/jetty-ant/src/main/java/org/eclipse/jetty/ant/JettyRunTask.java b/jetty-ant/src/main/java/org/eclipse/jetty/ant/JettyRunTask.java index 5da5e947f50..6b7355f5b0b 100644 --- a/jetty-ant/src/main/java/org/eclipse/jetty/ant/JettyRunTask.java +++ b/jetty-ant/src/main/java/org/eclipse/jetty/ant/JettyRunTask.java @@ -41,42 +41,59 @@ import org.eclipse.jetty.webapp.WebAppContext; */ public class JettyRunTask extends Task { - private int scanIntervalSeconds; - - /** Temporary files directory. */ + private int scanIntervalSeconds; + + /** + * Temporary files directory. + */ private File tempDirectory; - /** List of web applications to be deployed. */ + /** + * List of web applications to be deployed. + */ private List webapps = new ArrayList<>(); - /** Location of jetty.xml file. */ + /** + * Location of jetty.xml file. + */ private File jettyXml; - /** List of server connectors. */ + /** + * List of server connectors. + */ private Connectors connectors = null; - /** Server request logger object. */ + /** + * Server request logger object. + */ private RequestLog requestLog; - /** List of login services. */ + /** + * List of login services. + */ private LoginServices loginServices; - /** List of system properties to be set. */ + /** + * List of system properties to be set. + */ private SystemProperties systemProperties; - - /** List of other contexts to deploy */ + + /** + * List of other contexts to deploy + */ private ContextHandlers contextHandlers; - - /** Port Jetty will use for the default connector */ + /** + * Port Jetty will use for the default connector + */ private int jettyPort = 8080; - + private int stopPort; - + private String stopKey; private boolean daemon; - + public JettyRunTask() { TaskLog.setTask(this); @@ -84,16 +101,18 @@ public class JettyRunTask extends Task /** * Creates a new WebApp Ant object. - * @param webapp the webapp context + * + * @param webapp the webapp context */ public void addWebApp(AntWebAppContext webapp) { - webapps.add(webapp); + webapps.add(webapp); } /** * Adds a new Ant's connector tag object if it have not been created yet. - * @param connectors the connectors + * + * @param connectors the connectors */ public void addConnectors(Connectors connectors) { @@ -103,10 +122,10 @@ public class JettyRunTask extends Task } public void addLoginServices(LoginServices services) - { - if (this.loginServices != null ) - throw new BuildException("Only one tag is allowed!"); - this.loginServices = services; + { + if (this.loginServices != null) + throw new BuildException("Only one tag is allowed!"); + this.loginServices = services; } public void addSystemProperties(SystemProperties systemProperties) @@ -115,8 +134,8 @@ public class JettyRunTask extends Task throw new BuildException("Only one tag is allowed!"); this.systemProperties = systemProperties; } - - public void addContextHandlers (ContextHandlers handlers) + + public void addContextHandlers(ContextHandlers handlers) { if (this.contextHandlers != null) throw new BuildException("Only one tag is allowed!"); @@ -147,7 +166,7 @@ public class JettyRunTask extends Task { try { - this.requestLog = (RequestLog) Class.forName(className).getDeclaredConstructor().newInstance(); + this.requestLog = (RequestLog)Class.forName(className).getDeclaredConstructor().newInstance(); } catch (ClassNotFoundException e) { @@ -157,7 +176,6 @@ public class JettyRunTask extends Task { throw new BuildException("Request logger instantiation exception: " + e); } - } public String getRequestLog() @@ -172,7 +190,7 @@ public class JettyRunTask extends Task /** * Sets the port Jetty uses for the default connector. - * + * * @param jettyPort The port Jetty will use for the default connector */ public void setJettyPort(final int jettyPort) @@ -191,7 +209,7 @@ public class JettyRunTask extends Task { TaskLog.log("Configuring Jetty for project: " + getProject().getName()); - + setSystemProperties(); List connectorsList = null; @@ -199,9 +217,9 @@ public class JettyRunTask extends Task if (connectors != null) connectorsList = connectors.getConnectors(); else - connectorsList = new Connectors(jettyPort,30000).getDefaultConnectors(); + connectorsList = new Connectors(jettyPort, 30000).getDefaultConnectors(); - List loginServicesList = (loginServices != null?loginServices.getLoginServices():new ArrayList()); + List loginServicesList = (loginServices != null ? loginServices.getLoginServices() : new ArrayList()); ServerProxyImpl server = new ServerProxyImpl(); server.setConnectors(connectorsList); server.setLoginServices(loginServicesList); @@ -216,7 +234,7 @@ public class JettyRunTask extends Task try { - for (WebAppContext webapp: webapps) + for (WebAppContext webapp : webapps) { server.addWebApplication((AntWebAppContext)webapp); } @@ -237,7 +255,7 @@ public class JettyRunTask extends Task public void setStopPort(int stopPort) { this.stopPort = stopPort; - TaskLog.log("stopPort="+stopPort); + TaskLog.log("stopPort=" + stopPort); } public String getStopKey() @@ -248,7 +266,7 @@ public class JettyRunTask extends Task public void setStopKey(String stopKey) { this.stopKey = stopKey; - TaskLog.log("stopKey="+stopKey); + TaskLog.log("stopKey=" + stopKey); } /** @@ -265,7 +283,7 @@ public class JettyRunTask extends Task public void setDaemon(boolean daemon) { this.daemon = daemon; - TaskLog.log("Daemon="+daemon); + TaskLog.log("Daemon=" + daemon); } public int getScanIntervalSeconds() @@ -276,9 +294,9 @@ public class JettyRunTask extends Task public void setScanIntervalSeconds(int secs) { scanIntervalSeconds = secs; - TaskLog.log("scanIntervalSecs="+secs); + TaskLog.log("scanIntervalSecs=" + secs); } - + /** * Sets the system properties. */ @@ -289,10 +307,9 @@ public class JettyRunTask extends Task Iterator propertiesIterator = systemProperties.getSystemProperties().iterator(); while (propertiesIterator.hasNext()) { - Property property = ((Property) propertiesIterator.next()); + Property property = ((Property)propertiesIterator.next()); SystemProperties.setIfNotSetAlready(property); } } } - } diff --git a/jetty-ant/src/main/java/org/eclipse/jetty/ant/JettyStopTask.java b/jetty-ant/src/main/java/org/eclipse/jetty/ant/JettyStopTask.java index 167864df17e..9478bf8c9a8 100644 --- a/jetty-ant/src/main/java/org/eclipse/jetty/ant/JettyStopTask.java +++ b/jetty-ant/src/main/java/org/eclipse/jetty/ant/JettyStopTask.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -31,39 +31,35 @@ import org.eclipse.jetty.ant.utils.TaskLog; /** * JettyStopTask - * - * */ public class JettyStopTask extends Task { private int stopPort; - + private String stopKey; - + private int stopWait; - - - + /** - * + * */ public JettyStopTask() { TaskLog.setTask(this); } - /** + /** * @see org.apache.tools.ant.Task#execute() */ @Override public void execute() throws BuildException { try - { - Socket s = new Socket(InetAddress.getByName("127.0.0.1"),stopPort); + { + Socket s = new Socket(InetAddress.getByName("127.0.0.1"), stopPort); if (stopWait > 0) - s.setSoTimeout(stopWait*1000); + s.setSoTimeout(stopWait * 1000); try { OutputStream out = s.getOutputStream(); @@ -72,9 +68,9 @@ public class JettyStopTask extends Task if (stopWait > 0) { - TaskLog.log("Waiting"+(stopWait > 0 ? (" "+stopWait+"sec") : "")+" for jetty to stop"); + TaskLog.log("Waiting" + (stopWait > 0 ? (" " + stopWait + "sec") : "") + " for jetty to stop"); LineNumberReader lin = new LineNumberReader(new InputStreamReader(s.getInputStream())); - String response=lin.readLine(); + String response = lin.readLine(); if ("Stopped".equals(response)) System.err.println("Stopped"); } @@ -82,7 +78,7 @@ public class JettyStopTask extends Task finally { s.close(); - } + } } catch (ConnectException e) { @@ -94,22 +90,22 @@ public class JettyStopTask extends Task } } - public int getStopPort() + public int getStopPort() { return stopPort; } - public void setStopPort(int stopPort) + public void setStopPort(int stopPort) { this.stopPort = stopPort; } - public String getStopKey() + public String getStopKey() { return stopKey; } - public void setStopKey(String stopKey) + public void setStopKey(String stopKey) { this.stopKey = stopKey; } @@ -123,6 +119,4 @@ public class JettyStopTask extends Task { this.stopWait = stopWait; } - - } diff --git a/jetty-ant/src/main/java/org/eclipse/jetty/ant/ServerProxyImpl.java b/jetty-ant/src/main/java/org/eclipse/jetty/ant/ServerProxyImpl.java index 2dd2fdb9ee0..c94e2ed9ad2 100644 --- a/jetty-ant/src/main/java/org/eclipse/jetty/ant/ServerProxyImpl.java +++ b/jetty-ant/src/main/java/org/eclipse/jetty/ant/ServerProxyImpl.java @@ -16,7 +16,6 @@ // ======================================================================== // - package org.eclipse.jetty.ant; import java.io.File; @@ -40,14 +39,11 @@ import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandlerCollection; import org.eclipse.jetty.server.handler.DefaultHandler; import org.eclipse.jetty.server.handler.HandlerCollection; -import org.eclipse.jetty.server.handler.RequestLogHandler; import org.eclipse.jetty.util.Scanner; import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.xml.XmlConfiguration; import org.xml.sax.SAXException; - - /** * A proxy class for interaction with Jetty server object. Used to have some * level of abstraction over standard Jetty classes. @@ -55,62 +51,84 @@ import org.xml.sax.SAXException; public class ServerProxyImpl implements ServerProxy { - /** Proxied Jetty server object. */ + /** + * Proxied Jetty server object. + */ private Server server; - - /** Temporary files directory. */ + + /** + * Temporary files directory. + */ private File tempDirectory; - - /** Collection of context handlers (web application contexts). */ + + /** + * Collection of context handlers (web application contexts). + */ private ContextHandlerCollection contexts; - /** Location of jetty.xml file. */ + /** + * Location of jetty.xml file. + */ private File jettyXml; - /** List of connectors. */ + /** + * List of connectors. + */ private List connectors; - /** Request logger. */ + /** + * Request logger. + */ private RequestLog requestLog; - /** User realms. */ + /** + * User realms. + */ private List loginServices; - /** List of added web applications. */ + /** + * List of added web applications. + */ private List webApplications = new ArrayList(); - /** other contexts to deploy */ + /** + * other contexts to deploy + */ private ContextHandlers contextHandlers; - /** scan interval for changed files */ + /** + * scan interval for changed files + */ private int scanIntervalSecs; - /** port to listen for stop command */ + /** + * port to listen for stop command + */ private int stopPort; - /** security key for stop command */ + /** + * security key for stop command + */ private String stopKey; - /** wait for all jetty threads to exit or continue */ + /** + * wait for all jetty threads to exit or continue + */ private boolean daemon; - private boolean configured = false; - - /** * WebAppScannerListener * * Handle notifications that files we are interested in have changed * during execution. - * */ public static class WebAppScannerListener implements Scanner.BulkListener - { + { AntWebAppContext awc; - public WebAppScannerListener (AntWebAppContext awc) + public WebAppScannerListener(AntWebAppContext awc) { this.awc = awc; } @@ -137,25 +155,22 @@ public class ServerProxyImpl implements ServerProxy TaskLog.log(e.getMessage()); } } - } - /** * Default constructor. Creates a new Jetty server with a standard connector * listening on a given port. */ - public ServerProxyImpl () + public ServerProxyImpl() { server = new Server(); server.setStopAtShutdown(true); } - @Override public void addWebApplication(AntWebAppContext webApp) { - webApplications.add(webApp); + webApplications.add(webApp); } public int getStopPort() @@ -228,19 +243,16 @@ public class ServerProxyImpl implements ServerProxy this.webApplications = webApplications; } - public File getTempDirectory() { return tempDirectory; } - public void setTempDirectory(File tempDirectory) { this.tempDirectory = tempDirectory; } - /** * @see org.eclipse.jetty.ant.utils.ServerProxy#start() */ @@ -250,15 +262,15 @@ public class ServerProxyImpl implements ServerProxy try { configure(); - + configureWebApps(); - + server.start(); - - System.setProperty("jetty.ant.server.port","" + ((ServerConnector)server.getConnectors()[0]).getLocalPort()); - + + System.setProperty("jetty.ant.server.port", "" + ((ServerConnector)server.getConnectors()[0]).getLocalPort()); + String host = ((ServerConnector)server.getConnectors()[0]).getHost(); - + if (host == null) { System.setProperty("jetty.ant.server.host", "localhost"); @@ -267,9 +279,9 @@ public class ServerProxyImpl implements ServerProxy { System.setProperty("jetty.ant.server.host", host); } - + startScanners(); - + TaskLog.log("Jetty AntTask Started"); if (!daemon) @@ -286,9 +298,6 @@ public class ServerProxyImpl implements ServerProxy } } - - - /** * @see org.eclipse.jetty.ant.utils.ServerProxy#getProxiedObject() */ @@ -298,7 +307,6 @@ public class ServerProxyImpl implements ServerProxy return server; } - /** * @return the daemon */ @@ -307,16 +315,14 @@ public class ServerProxyImpl implements ServerProxy return daemon; } - /** * @param daemon the daemon to set */ public void setDaemon(boolean daemon) - { + { this.daemon = daemon; } - /** * @return the contextHandlers */ @@ -325,27 +331,23 @@ public class ServerProxyImpl implements ServerProxy return contextHandlers; } - /** * @param contextHandlers the contextHandlers to set */ - public void setContextHandlers (ContextHandlers contextHandlers) + public void setContextHandlers(ContextHandlers contextHandlers) { this.contextHandlers = contextHandlers; } - public int getScanIntervalSecs() { return scanIntervalSecs; } - public void setScanIntervalSecs(int scanIntervalSecs) { this.scanIntervalSecs = scanIntervalSecs; } - /** * Configures Jetty server before adding any web applications to it. @@ -354,27 +356,27 @@ public class ServerProxyImpl implements ServerProxy { if (configured) return; - + configured = true; - if(stopPort>0 && stopKey!=null) + if (stopPort > 0 && stopKey != null) { ShutdownMonitor monitor = ShutdownMonitor.getInstance(); monitor.setPort(stopPort); monitor.setKey(stopKey); monitor.setExitVm(false); } - + if (tempDirectory != null && !tempDirectory.exists()) tempDirectory.mkdirs(); - + // Applies external configuration via jetty.xml applyJettyXml(); // Configures connectors for this server instance. if (connectors != null) { - for (Connector c:connectors) + for (Connector c : connectors) { ServerConnector jc = new ServerConnector(server); @@ -388,7 +390,7 @@ public class ServerProxyImpl implements ServerProxy // Configures login services if (loginServices != null) { - for (LoginService ls:loginServices) + for (LoginService ls : loginServices) { server.addBean(ls); } @@ -400,48 +402,44 @@ public class ServerProxyImpl implements ServerProxy // Set default server handlers configureHandlers(); } - - + /** - * + * */ private void configureHandlers() { - RequestLogHandler requestLogHandler = new RequestLogHandler(); if (requestLog != null) - requestLogHandler.setRequestLog(requestLog); + server.setRequestLog(requestLog); - contexts = (ContextHandlerCollection) server - .getChildHandlerByClass(ContextHandlerCollection.class); + contexts = server + .getChildHandlerByClass(ContextHandlerCollection.class); if (contexts == null) { contexts = new ContextHandlerCollection(); - HandlerCollection handlers = (HandlerCollection) server - .getChildHandlerByClass(HandlerCollection.class); + HandlerCollection handlers = server + .getChildHandlerByClass(HandlerCollection.class); if (handlers == null) { handlers = new HandlerCollection(); server.setHandler(handlers); - handlers.setHandlers(new Handler[] { contexts, new DefaultHandler(), - requestLogHandler }); + handlers.setHandlers(new Handler[]{contexts, new DefaultHandler()}); } else { handlers.addHandler(contexts); } } - + //if there are any extra contexts to deploy if (contextHandlers != null && contextHandlers.getContextHandlers() != null) { - for (ContextHandler c:contextHandlers.getContextHandlers()) + for (ContextHandler c : contextHandlers.getContextHandlers()) + { contexts.addHandler(c); + } } } - - - /** * Applies jetty.xml configuration to the Jetty server instance. */ @@ -449,8 +447,7 @@ public class ServerProxyImpl implements ServerProxy { if (jettyXml != null && jettyXml.exists()) { - TaskLog.log("Configuring jetty from xml configuration file = " - + jettyXml.getAbsolutePath()); + TaskLog.log("Configuring jetty from xml configuration file = " + jettyXml.getAbsolutePath()); XmlConfiguration configuration; try { @@ -476,21 +473,19 @@ public class ServerProxyImpl implements ServerProxy } } - /** * Starts web applications' scanners. */ private void startScanners() throws Exception { - for (AntWebAppContext awc:webApplications) + for (AntWebAppContext awc : webApplications) { if (scanIntervalSecs <= 0) return; List scanList = awc.getScanFiles(); - - TaskLog.log("Web application '" + awc + "': starting scanner at interval of " - + scanIntervalSecs + " seconds."); + + TaskLog.log("Web application '" + awc + "': starting scanner at interval of " + scanIntervalSecs + " seconds."); Scanner.Listener changeListener = new WebAppScannerListener(awc); Scanner scanner = new Scanner(); scanner.setScanInterval(scanIntervalSecs); @@ -498,21 +493,19 @@ public class ServerProxyImpl implements ServerProxy scanner.setScanDirs(scanList); scanner.setReportExistingFilesOnStartup(false); scanner.start(); - } + } } - - + /** - * + * */ private void configureWebApps() { - for (AntWebAppContext awc:webApplications) + for (AntWebAppContext awc : webApplications) { awc.setAttribute(AntWebAppContext.BASETEMPDIR, tempDirectory); if (contexts != null) contexts.addHandler(awc); } } - } diff --git a/jetty-ant/src/main/java/org/eclipse/jetty/ant/package-info.java b/jetty-ant/src/main/java/org/eclipse/jetty/ant/package-info.java index 589f6104cce..8e76918c4fb 100644 --- a/jetty-ant/src/main/java/org/eclipse/jetty/ant/package-info.java +++ b/jetty-ant/src/main/java/org/eclipse/jetty/ant/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/Attribute.java b/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/Attribute.java index aed16c5a316..2bec15d8ebe 100644 --- a/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/Attribute.java +++ b/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/Attribute.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -22,24 +22,24 @@ public class Attribute { String name; - + String value; - + public void setName(String name) { this.name = name; } - + public void setValue(String value) { this.value = value; } - + public String getName() { return name; } - + public String getValue() { return value; diff --git a/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/Attributes.java b/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/Attributes.java index 590bd9ed655..516ed1109df 100644 --- a/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/Attributes.java +++ b/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/Attributes.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -25,12 +25,12 @@ public class Attributes { List _attributes = new ArrayList(); - - public void addAttribute(Attribute attr ) + + public void addAttribute(Attribute attr) { _attributes.add(attr); } - + public List getAttributes() { return _attributes; diff --git a/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/Connector.java b/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/Connector.java index a59b163e9f6..47ce2c2fd18 100644 --- a/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/Connector.java +++ b/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/Connector.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,8 +20,6 @@ package org.eclipse.jetty.ant.types; /** * Connector - * - * */ public class Connector { @@ -58,5 +56,4 @@ public class Connector { this.maxIdleTime = maxIdleTime; } - } diff --git a/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/Connectors.java b/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/Connectors.java index 6b25db15f4e..68f2a6e48ba 100644 --- a/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/Connectors.java +++ b/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/Connectors.java @@ -16,7 +16,6 @@ // ======================================================================== // - package org.eclipse.jetty.ant.types; import java.util.ArrayList; @@ -33,7 +32,8 @@ public class Connectors /** * Default constructor. */ - public Connectors() { + public Connectors() + { this(8080, 30000); } @@ -78,5 +78,4 @@ public class Connectors { return defaultConnectors; } - } diff --git a/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/ContextHandlers.java b/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/ContextHandlers.java index 0c250583d2a..7930ab10284 100644 --- a/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/ContextHandlers.java +++ b/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/ContextHandlers.java @@ -16,7 +16,6 @@ // ======================================================================== // - package org.eclipse.jetty.ant.types; import java.util.ArrayList; diff --git a/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/FileMatchingConfiguration.java b/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/FileMatchingConfiguration.java index 73749f98411..58e061d6e07 100644 --- a/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/FileMatchingConfiguration.java +++ b/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/FileMatchingConfiguration.java @@ -16,7 +16,6 @@ // ======================================================================== // - package org.eclipse.jetty.ant.types; import java.io.File; @@ -43,7 +42,7 @@ public class FileMatchingConfiguration /** * @param directoryScanner new directory scanner retrieved from the - * <fileset/> element. + * <fileset/> element. */ public void addDirectoryScanner(DirectoryScanner directoryScanner) { @@ -52,7 +51,7 @@ public class FileMatchingConfiguration /** * @return a list of base directories denoted by a list of directory - * scanners. + * scanners. */ public List getBaseDirectories() { @@ -60,7 +59,7 @@ public class FileMatchingConfiguration Iterator scanners = directoryScanners.iterator(); while (scanners.hasNext()) { - DirectoryScanner scanner = (DirectoryScanner) scanners.next(); + DirectoryScanner scanner = (DirectoryScanner)scanners.next(); baseDirs.add(scanner.getBasedir()); } @@ -69,7 +68,7 @@ public class FileMatchingConfiguration /** * Checks if passed file is scanned by any of the directory scanners. - * + * * @param pathToFile a fully qualified path to tested file. * @return true if so, false otherwise. */ @@ -78,7 +77,7 @@ public class FileMatchingConfiguration Iterator scanners = directoryScanners.iterator(); while (scanners.hasNext()) { - DirectoryScanner scanner = (DirectoryScanner) scanners.next(); + DirectoryScanner scanner = (DirectoryScanner)scanners.next(); scanner.scan(); String[] includedFiles = scanner.getIncludedFiles(); diff --git a/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/LoginServices.java b/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/LoginServices.java index 867f99bca32..33735a8a3e1 100644 --- a/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/LoginServices.java +++ b/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/LoginServices.java @@ -16,7 +16,6 @@ // ======================================================================== // - package org.eclipse.jetty.ant.types; import java.util.ArrayList; diff --git a/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/SystemProperties.java b/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/SystemProperties.java index 3e2b38bbdc9..56981c0ad78 100644 --- a/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/SystemProperties.java +++ b/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/SystemProperties.java @@ -16,7 +16,6 @@ // ======================================================================== // - package org.eclipse.jetty.ant.types; import java.util.ArrayList; @@ -27,12 +26,11 @@ import org.eclipse.jetty.ant.utils.TaskLog; /** * SystemProperties - *

    + *

    * Ant <systemProperties/> tag definition. */ public class SystemProperties { - private List systemProperties = new ArrayList(); public List getSystemProperties() @@ -47,17 +45,16 @@ public class SystemProperties /** * Set a System.property with this value if it is not already set. - * @param property the property to test + * + * @param property the property to test * @return true if property has been set */ public static boolean setIfNotSetAlready(Property property) { if (System.getProperty(property.getName()) == null) { - System.setProperty(property.getName(), (property.getValue() == null ? "" : property - .getValue())); - TaskLog.log("Setting property '" + property.getName() + "' to value '" - + property.getValue() + "'"); + System.setProperty(property.getName(), (property.getValue() == null ? "" : property.getValue())); + TaskLog.log("Setting property '" + property.getName() + "' to value '" + property.getValue() + "'"); return true; } diff --git a/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/package-info.java b/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/package-info.java index d3ad358cd3a..74366b9abc5 100644 --- a/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/package-info.java +++ b/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-ant/src/main/java/org/eclipse/jetty/ant/utils/ServerProxy.java b/jetty-ant/src/main/java/org/eclipse/jetty/ant/utils/ServerProxy.java index 432778e7148..ba9b1ebaf8c 100644 --- a/jetty-ant/src/main/java/org/eclipse/jetty/ant/utils/ServerProxy.java +++ b/jetty-ant/src/main/java/org/eclipse/jetty/ant/utils/ServerProxy.java @@ -16,7 +16,6 @@ // ======================================================================== // - package org.eclipse.jetty.ant.utils; import org.eclipse.jetty.ant.AntWebAppContext; @@ -26,17 +25,15 @@ public interface ServerProxy /** * Adds a new web application to this server. - * + * * @param awc a AntWebAppContext object. */ - public void addWebApplication(AntWebAppContext awc); + void addWebApplication(AntWebAppContext awc); /** * Starts this server. */ - public void start(); - - - public Object getProxiedObject(); + void start(); + Object getProxiedObject(); } diff --git a/jetty-ant/src/main/java/org/eclipse/jetty/ant/utils/TaskLog.java b/jetty-ant/src/main/java/org/eclipse/jetty/ant/utils/TaskLog.java index e9aad1d017d..ba0618fda75 100644 --- a/jetty-ant/src/main/java/org/eclipse/jetty/ant/utils/TaskLog.java +++ b/jetty-ant/src/main/java/org/eclipse/jetty/ant/utils/TaskLog.java @@ -26,7 +26,6 @@ import org.apache.tools.ant.Task; /** * Provides logging functionality for classes without access to the Ant project * variable. - * */ public class TaskLog { @@ -34,7 +33,7 @@ public class TaskLog private static Task task; private static final SimpleDateFormat format = new SimpleDateFormat( - "yyyy-MM-dd HH:mm:ss.SSS"); + "yyyy-MM-dd HH:mm:ss.SSS"); public static void setTask(Task task) { diff --git a/jetty-ant/src/main/java/org/eclipse/jetty/ant/utils/package-info.java b/jetty-ant/src/main/java/org/eclipse/jetty/ant/utils/package-info.java index 9c01692457f..21a25fd4331 100644 --- a/jetty-ant/src/main/java/org/eclipse/jetty/ant/utils/package-info.java +++ b/jetty-ant/src/main/java/org/eclipse/jetty/ant/utils/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-ant/src/test/java/org/eclipse/jetty/ant/AntBuild.java b/jetty-ant/src/test/java/org/eclipse/jetty/ant/AntBuild.java index 919b6323fb4..d0df7cc29f1 100644 --- a/jetty-ant/src/test/java/org/eclipse/jetty/ant/AntBuild.java +++ b/jetty-ant/src/test/java/org/eclipse/jetty/ant/AntBuild.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -46,7 +46,7 @@ public class AntBuild private int _port; private String _host; - + public AntBuild(String ant) { _ant = ant; @@ -55,22 +55,22 @@ public class AntBuild private class AntBuildProcess implements Runnable { List connList; - + @Override public void run() { File buildFile = new File(_ant); - + Project antProject = new Project(); try { antProject.setBaseDir(MavenTestingUtils.getBaseDir()); - antProject.setUserProperty("ant.file",buildFile.getAbsolutePath()); + antProject.setUserProperty("ant.file", buildFile.getAbsolutePath()); DefaultLogger logger = new DefaultLogger(); ConsoleParser parser = new ConsoleParser(); //connList = parser.newPattern(".*([0-9]+\\.[0-9]*\\.[0-9]*\\.[0-9]*):([0-9]*)",1); - connList = parser.newPattern("Jetty AntTask Started",1); + connList = parser.newPattern("Jetty AntTask Started", 1); PipedOutputStream pos = new PipedOutputStream(); PipedInputStream pis = new PipedInputStream(pos); @@ -78,9 +78,9 @@ public class AntBuild PipedOutputStream pose = new PipedOutputStream(); PipedInputStream pise = new PipedInputStream(pose); - startPump("STDOUT",parser,pis); - startPump("STDERR",parser,pise); - + startPump("STDOUT", parser, pis); + startPump("STDERR", parser, pise); + logger.setErrorPrintStream(new PrintStream(pos)); logger.setOutputPrintStream(new PrintStream(pose)); logger.setMessageOutputLevel(Project.MSG_VERBOSE); @@ -91,21 +91,20 @@ public class AntBuild ProjectHelper helper = ProjectHelper.getProjectHelper(); - antProject.addReference("ant.projectHelper",helper); + antProject.addReference("ant.projectHelper", helper); - helper.parse(antProject,buildFile); + helper.parse(antProject, buildFile); antProject.executeTarget("jetty.run"); - - parser.waitForDone(10000,TimeUnit.MILLISECONDS); + + parser.waitForDone(10000, TimeUnit.MILLISECONDS); } catch (Exception e) { antProject.fireBuildFinished(e); } } - - + public void waitForStarted() throws Exception { while (connList == null || connList.isEmpty()) @@ -122,26 +121,25 @@ public class AntBuild _process = new Thread(abp); _process.start(); - + abp.waitForStarted(); - + // once this has returned we should have the connection info we need //_host = abp.getConnectionList().get(0)[0]; //_port = Integer.parseInt(abp.getConnectionList().get(0)[1]); - + } - + public int getJettyPort() { return Integer.parseInt(System.getProperty("jetty.ant.server.port")); } - + public String getJettyHost() { return System.getProperty("jetty.ant.server.host"); } - - + /** * Stop the jetty server */ @@ -159,7 +157,7 @@ public class AntBuild public List newPattern(String exp, int cnt) { - ConsolePattern pat = new ConsolePattern(exp,cnt); + ConsolePattern pat = new ConsolePattern(exp, cnt); patterns.add(pat); count += cnt; @@ -173,7 +171,8 @@ public class AntBuild Matcher mat = pat.getMatcher(line); if (mat.find()) { - int num = 0, count = mat.groupCount(); + int num = 0; + int count = mat.groupCount(); String[] match = new String[count]; while (num++ < count) { @@ -191,7 +190,7 @@ public class AntBuild public void waitForDone(long timeout, TimeUnit unit) throws InterruptedException { - getLatch().await(timeout,unit); + getLatch().await(timeout, unit); } private CountDownLatch getLatch() @@ -239,9 +238,9 @@ public class AntBuild private void startPump(String mode, ConsoleParser parser, InputStream inputStream) { - ConsoleStreamer pump = new ConsoleStreamer(mode,inputStream); + ConsoleStreamer pump = new ConsoleStreamer(mode, inputStream); pump.setParser(parser); - Thread thread = new Thread(pump,"ConsoleStreamer/" + mode); + Thread thread = new Thread(pump, "ConsoleStreamer/" + mode); thread.start(); } diff --git a/jetty-ant/src/test/java/org/eclipse/jetty/ant/JettyAntTaskTest.java b/jetty-ant/src/test/java/org/eclipse/jetty/ant/JettyAntTaskTest.java index 8ea6ab6dfc1..2d6124cfa6c 100644 --- a/jetty-ant/src/test/java/org/eclipse/jetty/ant/JettyAntTaskTest.java +++ b/jetty-ant/src/test/java/org/eclipse/jetty/ant/JettyAntTaskTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,29 +18,29 @@ package org.eclipse.jetty.ant; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - import java.net.HttpURLConnection; import java.net.URI; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.junit.jupiter.api.Test; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + public class JettyAntTaskTest { - + @Test public void testConnectorTask() throws Exception { AntBuild build = new AntBuild(MavenTestingUtils.getTestResourceFile("connector-test.xml").getAbsolutePath()); - + build.start(); - + URI uri = new URI("http://" + build.getJettyHost() + ":" + build.getJettyPort()); - + HttpURLConnection connection = (HttpURLConnection)uri.toURL().openConnection(); - + connection.connect(); assertThat("response code is 404", connection.getResponseCode(), is(404)); @@ -48,9 +48,8 @@ public class JettyAntTaskTest build.stop(); } - @Test - public void testWebApp () throws Exception + public void testWebApp() throws Exception { AntBuild build = new AntBuild(MavenTestingUtils.getTestResourceFile("webapp-test.xml").getAbsolutePath()); @@ -67,6 +66,4 @@ public class JettyAntTaskTest System.err.println("Stop build!"); build.stop(); } - - } diff --git a/jetty-bom/pom.xml b/jetty-bom/pom.xml index a1a5dc4662d..9c3b6c8b20e 100644 --- a/jetty-bom/pom.xml +++ b/jetty-bom/pom.xml @@ -1,92 +1,51 @@ - org.eclipse.jetty 4.0.0 jetty-bom - 9.4.13-SNAPSHOT Jetty :: Bom Jetty BOM artifact http://www.eclipse.org/jetty - 1995 pom - - github - https://github.com/eclipse/jetty.project/issues - - - - - Apache Software License - Version 2.0 - http://www.apache.org/licenses/LICENSE-2.0 - - - Eclipse Public License - Version 1.0 - http://www.eclipse.org/org/documents/epl-v10.php - - - - - http://www.eclipse.org/jetty - UTF-8 - 1.4 - - - - scm:git:https://github.com/eclipse/jetty.project.git - scm:git:git@github.com:eclipse/jetty.project.git - https://github.com/eclipse/jetty.project - - - - - oss.sonatype.org - Jetty Staging Repository - https://oss.sonatype.org/service/local/staging/deploy/maven2/ - - - oss.sonatype.org - Jetty Snapshot Repository - https://oss.sonatype.org/content/repositories/jetty-snapshots/ - - - jetty.eclipse.website - scp://build.eclipse.org:/home/data/httpd/download.eclipse.org/jetty/${project.version}/ - - + + org.eclipse.jetty + jetty-project + 9.4.21-SNAPSHOT + - - - - org.apache.maven.plugins - maven-release-plugin - 2.5.3 - - false - deploy - -Peclipse-release - clean install - forked-path - - - - org.apache.maven.plugins - maven-source-plugin - 3.0.1 - - true - - - - org.apache.maven.plugins - maven-javadoc-plugin - 3.0.0 - - true - - - - + + + org.codehaus.mojo + flatten-maven-plugin + 1.0.1 + + ${project.build.directory} + flattened-pom.xml + bom + true + + remove + remove + + + + + flatten + + flatten + + process-resources + + + flatten-clean + + clean + + clean + + + + @@ -94,413 +53,332 @@ org.eclipse.jetty apache-jsp - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty apache-jstl - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-alpn-client - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-alpn-java-client - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-alpn-java-server - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-alpn-openjdk8-client - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-alpn-openjdk8-server - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-alpn-conscrypt-client - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-alpn-conscrypt-server - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-alpn-server - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-annotations - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-ant - 9.4.13-SNAPSHOT - - - org.eclipse.jetty.cdi - cdi-core - 9.4.13-SNAPSHOT - - - org.eclipse.jetty.cdi - cdi-servlet - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-client - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-continuation - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-deploy - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-distribution - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT zip org.eclipse.jetty jetty-distribution - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT tar.gz org.eclipse.jetty.fcgi fcgi-client - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty.fcgi fcgi-server - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty.gcloud jetty-gcloud-session-manager - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-home - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT zip org.eclipse.jetty jetty-home - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT tar.gz org.eclipse.jetty jetty-http - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty.http2 http2-client - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty.http2 http2-common - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty.http2 http2-hpack - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty.http2 http2-http-client-transport - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty.http2 http2-server - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-http-spi - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty - jetty-infinispan - 9.4.13-SNAPSHOT + infinispan-common + 9.4.21-SNAPSHOT + + + org.eclipse.jetty + infinispan-remote-query + 9.4.21-SNAPSHOT + + + org.eclipse.jetty + infinispan-embedded-query + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-hazelcast - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-io - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-jaas - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-jaspi - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-jmx - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-jndi - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty.memcached jetty-memcached-sessions - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-nosql - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty.osgi jetty-osgi-boot - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty.osgi jetty-osgi-boot-jsp - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty.osgi jetty-osgi-boot-warurl - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty.osgi jetty-httpservice - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-plus - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-proxy - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-quickstart - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-rewrite - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-security - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-server - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-servlet - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-servlets - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-spring - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-unixsocket - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-util - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-util-ajax - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-webapp - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty.websocket javax-websocket-client-impl - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty.websocket javax-websocket-server-impl - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty.websocket websocket-api - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty.websocket websocket-client - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty.websocket websocket-common - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty.websocket websocket-server - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty.websocket websocket-servlet - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT org.eclipse.jetty jetty-xml - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT - - - - gregw - Greg Wilkins - gregw@webtide.com - Webtide, LLC - https://webtide.com - 10 - - - janb - Jan Bartel - janb@webtide.com - Webtide, LLC - https://webtide.com - 10 - - - jesse - Jesse McConnell - jesse.mcconnell@gmail.com - Webtide, LLC - https://webtide.com - -6 - - - joakime - Joakim Erdfelt - joakim.erdfelt@gmail.com - Webtide, LLC - https://webtide.com - -6 - - - sbordet - Simone Bordet - simone.bordet@gmail.com - Webtide, LLC - https://webtide.com - 1 - - - djencks - David Jencks - david.a.jencks@gmail.com - IBM - -8 - - - - - - eclipse-release - - - - true - org.apache.maven.plugins - maven-deploy-plugin - - true - - - - org.apache.maven.plugins - maven-gpg-plugin - - - sign-artifacts - verify - - sign - - - - - - - - diff --git a/jetty-cdi/cdi-2/pom.xml b/jetty-cdi/cdi-2/pom.xml deleted file mode 100644 index 1cbad1f9b17..00000000000 --- a/jetty-cdi/cdi-2/pom.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - org.eclipse.jetty.cdi - jetty-cdi-parent - 9.4.13-SNAPSHOT - - 4.0.0 - cdi-2 - Jetty :: CDI 2 - http://www.eclipse.org/jetty - jar - - ${project.groupId}.cdi2 - - - - - org.apache.maven.plugins - maven-assembly-plugin - - - package - - single - - - - config - - - - - - - - diff --git a/jetty-cdi/cdi-2/src/main/config/etc/cdi2/jetty-web-cdi2.xml b/jetty-cdi/cdi-2/src/main/config/etc/cdi2/jetty-web-cdi2.xml deleted file mode 100644 index b45e52e2608..00000000000 --- a/jetty-cdi/cdi-2/src/main/config/etc/cdi2/jetty-web-cdi2.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - -org.eclipse.jetty.util.Decorator - - - -org.eclipse.jetty.util.DecoratedObjectFactory - - - -org.eclipse.jetty.server.handler.ContextHandler. - - - -org.eclipse.jetty.server.handler.ContextHandler - - - -org.eclipse.jetty.servlet.ServletContextHandler - - - diff --git a/jetty-cdi/cdi-2/src/main/config/modules/cdi2.mod b/jetty-cdi/cdi-2/src/main/config/modules/cdi2.mod deleted file mode 100644 index df6ee4135cd..00000000000 --- a/jetty-cdi/cdi-2/src/main/config/modules/cdi2.mod +++ /dev/null @@ -1,15 +0,0 @@ -DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html - -[description] -Jetty setup to support Weld/CDI2 with WELD inside the webapp - -[depend] -deploy - -[xml] -etc/cdi2/jetty-cdi2.xml - -[license] -Weld is an open source project hosted on Github and released under the Apache 2.0 license. -http://weld.cdi-spec.org/ -http://www.apache.org/licenses/LICENSE-2.0.html diff --git a/jetty-cdi/cdi-core/pom.xml b/jetty-cdi/cdi-core/pom.xml deleted file mode 100644 index 98b5008ea99..00000000000 --- a/jetty-cdi/cdi-core/pom.xml +++ /dev/null @@ -1,71 +0,0 @@ - - - org.eclipse.jetty.cdi - jetty-cdi-parent - 9.4.13-SNAPSHOT - - 4.0.0 - cdi-core - Jetty :: CDI :: Core - - Core CDI routines for Jetty (Also useful for CDI/SE applications that dont need a server) - - http://www.eclipse.org/jetty - jar - - ${project.groupId}.core - - - - - org.eclipse.jetty - jetty-util - ${project.version} - - - javax.enterprise - cdi-api - 1.2 - - - javax.el - javax.el-api - - - - - org.jboss.weld - weld-core - ${weld.version} - test - - - org.jboss.weld.se - weld-se-core - ${weld.version} - test - - - org.eclipse.jetty.toolchain - jetty-test-helper - test - - - - - - - org.apache.maven.plugins - maven-jar-plugin - - - tests-jar - - test-jar - - - - - - - diff --git a/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/SimpleBeanStore.java b/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/SimpleBeanStore.java deleted file mode 100644 index df75e9a19cd..00000000000 --- a/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/SimpleBeanStore.java +++ /dev/null @@ -1,95 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.cdi.core; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.enterprise.context.spi.Contextual; - -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - -@Deprecated -public class SimpleBeanStore -{ - private static final Logger LOG = Log.getLogger(SimpleBeanStore.class); - - public Map, List>> beans = new HashMap<>(); - - public void addBean(ScopedInstance instance) - { - if (LOG.isDebugEnabled()) - { - LOG.debug("addBean({})",instance); - } - List> instances = getBeans(instance.bean); - if (instances == null) - { - instances = new ArrayList<>(); - beans.put(instance.bean,instances); - } - instances.add(instance); - } - - public void clear() - { - beans.clear(); - } - - public void destroy() - { - if (LOG.isDebugEnabled()) - { - LOG.debug("destroy() - {} beans",beans.size()); - } - for (List> instances : beans.values()) - { - if (LOG.isDebugEnabled()) - { - LOG.debug("destroying - {} instance(s)",instances.size()); - } - for (ScopedInstance instance : instances) - { - if (LOG.isDebugEnabled()) - { - LOG.debug("destroying instance {}",instance); - } - instance.destroy(); - } - } - } - - public List> getBeans(Contextual contextual) - { - if (LOG.isDebugEnabled()) - { - LOG.debug("getBeans({})",contextual); - } - return beans.get(contextual); - } - - @Override - public String toString() - { - return String.format("%s@%X[size=%d]",this.getClass().getSimpleName(),hashCode(),beans.size()); - } -} \ No newline at end of file diff --git a/jetty-cdi/cdi-core/src/main/resources/META-INF/beans.xml b/jetty-cdi/cdi-core/src/main/resources/META-INF/beans.xml deleted file mode 100644 index f158a71b6e5..00000000000 --- a/jetty-cdi/cdi-core/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,6 +0,0 @@ - - \ No newline at end of file diff --git a/jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/AbstractWeldTest.java b/jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/AbstractWeldTest.java deleted file mode 100644 index 7644f181ed3..00000000000 --- a/jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/AbstractWeldTest.java +++ /dev/null @@ -1,78 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.cdi.core; - -import java.util.Set; - -import javax.enterprise.context.spi.CreationalContext; -import javax.enterprise.inject.spi.Bean; - -import org.jboss.weld.environment.se.Weld; -import org.jboss.weld.environment.se.WeldContainer; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; - -public abstract class AbstractWeldTest -{ - public static class TestBean - { - public Bean bean; - public CreationalContext cCtx; - public T instance; - - public void destroy() - { - bean.destroy(instance,cCtx); - } - } - - @BeforeAll - public static void initWeld() - { - weld = new Weld(); - container = weld.initialize(); - } - - @AfterAll - public static void shutdownWeld() - { - weld.shutdown(); - } - - private static WeldContainer container; - private static Weld weld; - - @SuppressWarnings("unchecked") - public TestBean newInstance(Class clazz) throws Exception - { - TestBean testBean = new TestBean<>(); - Set> beans = container.getBeanManager().getBeans(clazz,AnyLiteral.INSTANCE); - if (beans.size() > 0) - { - testBean.bean = (Bean)beans.iterator().next(); - testBean.cCtx = container.getBeanManager().createCreationalContext(testBean.bean); - testBean.instance = (T)container.getBeanManager().getReference(testBean.bean,clazz,testBean.cCtx); - return testBean; - } - else - { - throw new Exception(String.format("Can't find class %s",clazz)); - } - } -} diff --git a/jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/logging/LeanConsoleHandler.java b/jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/logging/LeanConsoleHandler.java deleted file mode 100644 index 90fb7e33ab2..00000000000 --- a/jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/logging/LeanConsoleHandler.java +++ /dev/null @@ -1,112 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.cdi.core.logging; - -import java.text.MessageFormat; -import java.util.ResourceBundle; -import java.util.logging.Handler; -import java.util.logging.Level; -import java.util.logging.LogRecord; -import java.util.regex.Pattern; - -public class LeanConsoleHandler extends Handler -{ - public static Handler createWithLevel(Level level) - { - LeanConsoleHandler handler = new LeanConsoleHandler(); - handler.setLevel(level); - return handler; - } - - @Override - public void close() throws SecurityException - { - /* nothing to do here */ - } - - @Override - public void flush() - { - /* nothing to do here */ - } - - public synchronized String formatMessage(LogRecord record) - { - String msg = getMessage(record); - - try - { - Object params[] = record.getParameters(); - if ((params == null) || (params.length == 0)) - { - return msg; - } - - if (Pattern.compile("\\{\\d+\\}").matcher(msg).find()) - { - return MessageFormat.format(msg,params); - } - - return msg; - } - catch (Exception ex) - { - return msg; - } - } - - private String getMessage(LogRecord record) - { - ResourceBundle bundle = record.getResourceBundle(); - if (bundle != null) - { - try - { - return bundle.getString(record.getMessage()); - } - catch (java.util.MissingResourceException ex) - { - } - } - - return record.getMessage(); - } - - @Override - public void publish(LogRecord record) - { - StringBuilder buf = new StringBuilder(); - buf.append("[").append(record.getLevel().getName()).append("] "); - String logname = record.getLoggerName(); - int idx = logname.lastIndexOf('.'); - if (idx > 0) - { - logname = logname.substring(idx + 1); - } - buf.append(logname); - buf.append(": "); - buf.append(formatMessage(record)); - - System.out.println(buf.toString()); - if (record.getThrown() != null) - { - record.getThrown().printStackTrace(System.out); - } - } -} diff --git a/jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/logging/Logging.java b/jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/logging/Logging.java deleted file mode 100644 index 53077b71f25..00000000000 --- a/jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/logging/Logging.java +++ /dev/null @@ -1,46 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.cdi.core.logging; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.util.logging.LogManager; - -public class Logging -{ - public static void config() - { - ClassLoader cl = Thread.currentThread().getContextClassLoader(); - URL url = cl.getResource("logging.properties"); - if (url != null) - { - try (InputStream in = url.openStream()) - { - LogManager.getLogManager().readConfiguration(in); - } - catch (IOException e) - { - e.printStackTrace(System.err); - } - } - - System.setProperty("org.apache.commons.logging.Log","org.apache.commons.logging.impl.Jdk14Logger"); - } -} diff --git a/jetty-cdi/cdi-core/src/test/resources/logging.properties b/jetty-cdi/cdi-core/src/test/resources/logging.properties deleted file mode 100644 index c0ff63eb82c..00000000000 --- a/jetty-cdi/cdi-core/src/test/resources/logging.properties +++ /dev/null @@ -1,2 +0,0 @@ -handlers = org.eclipse.jetty.cdi.core.logging.LeanConsoleHandler -.level=INFO diff --git a/jetty-cdi/cdi-full-servlet/pom.xml b/jetty-cdi/cdi-full-servlet/pom.xml deleted file mode 100644 index 171a458c1b0..00000000000 --- a/jetty-cdi/cdi-full-servlet/pom.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - org.eclipse.jetty.cdi - jetty-cdi-parent - 9.4.13-SNAPSHOT - - 4.0.0 - cdi-full-servlet - Jetty :: CDI :: Dependencies - http://www.eclipse.org/jetty - pom - - 2.2.9.Final - - - - - org.eclipse.jetty.cdi - cdi-servlet - ${project.version} - - - - javax.annotation - javax.annotation-api - 1.2 - - - org.mortbay.jasper - apache-jsp - ${jsp.version} - - - diff --git a/jetty-cdi/cdi-servlet/pom.xml b/jetty-cdi/cdi-servlet/pom.xml deleted file mode 100644 index 1a461d6b5bf..00000000000 --- a/jetty-cdi/cdi-servlet/pom.xml +++ /dev/null @@ -1,90 +0,0 @@ - - - org.eclipse.jetty.cdi - jetty-cdi-parent - 9.4.13-SNAPSHOT - - 4.0.0 - cdi-servlet - Jetty :: CDI :: Servlet - http://www.eclipse.org/jetty - jar - - 2.2.9.Final - ${project.groupId}.servlet - - - - - org.apache.maven.plugins - maven-assembly-plugin - - - package - - single - - - - config - - - - - - - - - - - org.eclipse.jetty.cdi - cdi-core - ${project.version} - - - org.eclipse.jetty - jetty-plus - ${project.version} - - - org.eclipse.jetty - jetty-deploy - ${project.version} - - - org.jboss.weld.servlet - weld-servlet-core - ${weld.version} - - - javax.el - javax.el-api - - - org.jboss.spec.javax.el - jboss-el-api_3.0_spec - - - org.jboss.spec.javax.annotation - jboss-annotations-api_1.2_spec - - - org.jboss.spec.javax.interceptor - jboss-interceptors-api_1.2_spec - - - - - - org.eclipse.jetty - apache-jsp - ${project.version} - test - - - org.eclipse.jetty.toolchain - jetty-test-helper - test - - - diff --git a/jetty-cdi/cdi-servlet/src/main/config/etc/jetty-cdi.xml b/jetty-cdi/cdi-servlet/src/main/config/etc/jetty-cdi.xml deleted file mode 100644 index 79ebdaee517..00000000000 --- a/jetty-cdi/cdi-servlet/src/main/config/etc/jetty-cdi.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/jetty-cdi/cdi-servlet/src/main/config/modules/cdi1.mod b/jetty-cdi/cdi-servlet/src/main/config/modules/cdi1.mod deleted file mode 100644 index c2deb6124f3..00000000000 --- a/jetty-cdi/cdi-servlet/src/main/config/modules/cdi1.mod +++ /dev/null @@ -1,39 +0,0 @@ -DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html - -[description] -Experimental CDI/Weld integration -Deprecated in favour of cdi2 module. - -[depend] -deploy -annotations -plus -# JSP (and EL) are requirements for CDI and Weld -jsp - -[files] -lib/cdi/ -maven://javax.enterprise/cdi-api/1.2|lib/cdi/javax.enterprise.cdi-api-1.2.jar -maven://javax.interceptor/javax.interceptor-api/1.2|lib/cdi/javax.interceptor-api-1.2.jar -maven://javax.inject/javax.inject/1|lib/cdi/javax.inject-1.0.jar -maven://org.jboss.weld.servlet/weld-servlet-core/2.4.3.Final|lib/cdi/weld-servlet-core-2.4.3.Final.jar -maven://org.jboss.weld.environment/weld-environment-common/2.4.3.Final|lib/cdi/weld-environment-common-2.4.3.Final.jar -maven://org.jboss.weld/weld-core-impl/2.4.3.Final|lib/cdi/weld-core-impl-2.4.3.Final.jar -maven://org.jboss.classfilewriter/jboss-classfilewriter/1.1.2.Final|lib/cdi/jboss-classfilewriter-1.1.2.Final.jar -maven://org.jboss.weld/weld-spi/2.4.SP1|lib/cdi/weld-spi-2.4.SP1.jar -maven://org.jboss.weld/weld-api/2.4.SP1|lib/cdi/weld-api-2.4.SP1.jar -maven://org.jboss.logging/jboss-logging/3.2.1.Final|lib/cdi/jboss-logging-3.2.1.Final.jar - - -[lib] -lib/cdi/*.jar -lib/cdi-core-${jetty.version}.jar -lib/cdi-servlet-${jetty.version}.jar - -[xml] -etc/jetty-cdi.xml - -[license] -Weld is an open source project hosted on Github and released under the Apache 2.0 license. -http://weld.cdi-spec.org/ -http://www.apache.org/licenses/LICENSE-2.0.html diff --git a/jetty-cdi/cdi-servlet/src/main/java/org/eclipse/jetty/cdi/servlet/EmbeddedCdiHandler.java b/jetty-cdi/cdi-servlet/src/main/java/org/eclipse/jetty/cdi/servlet/EmbeddedCdiHandler.java deleted file mode 100644 index e1e128cb4f8..00000000000 --- a/jetty-cdi/cdi-servlet/src/main/java/org/eclipse/jetty/cdi/servlet/EmbeddedCdiHandler.java +++ /dev/null @@ -1,145 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.cdi.servlet; - -import java.io.IOException; -import java.util.Collections; -import java.util.Set; - -import javax.servlet.ServletContext; -import javax.servlet.http.HttpSessionActivationListener; -import javax.servlet.http.HttpSessionAttributeListener; -import javax.servlet.http.HttpSessionBindingListener; -import javax.servlet.http.HttpSessionIdListener; -import javax.servlet.http.HttpSessionListener; - -import org.eclipse.jetty.servlet.ServletContextHandler; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.util.resource.Resource; -import org.jboss.weld.environment.servlet.EnhancedListener; - -/** - * Handy {@link ServletContextHandler} implementation that hooks up - * all of the various CDI related components and listeners from Weld. - */ -public class EmbeddedCdiHandler extends ServletContextHandler -{ - private static final Logger LOG = Log.getLogger(EmbeddedCdiHandler.class); - - private static final String[] REQUIRED_BEANS_XML_PATHS = new String[] { - "/WEB-INF/beans.xml", - "/META-INF/beans.xml", - "/WEB-INF/classes/META-INF/beans.xml" - }; - - public EmbeddedCdiHandler() - { - super(); - } - - public EmbeddedCdiHandler(int options) - { - super(options); - } - - @Override - protected void doStart() throws Exception - { - // Required of CDI - Resource baseResource = getBaseResource(); - if (baseResource == null) - { - throw new NullPointerException("baseResource must be set (to so it can find the beans.xml)"); - } - - boolean foundBeansXml = false; - - // Verify that beans.xml is present, otherwise weld will fail silently. - for(String beansXmlPath: REQUIRED_BEANS_XML_PATHS) { - Resource res = baseResource.addPath(beansXmlPath); - if (res == null) - { - // not found, skip it - continue; - } - - if (res.exists()) - { - foundBeansXml = true; - } - - if (res.isDirectory()) - { - throw new IOException("Directory conflicts with expected file: " + res.getURI().toASCIIString()); - } - } - - if (!foundBeansXml) - { - StringBuilder err = new StringBuilder(); - err.append("Unable to find required beans.xml from the baseResource: "); - err.append(baseResource.getURI().toASCIIString()).append(System.lineSeparator()); - err.append("Searched for: "); - for (String beansXmlPath : REQUIRED_BEANS_XML_PATHS) - { - err.append(System.lineSeparator()); - err.append(" ").append(beansXmlPath); - } - LOG.warn("ERROR: {}",err.toString()); - throw new IOException(err.toString()); - } - - // Initialize Weld - JettyWeldInitializer.initContext(this); - - // Wire up Weld (what's usually done via the ServletContainerInitializer) - ServletContext ctx = getServletContext(); - - // Fake the call to ServletContainerInitializer - ClassLoader orig = Thread.currentThread().getContextClassLoader(); - try - { - Thread.currentThread().setContextClassLoader(ctx.getClassLoader()); - - EnhancedListener weldListener = new EnhancedListener(); - Set> classes = Collections.emptySet(); - weldListener.onStartup(classes,ctx); - - // add the rest of the Weld Listeners - ctx.addListener(weldListener); - if ((weldListener instanceof HttpSessionActivationListener) - || (weldListener instanceof HttpSessionAttributeListener) - || (weldListener instanceof HttpSessionBindingListener) - || (weldListener instanceof HttpSessionListener) - || (weldListener instanceof HttpSessionIdListener)) - { - if (getSessionHandler() != null) - getSessionHandler().addEventListener(weldListener); - } - } - finally - { - Thread.currentThread().setContextClassLoader(orig); - } - - // Let normal ServletContextHandler startup continue its merry way - super.doStart(); - } -} diff --git a/jetty-cdi/cdi-servlet/src/main/java/org/eclipse/jetty/cdi/servlet/JettyWeldInitializer.java b/jetty-cdi/cdi-servlet/src/main/java/org/eclipse/jetty/cdi/servlet/JettyWeldInitializer.java deleted file mode 100644 index 3fd5cff8665..00000000000 --- a/jetty-cdi/cdi-servlet/src/main/java/org/eclipse/jetty/cdi/servlet/JettyWeldInitializer.java +++ /dev/null @@ -1,77 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.cdi.servlet; - -import javax.naming.NamingException; -import javax.naming.Reference; - -import org.eclipse.jetty.plus.jndi.Resource; -import org.eclipse.jetty.server.handler.ContextHandler; -import org.eclipse.jetty.webapp.WebAppContext; - -/** - * Utility class suitable for initializing CDI/Weld on Embedded Jetty - */ -public class JettyWeldInitializer -{ - /** - * Initialize WebAppContext to support CDI/Weld. - *

    - * Initializes Context, then sets up WebAppContext system and server classes to allow Weld to operate from Server - * level. - *

    - * Includes {@link #initContext(ContextHandler)} behavior as well. - * @param webapp the webapp - * @throws NamingException if unable to bind BeanManager context - */ - public static void initWebApp(WebAppContext webapp) throws NamingException - { - initContext(webapp); - - // webapp cannot change / replace weld classes - webapp.addSystemClass("org.jboss.weld."); - webapp.addSystemClass("org.jboss.classfilewriter."); - webapp.addSystemClass("org.jboss.logging."); - webapp.addSystemClass("com.google.common."); - webapp.addSystemClass("org.eclipse.jetty.cdi.websocket.annotation."); - - - // don't hide weld classes from webapps (allow webapp to use ones from system classloader) - webapp.prependServerClass("-org.eclipse.jetty.cdi.websocket.annotation."); - webapp.prependServerClass("-org.eclipse.jetty.cdi.core."); - webapp.prependServerClass("-org.eclipse.jetty.cdi.servlet."); - webapp.addServerClass("-org.jboss.weld."); - webapp.addServerClass("-org.jboss.classfilewriter."); - webapp.addServerClass("-org.jboss.logging."); - webapp.addServerClass("-com.google.common."); - - } - - public static void initContext(ContextHandler handler) throws NamingException - { - // Add context specific weld container reference. - // See https://issues.jboss.org/browse/WELD-1710 - // and https://github.com/weld/core/blob/2.2.5.Final/environments/servlet/core/src/main/java/org/jboss/weld/environment/servlet/WeldServletLifecycle.java#L244-L253 - handler.setInitParameter("org.jboss.weld.environment.container.class","org.jboss.weld.environment.jetty.JettyContainer"); - - // Setup Weld BeanManager reference - Reference ref = new Reference("javax.enterprise.inject.spi.BeanManager","org.jboss.weld.resources.ManagerObjectFactory",null); - new Resource(handler,"BeanManager",ref); - } -} diff --git a/jetty-cdi/cdi-servlet/src/main/java/org/eclipse/jetty/cdi/servlet/WeldDeploymentBinding.java b/jetty-cdi/cdi-servlet/src/main/java/org/eclipse/jetty/cdi/servlet/WeldDeploymentBinding.java deleted file mode 100644 index 77eafe4481f..00000000000 --- a/jetty-cdi/cdi-servlet/src/main/java/org/eclipse/jetty/cdi/servlet/WeldDeploymentBinding.java +++ /dev/null @@ -1,60 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.cdi.servlet; - -import org.eclipse.jetty.deploy.App; -import org.eclipse.jetty.deploy.AppLifeCycle; -import org.eclipse.jetty.deploy.graph.Node; -import org.eclipse.jetty.server.handler.ContextHandler; -import org.eclipse.jetty.webapp.WebAppContext; - -/** - * Perform some basic weld configuration of WebAppContext - */ -@Deprecated -public class WeldDeploymentBinding implements AppLifeCycle.Binding -{ - @Override - public String[] getBindingTargets() - { - return new String[] { "deploying" }; - } - - @Override - public void processBinding(Node node, App app) throws Exception - { - ContextHandler handler = app.getContextHandler(); - if (handler == null) - { - throw new NullPointerException("No Handler created for App: " + app); - } - - if (handler instanceof WebAppContext) - { - // Do webapp specific init - WebAppContext webapp = (WebAppContext)handler; - JettyWeldInitializer.initWebApp(webapp); - } - else - { - // Do general init - JettyWeldInitializer.initContext(handler); - } - } -} diff --git a/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/RequestParamsDumper.java b/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/RequestParamsDumper.java deleted file mode 100644 index 5b8dc6216bc..00000000000 --- a/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/RequestParamsDumper.java +++ /dev/null @@ -1,71 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.cdi.servlet; - -import java.io.IOException; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import javax.enterprise.context.RequestScoped; -import javax.inject.Inject; -import javax.inject.Named; -import javax.servlet.http.HttpServletRequest; - -@Named("params") -@RequestScoped -public class RequestParamsDumper implements Dumper -{ - @Inject - private HttpServletRequest request; - - @Override - public void dump(PrintWriter out) throws IOException - { - out.printf("request is %s%n",request == null ? "NULL" : "PRESENT"); - - if (request != null) - { - Map params = request.getParameterMap(); - List paramNames = new ArrayList<>(); - paramNames.addAll(params.keySet()); - Collections.sort(paramNames); - - out.printf("parameters.size = [%d]%n",params.size()); - - for (String name : paramNames) - { - out.printf(" param[%s] = [",name); - boolean delim = false; - for (String val : params.get(name)) - { - if (delim) - { - out.print(", "); - } - out.print(val); - delim = true; - } - out.println("]"); - } - } - } -} diff --git a/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/WeldInitializationTest.java b/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/WeldInitializationTest.java deleted file mode 100644 index b848115927a..00000000000 --- a/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/WeldInitializationTest.java +++ /dev/null @@ -1,121 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.cdi.servlet; - -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -import java.io.File; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.URI; - -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.servlet.ServletContextHandler; -import org.eclipse.jetty.toolchain.test.MavenTestingUtils; -import org.eclipse.jetty.util.IO; -import org.eclipse.jetty.util.log.JettyLogHandler; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.util.resource.Resource; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -public class WeldInitializationTest -{ - private static final Logger LOG = Log.getLogger(WeldInitializationTest.class); - private static Server server; - private static URI serverHttpURI; - - @BeforeAll - public static void startServer() throws Exception - { - JettyLogHandler.config(); - - server = new Server(); - ServerConnector connector = new ServerConnector(server); - connector.setPort(0); - server.addConnector(connector); - - EmbeddedCdiHandler context = new EmbeddedCdiHandler(ServletContextHandler.SESSIONS); - - File baseDir = MavenTestingUtils.getTestResourcesDir(); - - context.setBaseResource(Resource.newResource(baseDir)); - context.setContextPath("/"); - server.setHandler(context); - - // Add some servlets - context.addServlet(TimeServlet.class,"/time"); - context.addServlet(RequestInfoServlet.class,"/req-info"); - - server.start(); - - String host = connector.getHost(); - if (host == null) - { - host = "localhost"; - } - int port = connector.getLocalPort(); - serverHttpURI = new URI(String.format("http://%s:%d/",host,port)); - } - - @AfterAll - public static void stopServer() - { - try - { - server.stop(); - } - catch (Exception e) - { - LOG.warn(e); - } - } - - @Test - public void testRequestParamServletDefault() throws Exception - { - HttpURLConnection http = (HttpURLConnection) serverHttpURI.resolve("req-info").toURL().openConnection(); - assertThat("response code", http.getResponseCode(), is(200)); - try(InputStream inputStream = http.getInputStream()) - { - String resp = IO.toString(inputStream); - assertThat("Response", resp, containsString("request is PRESENT")); - assertThat("Response", resp, containsString("parameters.size = [0]")); - } - } - - @Test - public void testRequestParamServletAbc() throws Exception - { - HttpURLConnection http = (HttpURLConnection) serverHttpURI.resolve("req-info?abc=123").toURL().openConnection(); - assertThat("response code", http.getResponseCode(), is(200)); - try(InputStream inputStream = http.getInputStream()) - { - String resp = IO.toString(inputStream); - assertThat("Response", resp, containsString("request is PRESENT")); - assertThat("Response", resp, containsString("parameters.size = [1]")); - assertThat("Response", resp, containsString(" param[abc] = [123]")); - } - } -} diff --git a/jetty-cdi/cdi-servlet/src/test/resources/META-INF/beans.xml b/jetty-cdi/cdi-servlet/src/test/resources/META-INF/beans.xml deleted file mode 100644 index f158a71b6e5..00000000000 --- a/jetty-cdi/cdi-servlet/src/test/resources/META-INF/beans.xml +++ /dev/null @@ -1,6 +0,0 @@ - - \ No newline at end of file diff --git a/jetty-cdi/cdi-servlet/src/test/resources/jetty-logging.properties b/jetty-cdi/cdi-servlet/src/test/resources/jetty-logging.properties deleted file mode 100644 index aaf03af93a2..00000000000 --- a/jetty-cdi/cdi-servlet/src/test/resources/jetty-logging.properties +++ /dev/null @@ -1,11 +0,0 @@ -org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog -# org.jboss.LEVEL=DEBUG -org.eclipse.jetty.LEVEL=INFO - -# org.eclipse.jetty.util.DecoratedObjectFactory.LEVEL=DEBUG -# org.eclipse.jetty.cdi.LEVEL=DEBUG - -# org.eclipse.jetty.LEVEL=DEBUG -# org.eclipse.jetty.websocket.LEVEL=DEBUG -# org.eclipse.jetty.websocket.client.LEVEL=DEBUG - diff --git a/jetty-cdi/cdi-servlet/src/test/resources/logging.properties b/jetty-cdi/cdi-servlet/src/test/resources/logging.properties deleted file mode 100644 index cfec8c7ab58..00000000000 --- a/jetty-cdi/cdi-servlet/src/test/resources/logging.properties +++ /dev/null @@ -1,2 +0,0 @@ -handlers = org.eclipse.jetty.util.log.JettyLogHandler -.level=FINE diff --git a/jetty-cdi/cdi-websocket/pom.xml b/jetty-cdi/cdi-websocket/pom.xml deleted file mode 100644 index 4f1248f7279..00000000000 --- a/jetty-cdi/cdi-websocket/pom.xml +++ /dev/null @@ -1,71 +0,0 @@ - - - org.eclipse.jetty.cdi - jetty-cdi-parent - 9.4.13-SNAPSHOT - - 4.0.0 - cdi-websocket - Jetty :: CDI :: WebSocket - http://www.eclipse.org/jetty - jar - - 2.2.9.Final - ${project.groupId}.websocket - - - - - org.eclipse.jetty.cdi - cdi-core - ${project.version} - - - org.eclipse.jetty.websocket - websocket-common - ${project.version} - - - - org.eclipse.jetty - apache-jsp - ${project.version} - test - - - org.jboss.weld - weld-core - ${weld.version} - test - - - org.jboss.weld.se - weld-se-core - ${weld.version} - test - - - org.eclipse.jetty.cdi - cdi-core - ${project.version} - tests - test - - - org.eclipse.jetty.cdi - cdi-servlet - ${project.version} - test - - - org.eclipse.jetty.websocket - javax-websocket-server-impl - ${project.version} - - - org.eclipse.jetty.toolchain - jetty-test-helper - test - - - diff --git a/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/AbstractContainerListener.java b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/AbstractContainerListener.java deleted file mode 100644 index eafe1acb469..00000000000 --- a/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/AbstractContainerListener.java +++ /dev/null @@ -1,74 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.cdi.websocket; - -import org.eclipse.jetty.util.component.Container; -import org.eclipse.jetty.util.component.LifeCycle; - -/** - * Abstract implementation of listener that needs both Container events and LifeCycle events - */ -@Deprecated -public abstract class AbstractContainerListener implements LifeCycle.Listener, Container.InheritedListener -{ - @Override - public void beanAdded(Container parent, Object child) - { - if (child instanceof LifeCycle) - { - ((LifeCycle)child).addLifeCycleListener(this); - } - } - - @Override - public void beanRemoved(Container parent, Object child) - { - if (child instanceof LifeCycle) - { - ((LifeCycle)child).removeLifeCycleListener(this); - } - } - - @Override - public void lifeCycleFailure(LifeCycle event, Throwable cause) - { - } - - @Override - public void lifeCycleStarted(LifeCycle event) - { - } - - @Override - public void lifeCycleStarting(LifeCycle event) - { - } - - @Override - public void lifeCycleStopped(LifeCycle event) - { - - } - - @Override - public void lifeCycleStopping(LifeCycle event) - { - } - -} diff --git a/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/JavaWebSocketSessionProducer.java b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/JavaWebSocketSessionProducer.java deleted file mode 100644 index 69527a26715..00000000000 --- a/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/JavaWebSocketSessionProducer.java +++ /dev/null @@ -1,57 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.cdi.websocket; - -import javax.enterprise.inject.Produces; -import javax.enterprise.inject.spi.InjectionPoint; -import javax.websocket.Session; - -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - -/** - * Producer of {@link javax.websocket.Session} instances - */ -@Deprecated -public class JavaWebSocketSessionProducer -{ - private static final Logger LOG = Log.getLogger(JavaWebSocketSessionProducer.class); - - @Produces - public Session getSession(InjectionPoint injectionPoint) - { - if (LOG.isDebugEnabled()) - { - LOG.debug("getSession({})",injectionPoint); - } - org.eclipse.jetty.websocket.api.Session sess = WebSocketScopeContext.current().getSession(); - if (sess == null) - { - throw new IllegalStateException("No Session Available"); - } - - if (sess instanceof javax.websocket.Session) - { - return (Session)sess; - } - - throw new IllegalStateException("Incompatible Session, expected <" + javax.websocket.Session.class.getName() + ">, but got <" - + sess.getClass().getName() + "> instead"); - } -} diff --git a/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/JettyWebSocketSessionProducer.java b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/JettyWebSocketSessionProducer.java deleted file mode 100644 index 66bdf5853e2..00000000000 --- a/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/JettyWebSocketSessionProducer.java +++ /dev/null @@ -1,56 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.cdi.websocket; - -import javax.enterprise.inject.Produces; -import javax.enterprise.inject.spi.InjectionPoint; - -import org.eclipse.jetty.cdi.websocket.annotation.WebSocketScope; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.api.Session; - -/** - * Producer of {@link org.eclipse.jetty.websocket.api.Session} instances - */ -@Deprecated -public class JettyWebSocketSessionProducer -{ - private static final Logger LOG = Log.getLogger(JettyWebSocketSessionProducer.class); - - @Produces - public Session getSession(InjectionPoint injectionPoint) - { - if (LOG.isDebugEnabled()) - { - LOG.debug("getSession({})",injectionPoint); - } - WebSocketScopeContext ctx = WebSocketScopeContext.current(); - if (ctx == null) - { - throw new IllegalStateException("Not in a " + WebSocketScope.class.getName()); - } - org.eclipse.jetty.websocket.api.Session sess = ctx.getSession(); - if (sess == null) - { - throw new IllegalStateException("No Session Available"); - } - return sess; - } -} diff --git a/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketCdiInitializer.java b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketCdiInitializer.java deleted file mode 100644 index 450a42ccb67..00000000000 --- a/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketCdiInitializer.java +++ /dev/null @@ -1,71 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.cdi.websocket; - -import java.util.Set; - -import javax.servlet.ServletContainerInitializer; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; - -import org.eclipse.jetty.server.handler.ContextHandler; -import org.eclipse.jetty.servlet.ServletContextHandler; -import org.eclipse.jetty.util.component.ContainerLifeCycle; -import org.eclipse.jetty.util.thread.ThreadClassLoaderScope; - -@Deprecated -public class WebSocketCdiInitializer implements ServletContainerInitializer -{ - public static void configureContext(ServletContextHandler context) throws ServletException - { - try (ThreadClassLoaderScope scope = new ThreadClassLoaderScope(context.getClassLoader())) - { - addListeners(context); - } - } - - @Override - public void onStartup(Set> c, ServletContext context) throws ServletException - { - ContextHandler handler = ContextHandler.getContextHandler(context); - - if (handler == null) - { - throw new ServletException("Not running on Jetty, WebSocket+CDI support unavailable"); - } - - if (!(handler instanceof ServletContextHandler)) - { - throw new ServletException("Not running in Jetty ServletContextHandler, WebSocket+CDI support unavailable"); - } - - ServletContextHandler jettyContext = (ServletContextHandler)handler; - try (ThreadClassLoaderScope scope = new ThreadClassLoaderScope(context.getClassLoader())) - { - addListeners(jettyContext); - } - } - - private static void addListeners(ContainerLifeCycle container) - { - WebSocketCdiListener listener = new WebSocketCdiListener(); - container.addLifeCycleListener(listener); - container.addEventListener(listener); - } -} diff --git a/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketCdiListener.java b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketCdiListener.java deleted file mode 100644 index 0fe2d7f3c8d..00000000000 --- a/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketCdiListener.java +++ /dev/null @@ -1,138 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.cdi.websocket; - -import java.util.Set; - -import javax.enterprise.inject.spi.Bean; -import javax.enterprise.inject.spi.BeanManager; -import javax.enterprise.inject.spi.CDI; - -import org.eclipse.jetty.cdi.core.AnyLiteral; -import org.eclipse.jetty.cdi.core.ScopedInstance; -import org.eclipse.jetty.util.component.ContainerLifeCycle; -import org.eclipse.jetty.util.component.LifeCycle; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.api.Session; -import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope; -import org.eclipse.jetty.websocket.common.scopes.WebSocketSessionScope; - -@Deprecated -public class WebSocketCdiListener extends AbstractContainerListener -{ - static final Logger LOG = Log.getLogger(WebSocketCdiListener.class); - - @SuppressWarnings( - { "rawtypes", "unchecked" }) - public static ScopedInstance newInstance(Class clazz) - { - BeanManager bm = CDI.current().getBeanManager(); - - ScopedInstance sbean = new ScopedInstance(); - Set> beans = bm.getBeans(clazz,AnyLiteral.INSTANCE); - if (beans.size() > 0) - { - sbean.bean = beans.iterator().next(); - sbean.creationalContext = bm.createCreationalContext(sbean.bean); - sbean.instance = bm.getReference(sbean.bean,clazz,sbean.creationalContext); - return sbean; - } - else - { - throw new RuntimeException(String.format("Can't find class %s",clazz)); - } - } - - public static class ContainerListener extends AbstractContainerListener - { - private static final Logger LOG = Log.getLogger(WebSocketCdiListener.ContainerListener.class); - private final WebSocketContainerScope container; - private final ScopedInstance wsScope; - - public ContainerListener(WebSocketContainerScope container) - { - this.container = container; - this.wsScope = newInstance(WebSocketScopeContext.class); - this.wsScope.instance.create(); - } - - @Override - public void lifeCycleStarted(LifeCycle event) - { - if (event == container) - { - if (LOG.isDebugEnabled()) - { - LOG.debug("starting websocket container [{}]",event); - } - wsScope.instance.begin(); - return; - } - - if (event instanceof WebSocketSessionScope) - { - if (LOG.isDebugEnabled()) - { - LOG.debug("starting websocket session [{}]",event); - } - wsScope.instance.setSession((Session)event); - return; - } - } - - @Override - public void lifeCycleStopped(LifeCycle event) - { - if (event == container) - { - if (LOG.isDebugEnabled()) - { - LOG.debug("stopped websocket container [{}]",event); - } - this.wsScope.instance.end(); - this.wsScope.instance.destroy(); - this.wsScope.destroy(); - } - } - } - - @Override - public void lifeCycleStarting(LifeCycle event) - { - if (event instanceof WebSocketContainerScope) - { - if (LOG.isDebugEnabled()) - { - LOG.debug("started websocket container [{}]",event); - } - ContainerListener listener = new ContainerListener((WebSocketContainerScope)event); - if (event instanceof ContainerLifeCycle) - { - ContainerLifeCycle container = (ContainerLifeCycle)event; - container.addLifeCycleListener(listener); - container.addEventListener(listener); - } - else - { - throw new RuntimeException("Unable to setup CDI against non-container: " + event.getClass().getName()); - } - } - } -} diff --git a/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketScopeContext.java b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketScopeContext.java deleted file mode 100644 index bc464855143..00000000000 --- a/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketScopeContext.java +++ /dev/null @@ -1,231 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.cdi.websocket; - -import java.lang.annotation.Annotation; -import java.util.List; -import java.util.Set; - -import javax.enterprise.context.spi.Context; -import javax.enterprise.context.spi.Contextual; -import javax.enterprise.context.spi.CreationalContext; -import javax.enterprise.inject.spi.Bean; -import javax.enterprise.inject.spi.BeanManager; -import javax.inject.Inject; - -import org.eclipse.jetty.cdi.core.AnyLiteral; -import org.eclipse.jetty.cdi.core.ScopedInstance; -import org.eclipse.jetty.cdi.core.SimpleBeanStore; -import org.eclipse.jetty.cdi.websocket.annotation.WebSocketScope; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.api.Session; - -/** - * WebSocket Scope Context. - *

    - * A CDI Context definition for how CDI will use objects defined to belong to the WebSocketScope - */ -@Deprecated -public class WebSocketScopeContext implements Context -{ - private static final Logger LOG = Log.getLogger(WebSocketScopeContext.class); - - private static ThreadLocal current = new ThreadLocal<>(); - - public static WebSocketScopeContext current() - { - return current.get(); - } - - private SimpleBeanStore beanStore; - - @Inject - private BeanManager beanManager; - - private ThreadLocal session = new ThreadLocal<>(); - - public void begin() - { - if (LOG.isDebugEnabled()) - { - LOG.debug("{} begin()",this); - } - current.set(this); - } - - public void create() - { - if (LOG.isDebugEnabled()) - { - LOG.debug("{} create()",this); - } - current.set(this); - beanStore = new SimpleBeanStore(); - } - - public void destroy() - { - if (LOG.isDebugEnabled()) - { - LOG.debug("{} destroy()",this); - } - - beanStore.destroy(); - } - - public void end() - { - if (LOG.isDebugEnabled()) - { - LOG.debug("{} end()",this); - } - beanStore.clear(); - } - - @SuppressWarnings({ "unchecked" }) - @Override - public T get(Contextual contextual) - { - if (LOG.isDebugEnabled()) - { - LOG.debug("{} get({})",this,contextual); - } - - Bean bean = (Bean)contextual; - - if (bean.getBeanClass().isAssignableFrom(Session.class)) - { - return (T)this.session; - } - - if (beanStore == null) - { - return null; - } - - List> beans = beanStore.getBeans(contextual); - - if ((beans != null) && (!beans.isEmpty())) - { - return (T)beans.get(0).instance; - } - - return null; - } - - @SuppressWarnings("unchecked") - @Override - public T get(Contextual contextual, CreationalContext creationalContext) - { - if (LOG.isDebugEnabled()) - { - LOG.debug("{} get({},{})",this,contextual,creationalContext); - } - - Bean bean = (Bean)contextual; - - if (bean.getBeanClass().isAssignableFrom(Session.class)) - { - return (T)this.session; - } - - if (beanStore == null) - { - beanStore = new SimpleBeanStore(); - } - - List> beans = beanStore.getBeans(contextual); - - if ((beans != null) && (!beans.isEmpty())) - { - for (ScopedInstance instance : beans) - { - if (instance.bean.equals(bean)) - { - return (T)instance.instance; - } - } - } - - // no bean found, create it - T t = bean.create(creationalContext); - ScopedInstance customInstance = new ScopedInstance<>(); - customInstance.bean = bean; - customInstance.creationalContext = creationalContext; - customInstance.instance = t; - beanStore.addBean(customInstance); - return t; - } - - @Override - public Class getScope() - { - return WebSocketScope.class; - } - - @Override - public boolean isActive() - { - return true; - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - public T newInstance(Class clazz) - { - if (LOG.isDebugEnabled()) - { - LOG.debug("newInstance({})",clazz); - } - Set> beans = beanManager.getBeans(clazz,AnyLiteral.INSTANCE); - if (beans.isEmpty()) - { - return null; - } - - Bean bean = beans.iterator().next(); - CreationalContext cc = beanManager.createCreationalContext(bean); - return (T)beanManager.getReference(bean,clazz,cc); - } - - public void setSession(org.eclipse.jetty.websocket.api.Session sess) - { - if (LOG.isDebugEnabled()) - { - LOG.debug("{} setSession({})",this,sess); - } - current.set(this); - this.session.set(sess); - } - - public org.eclipse.jetty.websocket.api.Session getSession() - { - if (LOG.isDebugEnabled()) - { - LOG.debug("{} getSession()",this); - } - return this.session.get(); - } - - @Override - public String toString() - { - return String.format("%s@%X[%s]",this.getClass().getSimpleName(),hashCode(),beanStore); - } -} diff --git a/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketScopeExtension.java b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketScopeExtension.java deleted file mode 100644 index 16df70b6dbd..00000000000 --- a/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketScopeExtension.java +++ /dev/null @@ -1,75 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.cdi.websocket; - -import javax.enterprise.context.Destroyed; -import javax.enterprise.context.Initialized; -import javax.enterprise.event.Observes; -import javax.enterprise.inject.spi.AfterBeanDiscovery; -import javax.enterprise.inject.spi.BeforeBeanDiscovery; -import javax.enterprise.inject.spi.Extension; - -import org.eclipse.jetty.cdi.websocket.annotation.WebSocketScope; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - -/** - * Register the various WebSocket specific components for CDI - */ -@Deprecated -public class WebSocketScopeExtension implements Extension -{ - private static final Logger LOG = Log.getLogger(WebSocketScopeExtension.class); - - public void addScope(@Observes final BeforeBeanDiscovery event) - { - if (LOG.isDebugEnabled()) - { - LOG.debug("addScope()"); - } - // Add our scope - event.addScope(WebSocketScope.class,true,false); - } - - public void registerContext(@Observes final AfterBeanDiscovery event) - { - if (LOG.isDebugEnabled()) - { - LOG.debug("registerContext()"); - } - // Register our context - event.addContext(new WebSocketScopeContext()); - } - - public void logWsScopeInit(@Observes @Initialized(WebSocketScope.class) org.eclipse.jetty.websocket.api.Session sess) - { - if (LOG.isDebugEnabled()) - { - LOG.debug("Initialized @WebSocketScope - {}",sess); - } - } - - public void logWsScopeDestroyed(@Observes @Destroyed(WebSocketScope.class) org.eclipse.jetty.websocket.api.Session sess) - { - if (LOG.isDebugEnabled()) - { - LOG.debug("Destroyed @WebSocketScope - {}",sess); - } - } -} diff --git a/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/annotation/WebSocketScope.java b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/annotation/WebSocketScope.java deleted file mode 100644 index aae39ef88bd..00000000000 --- a/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/annotation/WebSocketScope.java +++ /dev/null @@ -1,46 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.cdi.websocket.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import javax.inject.Scope; - -/** - * A CDI Context Scope for a WebSocket Session / Endpoint - *

    - * CAUTION: This is a highly speculative scope defined by Jetty. One that will likely be replaced by a formal spec later - *

    - * At the time of implementation (of this scope), no standard scope exists for websocket session lifecycle. - */ -@Scope -@Retention(RetentionPolicy.RUNTIME) -@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD }) -@Inherited -@Documented -@Deprecated -public @interface WebSocketScope -{ - -} diff --git a/jetty-cdi/cdi-websocket/src/main/resources/META-INF/beans.xml b/jetty-cdi/cdi-websocket/src/main/resources/META-INF/beans.xml deleted file mode 100644 index aeeef5387ca..00000000000 --- a/jetty-cdi/cdi-websocket/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - \ No newline at end of file diff --git a/jetty-cdi/cdi-websocket/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension b/jetty-cdi/cdi-websocket/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension deleted file mode 100644 index 93723bc0aec..00000000000 --- a/jetty-cdi/cdi-websocket/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension +++ /dev/null @@ -1 +0,0 @@ -org.eclipse.jetty.cdi.websocket.WebSocketScopeExtension \ No newline at end of file diff --git a/jetty-cdi/cdi-websocket/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer b/jetty-cdi/cdi-websocket/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer deleted file mode 100644 index f527270e524..00000000000 --- a/jetty-cdi/cdi-websocket/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer +++ /dev/null @@ -1 +0,0 @@ -org.eclipse.jetty.cdi.websocket.WebSocketCdiInitializer \ No newline at end of file diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/CheckSocket.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/CheckSocket.java deleted file mode 100644 index 46120753e87..00000000000 --- a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/CheckSocket.java +++ /dev/null @@ -1,99 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.cdi.websocket; - -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.io.IOException; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.api.Session; -import org.eclipse.jetty.websocket.api.WebSocketAdapter; -import org.eclipse.jetty.websocket.api.annotations.WebSocket; - -@WebSocket -public class CheckSocket extends WebSocketAdapter -{ - private static final Logger LOG = Log.getLogger(CheckSocket.class); - private CountDownLatch closeLatch = new CountDownLatch(1); - private CountDownLatch openLatch = new CountDownLatch(1); - public LinkedBlockingQueue textMessages = new LinkedBlockingQueue<>(); - - public void awaitClose(int timeout, TimeUnit timeunit) throws InterruptedException - { - assertTrue(closeLatch.await(timeout,timeunit), "Timeout waiting for close"); - } - - public void awaitOpen(int timeout, TimeUnit timeunit) throws InterruptedException - { - assertTrue(openLatch.await(timeout,timeunit), "Timeout waiting for open"); - } - - public LinkedBlockingQueue getTextMessages() - { - return textMessages; - } - - @Override - public void onWebSocketClose(int statusCode, String reason) - { - LOG.debug("Close: {}, {}",statusCode,reason); - super.onWebSocketClose(statusCode,reason); - closeLatch.countDown(); - } - - @Override - public void onWebSocketConnect(Session sess) - { - LOG.debug("Open: {}",sess); - super.onWebSocketConnect(sess); - openLatch.countDown(); - } - - @Override - public void onWebSocketError(Throwable cause) - { - LOG.warn("WebSocket Error",cause); - super.onWebSocketError(cause); - } - - @Override - public void onWebSocketText(String message) - { - LOG.debug("TEXT: {}",message); - textMessages.add(message); - } - - public void sendText(String msg) throws IOException - { - if (isConnected()) - { - getRemote().sendString(msg); - } - } - - public void close(int statusCode, String reason) - { - getSession().close(statusCode,reason); - } -} diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicapp/BasicAppTest.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicapp/BasicAppTest.java deleted file mode 100644 index 9574b9abca4..00000000000 --- a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicapp/BasicAppTest.java +++ /dev/null @@ -1,130 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.cdi.websocket.basicapp; - -import static org.hamcrest.Matchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -import java.io.File; -import java.net.URI; -import java.util.concurrent.TimeUnit; - -import javax.websocket.server.ServerContainer; - -import org.eclipse.jetty.cdi.servlet.EmbeddedCdiHandler; -import org.eclipse.jetty.cdi.websocket.CheckSocket; -import org.eclipse.jetty.cdi.websocket.cdiapp.InfoSocket; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.toolchain.test.MavenTestingUtils; -import org.eclipse.jetty.util.log.JettyLogHandler; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.util.resource.Resource; -import org.eclipse.jetty.websocket.api.StatusCode; -import org.eclipse.jetty.websocket.client.WebSocketClient; -import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -public class BasicAppTest -{ - private static final Logger LOG = Log.getLogger(BasicAppTest.class); - - private static Server server; - @SuppressWarnings("unused") - private static URI serverHttpURI; - private static URI serverWebsocketURI; - - @BeforeAll - public static void startServer() throws Exception - { - JettyLogHandler.config(); - - server = new Server(); - ServerConnector connector = new ServerConnector(server); - connector.setPort(0); - server.addConnector(connector); - - EmbeddedCdiHandler context = new EmbeddedCdiHandler(); - - File baseDir = MavenTestingUtils.getTestResourcesDir(); - - context.setBaseResource(Resource.newResource(baseDir)); - context.setContextPath("/"); - server.setHandler(context); - - // Add some websockets - ServerContainer container = WebSocketServerContainerInitializer.configureContext(context); - container.addEndpoint(EchoSocket.class); - container.addEndpoint(InfoSocket.class); - - server.start(); - - String host = connector.getHost(); - if (host == null) - { - host = "localhost"; - } - int port = connector.getLocalPort(); - serverHttpURI = new URI(String.format("http://%s:%d/",host,port)); - serverWebsocketURI = new URI(String.format("ws://%s:%d/",host,port)); - } - - @AfterAll - public static void stopServer() - { - try - { - server.stop(); - } - catch (Exception e) - { - LOG.warn(e); - } - } - - @Test - public void testWebSocketEcho() throws Exception - { - WebSocketClient client = new WebSocketClient(); - try - { - client.start(); - CheckSocket socket = new CheckSocket(); - client.connect(socket,serverWebsocketURI.resolve("/echo")); - - socket.awaitOpen(2,TimeUnit.SECONDS); - socket.sendText("Hello World"); - socket.close(StatusCode.NORMAL,"Test complete"); - socket.awaitClose(2,TimeUnit.SECONDS); - - assertThat("Messages received",socket.getTextMessages().size(),is(1)); - String response = socket.getTextMessages().poll(); - System.err.println(response); - - assertThat("Message[0]",response,is("Hello World")); - } - finally - { - client.stop(); - } - } -} diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicapp/EchoSocket.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicapp/EchoSocket.java deleted file mode 100644 index 2cdd1f4275a..00000000000 --- a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicapp/EchoSocket.java +++ /dev/null @@ -1,57 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.cdi.websocket.basicapp; - -import javax.websocket.CloseReason; -import javax.websocket.OnClose; -import javax.websocket.OnMessage; -import javax.websocket.OnOpen; -import javax.websocket.Session; -import javax.websocket.server.ServerEndpoint; - -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - -@ServerEndpoint("/echo") -public class EchoSocket -{ - private static final Logger LOG = Log.getLogger(EchoSocket.class); - @SuppressWarnings("unused") - private Session session; - - @OnOpen - public void onOpen(Session session) - { - LOG.debug("onOpen(): {}",session); - this.session = session; - } - - @OnClose - public void onClose(CloseReason close) - { - LOG.debug("onClose(): {}",close); - this.session = null; - } - - @OnMessage - public String onMessage(String msg) - { - return msg; - } -} diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicscope/Food.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicscope/Food.java deleted file mode 100644 index 24a0fa2d9ad..00000000000 --- a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicscope/Food.java +++ /dev/null @@ -1,100 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.cdi.websocket.basicscope; - -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; - -public class Food -{ - private boolean constructed = false; - private boolean destroyed = false; - private String name; - - @PreDestroy - void destroy() - { - destroyed = true; - } - - @Override - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (obj == null) - { - return false; - } - if (getClass() != obj.getClass()) - { - return false; - } - Food other = (Food)obj; - if (name == null) - { - if (other.name != null) - { - return false; - } - } - else if (!name.equals(other.name)) - { - return false; - } - return true; - } - - public String getName() - { - return name; - } - - @Override - public int hashCode() - { - final int prime = 31; - int result = 1; - result = (prime * result) + ((name == null) ? 0 : name.hashCode()); - return result; - } - - @PostConstruct - void init() - { - constructed = true; - } - - public boolean isConstructed() - { - return constructed; - } - - public boolean isDestroyed() - { - return destroyed; - } - - public void setName(String name) - { - this.name = name; - } -} diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicscope/ScopeBasicsTest.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicscope/ScopeBasicsTest.java deleted file mode 100644 index ef76864cde7..00000000000 --- a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicscope/ScopeBasicsTest.java +++ /dev/null @@ -1,97 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.cdi.websocket.basicscope; - -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.sameInstance; -import static org.hamcrest.MatcherAssert.assertThat; - -import java.util.Set; - -import javax.enterprise.inject.spi.Bean; - -import org.eclipse.jetty.cdi.core.AnyLiteral; -import org.eclipse.jetty.cdi.core.ScopedInstance; -import org.eclipse.jetty.cdi.core.logging.Logging; -import org.jboss.weld.environment.se.Weld; -import org.jboss.weld.environment.se.WeldContainer; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -public class ScopeBasicsTest -{ - private static Weld weld; - private static WeldContainer container; - - @BeforeAll - public static void startWeld() - { - Logging.config(); - weld = new Weld(); - container = weld.initialize(); - } - - @AfterAll - public static void stopWeld() - { - weld.shutdown(); - } - - /** - * Validation of Scope / Inject logic on non-websocket-scoped classes - * @throws Exception on test failure - */ - @Test - public void testBasicBehavior() throws Exception - { - ScopedInstance meal1Bean = newInstance(Meal.class); - Meal meal1 = meal1Bean.instance; - ScopedInstance meal2Bean = newInstance(Meal.class); - Meal meal2 = meal2Bean.instance; - - assertThat("Meals are not the same",meal1,not(sameInstance(meal2))); - - assertThat("Meal 1 Entree Constructed",meal1.getEntree().isConstructed(),is(true)); - assertThat("Meal 1 Side Constructed",meal1.getSide().isConstructed(),is(true)); - - assertThat("Meal parts not the same",meal1.getEntree(),not(sameInstance(meal1.getSide()))); - assertThat("Meal entrees are the same",meal1.getEntree(),not(sameInstance(meal2.getEntree()))); - assertThat("Meal sides are the same",meal1.getSide(),not(sameInstance(meal2.getSide()))); - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - public static ScopedInstance newInstance(Class clazz) throws Exception - { - ScopedInstance sbean = new ScopedInstance(); - Set> beans = container.getBeanManager().getBeans(clazz,AnyLiteral.INSTANCE); - if (beans.size() > 0) - { - sbean.bean = beans.iterator().next(); - sbean.creationalContext = container.getBeanManager().createCreationalContext(sbean.bean); - sbean.instance = container.getBeanManager().getReference(sbean.bean,clazz,sbean.creationalContext); - return sbean; - } - else - { - throw new Exception(String.format("Can't find class %s",clazz)); - } - } -} diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/cdiapp/CdiAppTest.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/cdiapp/CdiAppTest.java deleted file mode 100644 index 6b384fbc127..00000000000 --- a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/cdiapp/CdiAppTest.java +++ /dev/null @@ -1,185 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.cdi.websocket.cdiapp; - -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -import java.io.File; -import java.net.URI; -import java.util.concurrent.TimeUnit; - -import javax.websocket.server.ServerContainer; - -import org.eclipse.jetty.cdi.servlet.EmbeddedCdiHandler; -import org.eclipse.jetty.cdi.websocket.CheckSocket; -import org.eclipse.jetty.cdi.websocket.WebSocketCdiInitializer; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.toolchain.test.MavenTestingUtils; -import org.eclipse.jetty.util.log.JettyLogHandler; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.util.resource.Resource; -import org.eclipse.jetty.websocket.api.StatusCode; -import org.eclipse.jetty.websocket.client.WebSocketClient; -import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -public class CdiAppTest -{ - private static final Logger LOG = Log.getLogger(CdiAppTest.class); - private static Server server; - private static URI serverWebsocketURI; - - @BeforeAll - public static void startServer() throws Exception - { - JettyLogHandler.config(); - - server = new Server(); - ServerConnector connector = new ServerConnector(server); - connector.setPort(0); - server.addConnector(connector); - - EmbeddedCdiHandler context = new EmbeddedCdiHandler(); - WebSocketCdiInitializer.configureContext(context); - - File baseDir = MavenTestingUtils.getTestResourcesDir(); - - context.setBaseResource(Resource.newResource(baseDir)); - context.setContextPath("/"); - server.setHandler(context); - - // Add some websockets - ServerContainer container = WebSocketServerContainerInitializer.configureContext(context); - container.addEndpoint(EchoSocket.class); - container.addEndpoint(InfoSocket.class); - - server.start(); - - String host = connector.getHost(); - if (host == null) - { - host = "localhost"; - } - int port = connector.getLocalPort(); - serverWebsocketURI = new URI(String.format("ws://%s:%d/",host,port)); - } - - @AfterAll - public static void stopServer() - { - try - { - server.stop(); - } - catch (Exception e) - { - LOG.warn(e); - } - } - - @Test - public void testWebSocketActivated() throws Exception - { - WebSocketClient client = new WebSocketClient(); - try - { - client.start(); - CheckSocket socket = new CheckSocket(); - client.connect(socket,serverWebsocketURI.resolve("/echo")); - - socket.awaitOpen(2,TimeUnit.SECONDS); - socket.sendText("Hello"); - socket.close(StatusCode.NORMAL,"Test complete"); - socket.awaitClose(2,TimeUnit.SECONDS); - - assertThat("Messages received",socket.getTextMessages().size(),is(1)); - assertThat("Message[0]",socket.getTextMessages().poll(),is("Hello")); - } - finally - { - client.stop(); - } - } - - @Test - public void testWebSocket_Info_FieldPresence() throws Exception - { - WebSocketClient client = new WebSocketClient(); - try - { - client.start(); - CheckSocket socket = new CheckSocket(); - client.connect(socket,serverWebsocketURI.resolve("/cdi-info")); - - socket.awaitOpen(2,TimeUnit.SECONDS); - socket.sendText("info"); - socket.close(StatusCode.NORMAL,"Test complete"); - socket.awaitClose(2,TimeUnit.SECONDS); - - assertThat("Messages received",socket.getTextMessages().size(),is(1)); - String response = socket.getTextMessages().poll(); - System.err.println(response); - - assertThat("Message[0]",response, - allOf( - containsString("websocketSession is PRESENT"), - containsString("httpSession is PRESENT"), - containsString("servletContext is PRESENT") - )); - } - finally - { - client.stop(); - } - } - - @Test - public void testWebSocket_Info_DataFromCdi() throws Exception - { - WebSocketClient client = new WebSocketClient(); - try - { - client.start(); - CheckSocket socket = new CheckSocket(); - client.connect(socket,serverWebsocketURI.resolve("/cdi-info")); - - socket.awaitOpen(2,TimeUnit.SECONDS); - socket.sendText("data|stuff"); - socket.close(StatusCode.NORMAL,"Test complete"); - socket.awaitClose(2,TimeUnit.SECONDS); - - assertThat("Messages received",socket.getTextMessages().size(),is(2)); - String response = socket.getTextMessages().poll(); - System.out.println("[0]" + response); - assertThat("Message[0]",response,containsString("Hello there stuff")); - System.out.println("[1]" + socket.getTextMessages().poll()); - } - finally - { - client.stop(); - } - } -} diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/cdiapp/EchoSocket.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/cdiapp/EchoSocket.java deleted file mode 100644 index b52e3d80b35..00000000000 --- a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/cdiapp/EchoSocket.java +++ /dev/null @@ -1,57 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.cdi.websocket.cdiapp; - -import javax.websocket.CloseReason; -import javax.websocket.OnClose; -import javax.websocket.OnMessage; -import javax.websocket.OnOpen; -import javax.websocket.Session; -import javax.websocket.server.ServerEndpoint; - -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - -@ServerEndpoint("/echo") -public class EchoSocket -{ - private static final Logger LOG = Log.getLogger(EchoSocket.class); - @SuppressWarnings("unused") - private Session session; - - @OnOpen - public void onOpen(Session session) - { - LOG.debug("onOpen(): {}",session); - this.session = session; - } - - @OnClose - public void onClose(CloseReason close) - { - LOG.debug("onClose(): {}",close); - this.session = null; - } - - @OnMessage - public String onMessage(String msg) - { - return msg; - } -} diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/cdiapp/InfoSocket.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/cdiapp/InfoSocket.java deleted file mode 100644 index e93eb4b9245..00000000000 --- a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/cdiapp/InfoSocket.java +++ /dev/null @@ -1,94 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.cdi.websocket.cdiapp; - -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.logging.Level; - -import javax.enterprise.context.SessionScoped; -import javax.inject.Inject; -import javax.servlet.ServletContext; -import javax.servlet.http.HttpSession; -import javax.websocket.CloseReason; -import javax.websocket.OnClose; -import javax.websocket.OnMessage; -import javax.websocket.OnOpen; -import javax.websocket.Session; -import javax.websocket.server.ServerEndpoint; - -@ServerEndpoint("/cdi-info") -public class InfoSocket -{ - private static final java.util.logging.Logger LOG = java.util.logging.Logger.getLogger(InfoSocket.class.getName()); - - @SessionScoped - @Inject - private HttpSession httpSession; - - @Inject - private ServletContext servletContext; - - @Inject - private DataMaker dataMaker; - - private Session session; - - @OnOpen - public void onOpen(Session session) - { - LOG.log(Level.INFO,"onOpen(): {0}",session); - this.session = session; - } - - @OnClose - public void onClose(CloseReason close) - { - LOG.log(Level.INFO,"onClose(): {}",close); - this.session = null; - } - - @OnMessage - public String onMessage(String msg) - { - StringWriter str = new StringWriter(); - PrintWriter out = new PrintWriter(str); - - String args[] = msg.split("\\|"); - - switch (args[0]) - { - case "info": - out.printf("websocketSession is %s%n",asPresent(session)); - out.printf("httpSession is %s%n",asPresent(httpSession)); - out.printf("servletContext is %s%n",asPresent(servletContext)); - break; - case "data": - dataMaker.processMessage(args[1]); - break; - } - - return str.toString(); - } - - private String asPresent(Object obj) - { - return obj == null ? "NULL" : "PRESENT"; - } -} diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/BogusSession.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/BogusSession.java deleted file mode 100644 index 3e669c44ca3..00000000000 --- a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/BogusSession.java +++ /dev/null @@ -1,150 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.cdi.websocket.wsscope; - -import java.io.IOException; -import java.net.InetSocketAddress; - -import org.eclipse.jetty.websocket.api.CloseStatus; -import org.eclipse.jetty.websocket.api.RemoteEndpoint; -import org.eclipse.jetty.websocket.api.Session; -import org.eclipse.jetty.websocket.api.SuspendToken; -import org.eclipse.jetty.websocket.api.UpgradeRequest; -import org.eclipse.jetty.websocket.api.UpgradeResponse; -import org.eclipse.jetty.websocket.api.WebSocketPolicy; - -/** - * A bogus websocket Session concept object. - *

    - * Used to test the scope @Inject of this kind of Session. This is important to test, as the BogusSession does not have - * a default constructor that CDI itself can use to create this object. - *

    - * This object would need to be added to the beanstore for this scope for later @Inject to use. - */ -public class BogusSession implements Session -{ - private final String id; - - public BogusSession(String id) - { - this.id = id; - } - - @Override - public String toString() - { - return String.format("BogusSession[id=%s]",id); - } - - public String getId() - { - return id; - } - - @Override - public void close() - { - } - - @Override - public void close(CloseStatus closeStatus) - { - } - - @Override - public void close(int statusCode, String reason) - { - } - - @Override - public void disconnect() throws IOException - { - } - - @Override - public long getIdleTimeout() - { - return 0; - } - - @Override - public InetSocketAddress getLocalAddress() - { - return null; - } - - @Override - public WebSocketPolicy getPolicy() - { - return null; - } - - @Override - public String getProtocolVersion() - { - return null; - } - - @Override - public RemoteEndpoint getRemote() - { - return null; - } - - @Override - public InetSocketAddress getRemoteAddress() - { - return null; - } - - @Override - public UpgradeRequest getUpgradeRequest() - { - return null; - } - - @Override - public UpgradeResponse getUpgradeResponse() - { - return null; - } - - @Override - public boolean isOpen() - { - return false; - } - - @Override - public boolean isSecure() - { - return false; - } - - @Override - public void setIdleTimeout(long ms) - { - } - - @Override - public SuspendToken suspend() - { - return null; - } -} diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/Food.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/Food.java deleted file mode 100644 index 164ede5a403..00000000000 --- a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/Food.java +++ /dev/null @@ -1,119 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.cdi.websocket.wsscope; - -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; - -import org.eclipse.jetty.cdi.websocket.annotation.WebSocketScope; - -@WebSocketScope -public class Food -{ - private boolean constructed = false; - private boolean destroyed = false; - private String name; - - public Food() - { - // default constructor (for CDI use) - } - - public Food(String name) - { - this.name = name; - } - - @PreDestroy - void destroy() - { - destroyed = true; - } - - @Override - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (obj == null) - { - return false; - } - if (getClass() != obj.getClass()) - { - return false; - } - Food other = (Food)obj; - if (name == null) - { - if (other.name != null) - { - return false; - } - } - else if (!name.equals(other.name)) - { - return false; - } - return true; - } - - public String getName() - { - return name; - } - - @Override - public int hashCode() - { - final int prime = 31; - int result = 1; - result = (prime * result) + ((name == null) ? 0 : name.hashCode()); - return result; - } - - @PostConstruct - void init() - { - constructed = true; - } - - public boolean isConstructed() - { - return constructed; - } - - public boolean isDestroyed() - { - return destroyed; - } - - public void setName(String name) - { - this.name = name; - } - - @Override - public String toString() - { - return String.format("%s@%X[%s]",Food.class.getSimpleName(),hashCode(),name); - } -} diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/WebSocketScopeBaselineTest.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/WebSocketScopeBaselineTest.java deleted file mode 100644 index f780e60ab67..00000000000 --- a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/WebSocketScopeBaselineTest.java +++ /dev/null @@ -1,131 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.cdi.websocket.wsscope; - -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.sameInstance; -import static org.hamcrest.MatcherAssert.assertThat; - -import java.util.Set; - -import javax.enterprise.inject.spi.Bean; - -import org.eclipse.jetty.cdi.core.AnyLiteral; -import org.eclipse.jetty.cdi.core.ScopedInstance; -import org.eclipse.jetty.cdi.core.logging.Logging; -import org.eclipse.jetty.cdi.websocket.WebSocketScopeContext; -import org.eclipse.jetty.cdi.websocket.annotation.WebSocketScope; -import org.jboss.weld.environment.se.Weld; -import org.jboss.weld.environment.se.WeldContainer; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -public class WebSocketScopeBaselineTest -{ - private static Weld weld; - private static WeldContainer container; - - @BeforeAll - public static void startWeld() - { - Logging.config(); - weld = new Weld(); - container = weld.initialize(); - } - - @AfterAll - public static void stopWeld() - { - weld.shutdown(); - } - - /** - * Test behavior of {@link WebSocketScope} in basic operation. - *

    - * Food is declared as part of WebSocketScope, and as such, only 1 instance of it can exist. - * @throws Exception on test failure - */ - @Test - public void testScopeBehavior() throws Exception - { - ScopedInstance wsScopeBean = newInstance(WebSocketScopeContext.class); - WebSocketScopeContext wsScope = wsScopeBean.instance; - - wsScope.create(); - Meal meal1; - try - { - wsScope.begin(); - ScopedInstance meal1Bean = newInstance(Meal.class); - meal1 = meal1Bean.instance; - ScopedInstance meal2Bean = newInstance(Meal.class); - Meal meal2 = meal2Bean.instance; - - assertThat("Meals are not the same",meal1,not(sameInstance(meal2))); - - assertThat("Meal 1 Entree Constructed",meal1.getEntree().isConstructed(),is(true)); - assertThat("Meal 1 Side Constructed",meal1.getSide().isConstructed(),is(true)); - - /* Since Food is annotated with @WebSocketScope, there can only be one instance of it - * in use with the 2 Meal objects. - */ - assertThat("Meal parts not the same",meal1.getEntree(),sameInstance(meal1.getSide())); - assertThat("Meal entrees are the same",meal1.getEntree(),sameInstance(meal2.getEntree())); - assertThat("Meal sides are the same",meal1.getSide(),sameInstance(meal2.getSide())); - - meal1Bean.destroy(); - meal2Bean.destroy(); - } - finally - { - wsScope.end(); - } - - Food entree1 = meal1.getEntree(); - Food side1 = meal1.getSide(); - - assertThat("Meal 1 entree destroyed",entree1.isDestroyed(),is(false)); - assertThat("Meal 1 side destroyed",side1.isDestroyed(),is(false)); - wsScope.destroy(); - - // assertThat("Meal 1 entree destroyed",entree1.isDestroyed(),is(true)); - // assertThat("Meal 1 side destroyed",side1.isDestroyed(),is(true)); - wsScopeBean.destroy(); - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - public static ScopedInstance newInstance(Class clazz) throws Exception - { - ScopedInstance sbean = new ScopedInstance(); - Set> beans = container.getBeanManager().getBeans(clazz,AnyLiteral.INSTANCE); - if (beans.size() > 0) - { - sbean.bean = beans.iterator().next(); - sbean.creationalContext = container.getBeanManager().createCreationalContext(sbean.bean); - sbean.instance = container.getBeanManager().getReference(sbean.bean,clazz,sbean.creationalContext); - return sbean; - } - else - { - throw new Exception(String.format("Can't find class %s",clazz)); - } - } -} diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/WebSocketScopeSessionTest.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/WebSocketScopeSessionTest.java deleted file mode 100644 index b8ad0835803..00000000000 --- a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/WebSocketScopeSessionTest.java +++ /dev/null @@ -1,253 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.cdi.websocket.wsscope; - -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.sameInstance; -import static org.hamcrest.MatcherAssert.assertThat; - -import java.util.Set; -import java.util.concurrent.Callable; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; - -import javax.enterprise.inject.spi.Bean; - -import org.eclipse.jetty.cdi.core.AnyLiteral; -import org.eclipse.jetty.cdi.core.ScopedInstance; -import org.eclipse.jetty.cdi.core.logging.Logging; -import org.eclipse.jetty.cdi.websocket.WebSocketScopeContext; -import org.eclipse.jetty.websocket.api.Session; -import org.jboss.weld.environment.se.Weld; -import org.jboss.weld.environment.se.WeldContainer; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -public class WebSocketScopeSessionTest -{ - private static Weld weld; - private static WeldContainer container; - - @BeforeAll - public static void startWeld() - { - Logging.config(); - weld = new Weld(); - container = weld.initialize(); - } - - @AfterAll - public static void stopWeld() - { - weld.shutdown(); - } - - @Test - public void testSessionActivation() throws Exception - { - ScopedInstance wsScopeBean = newInstance(WebSocketScopeContext.class); - WebSocketScopeContext wsScope = wsScopeBean.instance; - - wsScope.create(); - try - { - // Scope 1 - wsScope.begin(); - BogusSession sess = new BogusSession("1"); - wsScope.setSession(sess); - ScopedInstance sock1Bean = newInstance(BogusSocket.class); - BogusSocket sock1 = sock1Bean.instance; - assertThat("Socket 1 Session",sock1.getSession().toString(),is(sess.toString())); - - sock1Bean.destroy(); - } - finally - { - wsScope.end(); - } - - wsScope.destroy(); - wsScopeBean.destroy(); - } - - @Test - public void testMultiSession_Sequential() throws Exception - { - ScopedInstance wsScope1Bean = newInstance(WebSocketScopeContext.class); - WebSocketScopeContext wsScope1 = wsScope1Bean.instance; - - ScopedInstance wsScope2Bean = newInstance(WebSocketScopeContext.class); - WebSocketScopeContext wsScope2 = wsScope2Bean.instance; - - wsScope1.create(); - try - { - // Scope 1 - wsScope1.begin(); - BogusSession sess = new BogusSession("1"); - wsScope1.setSession(sess); - ScopedInstance sock1Bean = newInstance(BogusSocket.class); - BogusSocket sock1 = sock1Bean.instance; - assertThat("Socket 1 Session",sock1.getSession(),sameInstance((Session)sess)); - sock1Bean.destroy(); - } - finally - { - wsScope1.end(); - } - - wsScope1.destroy(); - wsScope1Bean.destroy(); - - wsScope2.create(); - try - { - // Scope 2 - wsScope2.begin(); - BogusSession sess = new BogusSession("2"); - wsScope2.setSession(sess); - ScopedInstance sock2Bean = newInstance(BogusSocket.class); - BogusSocket sock2 = sock2Bean.instance; - assertThat("Socket 2 Session",sock2.getSession(),sameInstance((Session)sess)); - sock2Bean.destroy(); - } - finally - { - wsScope2.end(); - } - - wsScope2.destroy(); - wsScope2Bean.destroy(); - } - - @Test - public void testMultiSession_Overlapping() throws Exception - { - final CountDownLatch midLatch = new CountDownLatch(2); - final CountDownLatch end1Latch = new CountDownLatch(1); - - Callable call1 = new Callable() { - @Override - public Session call() throws Exception - { - Session ret = null; - ScopedInstance wsScope1Bean = newInstance(WebSocketScopeContext.class); - WebSocketScopeContext wsScope1 = wsScope1Bean.instance; - - wsScope1.create(); - try - { - // Scope 1 - wsScope1.begin(); - BogusSession sess = new BogusSession("1"); - wsScope1.setSession(sess); - - midLatch.countDown(); - midLatch.await(1, TimeUnit.SECONDS); - - ScopedInstance sock1Bean = newInstance(BogusSocket.class); - BogusSocket sock1 = sock1Bean.instance; - assertThat("Socket 1 Session",sock1.getSession(),sameInstance((Session)sess)); - ret = sock1.getSession(); - sock1Bean.destroy(); - } - finally - { - wsScope1.end(); - } - - wsScope1.destroy(); - wsScope1Bean.destroy(); - end1Latch.countDown(); - return ret; - } - }; - - final CountDownLatch end2Latch = new CountDownLatch(1); - - Callable call2 = new Callable() { - @Override - public Session call() throws Exception - { - Session ret = null; - ScopedInstance wsScope2Bean = newInstance(WebSocketScopeContext.class); - WebSocketScopeContext wsScope2 = wsScope2Bean.instance; - - wsScope2.create(); - try - { - // Scope 2 - wsScope2.begin(); - BogusSession sess = new BogusSession("2"); - wsScope2.setSession(sess); - ScopedInstance sock2Bean = newInstance(BogusSocket.class); - - midLatch.countDown(); - midLatch.await(1, TimeUnit.SECONDS); - - BogusSocket sock2 = sock2Bean.instance; - ret = sock2.getSession(); - assertThat("Socket 2 Session",sock2.getSession(),sameInstance((Session)sess)); - sock2Bean.destroy(); - } - finally - { - wsScope2.end(); - } - - wsScope2.destroy(); - wsScope2Bean.destroy(); - end2Latch.countDown(); - return ret; - } - }; - - ExecutorService svc = Executors.newFixedThreadPool(4); - Future fut1 = svc.submit(call1); - Future fut2 = svc.submit(call2); - - Session sess1 = fut1.get(1,TimeUnit.SECONDS); - Session sess2 = fut2.get(1,TimeUnit.SECONDS); - - assertThat("Sessions are different", sess1, not(sameInstance(sess2))); - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - public static ScopedInstance newInstance(Class clazz) - { - ScopedInstance sbean = new ScopedInstance(); - Set> beans = container.getBeanManager().getBeans(clazz,AnyLiteral.INSTANCE); - if (beans.size() > 0) - { - sbean.bean = beans.iterator().next(); - sbean.creationalContext = container.getBeanManager().createCreationalContext(sbean.bean); - sbean.instance = container.getBeanManager().getReference(sbean.bean,clazz,sbean.creationalContext); - return sbean; - } - else - { - throw new RuntimeException(String.format("Can't find class %s",clazz)); - } - } -} diff --git a/jetty-cdi/cdi-websocket/src/test/resources/META-INF/beans.xml b/jetty-cdi/cdi-websocket/src/test/resources/META-INF/beans.xml deleted file mode 100644 index f158a71b6e5..00000000000 --- a/jetty-cdi/cdi-websocket/src/test/resources/META-INF/beans.xml +++ /dev/null @@ -1,6 +0,0 @@ - - \ No newline at end of file diff --git a/jetty-cdi/cdi-websocket/src/test/resources/jetty-logging.properties b/jetty-cdi/cdi-websocket/src/test/resources/jetty-logging.properties deleted file mode 100644 index eeed11d303b..00000000000 --- a/jetty-cdi/cdi-websocket/src/test/resources/jetty-logging.properties +++ /dev/null @@ -1,15 +0,0 @@ -org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog -org.jetty.LEVEL=INFO -org.jboss.LEVEL=INFO -# org.eclipse.jetty.LEVEL=INFO - -# org.eclipse.jetty.util.component.LEVEL=DEBUG - -# org.eclipse.jetty.websocket.common.LEVEL=DEBUG -# org.eclipse.jetty.util.DecoratedObjectFactory.LEVEL=DEBUG -# org.eclipse.jetty.cdi.LEVEL=DEBUG - -# org.eclipse.jetty.LEVEL=DEBUG -# org.eclipse.jetty.websocket.LEVEL=DEBUG -# org.eclipse.jetty.websocket.client.LEVEL=DEBUG - diff --git a/jetty-cdi/cdi-websocket/src/test/resources/logging.properties b/jetty-cdi/cdi-websocket/src/test/resources/logging.properties deleted file mode 100644 index cfec8c7ab58..00000000000 --- a/jetty-cdi/cdi-websocket/src/test/resources/logging.properties +++ /dev/null @@ -1,2 +0,0 @@ -handlers = org.eclipse.jetty.util.log.JettyLogHandler -.level=FINE diff --git a/jetty-cdi/pom.xml b/jetty-cdi/pom.xml index d862017688c..6290a1486cb 100644 --- a/jetty-cdi/pom.xml +++ b/jetty-cdi/pom.xml @@ -2,24 +2,56 @@ org.eclipse.jetty jetty-project - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 - org.eclipse.jetty.cdi - jetty-cdi-parent - Jetty :: CDI :: Parent + org.eclipse.jetty + jetty-cdi + Jetty :: CDI http://www.eclipse.org/jetty - pom - - - cdi-core - cdi-servlet - cdi-full-servlet - cdi-websocket - cdi-2 - test-cdi-webapp - - + jar + + ${project.groupId}.cdi + + + + org.eclipse.jetty + jetty-util + ${project.version} + compile + + + org.eclipse.jetty + jetty-webapp + ${project.version} + compile + + + org.eclipse.jetty + jetty-annotations + ${project.version} + compile + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + package + + single + + + + config + + + + + + + diff --git a/jetty-cdi/src/main/config/etc/cdi/jetty-cdi.xml b/jetty-cdi/src/main/config/etc/cdi/jetty-cdi.xml new file mode 100644 index 00000000000..fb61892dc41 --- /dev/null +++ b/jetty-cdi/src/main/config/etc/cdi/jetty-cdi.xml @@ -0,0 +1,9 @@ + + + + + org.eclipse.jetty.cdi + + + + diff --git a/jetty-cdi/src/main/config/etc/cdi/jetty-cdi2.xml b/jetty-cdi/src/main/config/etc/cdi/jetty-cdi2.xml new file mode 100644 index 00000000000..4498da59bbe --- /dev/null +++ b/jetty-cdi/src/main/config/etc/cdi/jetty-cdi2.xml @@ -0,0 +1,18 @@ + + + + + cdi2 module is deprecated! + + + + + + /etc/cdi/jetty-web-cdi2.xml + + + + + + + diff --git a/jetty-cdi/src/main/config/etc/cdi/jetty-web-cdi2.xml b/jetty-cdi/src/main/config/etc/cdi/jetty-web-cdi2.xml new file mode 100644 index 00000000000..6227b9974fe --- /dev/null +++ b/jetty-cdi/src/main/config/etc/cdi/jetty-web-cdi2.xml @@ -0,0 +1,21 @@ + + + + + + -org.eclipse.jetty.util.Decorator + + + -org.eclipse.jetty.util.DecoratedObjectFactory + + + -org.eclipse.jetty.server.handler.ContextHandler. + + + -org.eclipse.jetty.server.handler.ContextHandler + + + -org.eclipse.jetty.servlet.ServletContextHandler + + + diff --git a/jetty-cdi/src/main/config/modules/cdi-decorate.mod b/jetty-cdi/src/main/config/modules/cdi-decorate.mod new file mode 100644 index 00000000000..f1e2b042d47 --- /dev/null +++ b/jetty-cdi/src/main/config/modules/cdi-decorate.mod @@ -0,0 +1,18 @@ +# DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + +[description] +Configures Jetty to use the "CdiDecoratingListener" as the default +CDI integration mode that allows a webapp to register it's own CDI +decorator. + +[tag] +cdi + +[provides] +cdi-mode + +[depend] +cdi + +[ini] +jetty.cdi.mode=CdiDecoratingListener \ No newline at end of file diff --git a/jetty-cdi/src/main/config/modules/cdi-spi.mod b/jetty-cdi/src/main/config/modules/cdi-spi.mod new file mode 100644 index 00000000000..5002bf967db --- /dev/null +++ b/jetty-cdi/src/main/config/modules/cdi-spi.mod @@ -0,0 +1,17 @@ +# DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + +[description] +Configures Jetty to use the "CdiSpiDecorator" that calls the CDI SPI +as the default CDI integration mode. + +[tag] +cdi + +[provides] +cdi-mode + +[depend] +cdi + +[ini] +jetty.cdi.mode=CdiSpiDecorator diff --git a/jetty-cdi/src/main/config/modules/cdi.mod b/jetty-cdi/src/main/config/modules/cdi.mod new file mode 100644 index 00000000000..8542f0693ec --- /dev/null +++ b/jetty-cdi/src/main/config/modules/cdi.mod @@ -0,0 +1,34 @@ +# DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + +[description] +Support for CDI inside the webapp. +This module does not provide CDI, but configures jetty to support various +integration modes with a CDI implementation on the webapp classpath. +CDI integration modes can be selected per webapp with the "org.eclipse.jetty.cdi" +init parameter or defaults to the mode set by the "org.eclipse.jetty.cdi" server +attribute (which is initialised from the "jetty.cdi.mode" start property). +Supported modes are: +CdiSpiDecorator - Jetty will call the CDI SPI within the webapp to decorate + objects (default). +CdiDecoratingLister - The webapp may register a decorator on the context attribute + "org.eclipse.jetty.cdi.decorator". + +[tag] +cdi + +[provides] +cdi + +[depend] +deploy + +[xml] +etc/cdi/jetty-cdi.xml + +[lib] +lib/jetty-cdi-${jetty.version}.jar +lib/apache-jsp/org.mortbay.jasper.apache-el-*.jar + +[ini] +jetty.webapp.addSystemClasses+=,org.eclipse.jetty.cdi.CdiServletContainerInitializer +jetty.webapp.addServerClasses+=,-org.eclipse.jetty.cdi.CdiServletContainerInitializer \ No newline at end of file diff --git a/jetty-cdi/src/main/config/modules/cdi2.mod b/jetty-cdi/src/main/config/modules/cdi2.mod new file mode 100644 index 00000000000..48f1387d978 --- /dev/null +++ b/jetty-cdi/src/main/config/modules/cdi2.mod @@ -0,0 +1,23 @@ +# DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + +[description] +Deprecated support for CDI integrations inside the webapp. +This module does not provide CDI, but configures jetty so that a CDI implementation +can enable itself as a decorator for Filters, Servlets and Listeners. +This modules uses the deprecated technique of exposing private Jetty decorate APIs to the CDI +implementation in the webapp. + +[tag] +cdi + +[provides] +cdi-mode + +[depend] +deploy + +[lib] +lib/apache-jsp/org.mortbay.jasper.apache-el-*.jar + +[xml] +etc/cdi/jetty-cdi2.xml diff --git a/jetty-cdi/src/main/java/org/eclipse/jetty/cdi/CdiDecoratingListener.java b/jetty-cdi/src/main/java/org/eclipse/jetty/cdi/CdiDecoratingListener.java new file mode 100644 index 00000000000..86ed47bf6cf --- /dev/null +++ b/jetty-cdi/src/main/java/org/eclipse/jetty/cdi/CdiDecoratingListener.java @@ -0,0 +1,36 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.cdi; + +import org.eclipse.jetty.servlet.DecoratingListener; +import org.eclipse.jetty.servlet.ServletContextHandler; + +/** + * A DecoratingListener that listens for "org.eclipse.jetty.cdi.decorator" + */ +class CdiDecoratingListener extends DecoratingListener +{ + public static final String MODE = "CdiDecoratingListener"; + public static final String ATTRIBUTE = "org.eclipse.jetty.cdi.decorator"; + + public CdiDecoratingListener(ServletContextHandler contextHandler) + { + super(contextHandler, ATTRIBUTE); + } +} diff --git a/jetty-cdi/src/main/java/org/eclipse/jetty/cdi/CdiServletContainerInitializer.java b/jetty-cdi/src/main/java/org/eclipse/jetty/cdi/CdiServletContainerInitializer.java new file mode 100644 index 00000000000..d8d3826c3f7 --- /dev/null +++ b/jetty-cdi/src/main/java/org/eclipse/jetty/cdi/CdiServletContainerInitializer.java @@ -0,0 +1,99 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.cdi; + +import java.util.Objects; +import java.util.Set; +import javax.servlet.ServletContainerInitializer; +import javax.servlet.ServletContext; + +import org.eclipse.jetty.annotations.AnnotationConfiguration; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.util.Loader; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + +/** + *

    A {@link ServletContainerInitializer} that introspects for a CDI API + * implementation within a web application and applies an integration + * mode if CDI is found. CDI integration modes can be selected per webapp with + * the "org.eclipse.jetty.cdi" init parameter or default to the mode set by the + * "org.eclipse.jetty.cdi" server attribute. Supported modes are:

    + *
    + *
    CdiSpiDecorator
    + *
    Jetty will call the CDI SPI within the webapp to decorate objects (default).
    + *
    CdiDecoratingLister
    + *
    The webapp may register a decorator on the context attribute + * "org.eclipse.jetty.cdi.decorator".
    + *
    + * + * @see AnnotationConfiguration.ServletContainerInitializerOrdering + */ +public class CdiServletContainerInitializer implements ServletContainerInitializer +{ + public static final String CDI_INTEGRATION_ATTRIBUTE = "org.eclipse.jetty.cdi"; + private static final Logger LOG = Log.getLogger(CdiServletContainerInitializer.class); + + @Override + public void onStartup(Set> c, ServletContext ctx) + { + try + { + ServletContextHandler context = ServletContextHandler.getServletContextHandler(ctx); + Objects.requireNonNull(context); + + // Test if CDI is in the webapp by trying to load the CDI class. + ClassLoader loader = context.getClassLoader(); + if (loader == null) + Loader.loadClass("javax.enterprise.inject.spi.CDI"); + else + loader.loadClass("javax.enterprise.inject.spi.CDI"); + + String mode = ctx.getInitParameter(CDI_INTEGRATION_ATTRIBUTE); + if (mode == null) + { + mode = (String)context.getServer().getAttribute(CDI_INTEGRATION_ATTRIBUTE); + if (mode == null) + mode = CdiSpiDecorator.MODE; + } + + switch (mode) + { + case CdiSpiDecorator.MODE: + context.getObjectFactory().addDecorator(new CdiSpiDecorator(context)); + break; + + case CdiDecoratingListener.MODE: + context.addEventListener(new CdiDecoratingListener(context)); + break; + + default: + throw new IllegalStateException(mode); + } + + context.setAttribute(CDI_INTEGRATION_ATTRIBUTE, mode); + LOG.info(mode + " enabled in " + ctx); + } + catch (UnsupportedOperationException | ClassNotFoundException e) + { + if (LOG.isDebugEnabled()) + LOG.debug("CDI not found in " + ctx, e); + } + } +} diff --git a/jetty-cdi/src/main/java/org/eclipse/jetty/cdi/CdiSpiDecorator.java b/jetty-cdi/src/main/java/org/eclipse/jetty/cdi/CdiSpiDecorator.java new file mode 100644 index 00000000000..ad4f7741674 --- /dev/null +++ b/jetty-cdi/src/main/java/org/eclipse/jetty/cdi/CdiSpiDecorator.java @@ -0,0 +1,166 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.cdi; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.util.Decorator; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + +/** + * A Decorator that invokes the CDI provider within a webapp to decorate objects created by + * the contexts {@link org.eclipse.jetty.util.DecoratedObjectFactory} + * (typically Listeners, Filters and Servlets). + * The CDI provider is invoked using {@link MethodHandle}s to avoid any CDI instance + * or dependencies within the server scope. The code invoked is equivalent to: + *
    + * public <T> T decorate(T o)
    + * {
    + *   BeanManager manager = CDI.current().getBeanManager();
    + *   manager.createInjectionTarget(manager.createAnnotatedType((Class<T>)o.getClass()))
    + *     .inject(o,manager.createCreationalContext(null));
    + *   return o;
    + * }
    + * 
    + */ +public class CdiSpiDecorator implements Decorator +{ + private static final Logger LOG = Log.getLogger(CdiServletContainerInitializer.class); + public static final String MODE = "CdiSpiDecorator"; + + private final ServletContextHandler _context; + private final Map _decorated = new HashMap<>(); + + private final MethodHandle _current; + private final MethodHandle _getBeanManager; + private final MethodHandle _createAnnotatedType; + private final MethodHandle _createInjectionTarget; + private final MethodHandle _createCreationalContext; + private final MethodHandle _inject; + private final MethodHandle _dispose; + private final MethodHandle _release; + + public CdiSpiDecorator(ServletContextHandler context) throws UnsupportedOperationException + { + _context = context; + ClassLoader classLoader = _context.getClassLoader(); + + try + { + Class cdiClass = classLoader.loadClass("javax.enterprise.inject.spi.CDI"); + Class beanManagerClass = classLoader.loadClass("javax.enterprise.inject.spi.BeanManager"); + Class annotatedTypeClass = classLoader.loadClass("javax.enterprise.inject.spi.AnnotatedType"); + Class injectionTargetClass = classLoader.loadClass("javax.enterprise.inject.spi.InjectionTarget"); + Class creationalContextClass = classLoader.loadClass("javax.enterprise.context.spi.CreationalContext"); + Class contextualClass = classLoader.loadClass("javax.enterprise.context.spi.Contextual"); + + MethodHandles.Lookup lookup = MethodHandles.lookup(); + _current = lookup.findStatic(cdiClass, "current", MethodType.methodType(cdiClass)); + _getBeanManager = lookup.findVirtual(cdiClass, "getBeanManager", MethodType.methodType(beanManagerClass)); + _createAnnotatedType = lookup.findVirtual(beanManagerClass, "createAnnotatedType", MethodType.methodType(annotatedTypeClass, Class.class)); + _createInjectionTarget = lookup.findVirtual(beanManagerClass, "createInjectionTarget", MethodType.methodType(injectionTargetClass, annotatedTypeClass)); + _createCreationalContext = lookup.findVirtual(beanManagerClass, "createCreationalContext", MethodType.methodType(creationalContextClass, contextualClass)); + _inject = lookup.findVirtual(injectionTargetClass, "inject", MethodType.methodType(Void.TYPE, Object.class, creationalContextClass)); + _dispose = lookup.findVirtual(injectionTargetClass, "dispose", MethodType.methodType(Void.TYPE, Object.class)); + _release = lookup.findVirtual(creationalContextClass, "release", MethodType.methodType(Void.TYPE)); + } + catch (Exception e) + { + throw new UnsupportedOperationException(e); + } + } + + /** + * Decorate an object. + *

    The signature of this method must match what is introspected for by the + * Jetty DecoratingListener class. It is invoked dynamically.

    + * + * @param o The object to be decorated + * @param The type of the object to be decorated + * @return The decorated object + */ + public T decorate(T o) + { + try + { + if (LOG.isDebugEnabled()) + LOG.debug("decorate {} in {}", o, _context); + + _decorated.put(o, new Decorated(o)); + } + catch (Throwable th) + { + LOG.warn("Unable to decorate " + o, th); + } + return o; + } + + /** + * Destroy a decorated object. + *

    The signature of this method must match what is introspected for by the + * Jetty DecoratingListener class. It is invoked dynamically.

    + * + * @param o The object to be destroyed + */ + public void destroy(Object o) + { + try + { + Decorated decorated = _decorated.remove(o); + if (decorated != null) + decorated.destroy(o); + } + catch (Throwable th) + { + LOG.warn("Unable to destroy " + o, th); + } + } + + private class Decorated + { + private final Object _injectionTarget; + private final Object _creationalContext; + + Decorated(Object o) throws Throwable + { + // BeanManager manager = CDI.current().getBeanManager(); + Object manager = _getBeanManager.invoke(_current.invoke()); + // AnnotatedType annotatedType = manager.createAnnotatedType((Class)o.getClass()); + Object annotatedType = _createAnnotatedType.invoke(manager, o.getClass()); + // CreationalContext creationalContext = manager.createCreationalContext(null); + _creationalContext = _createCreationalContext.invoke(manager, null); + // InjectionTarget injectionTarget = manager.createInjectionTarget(); + _injectionTarget = _createInjectionTarget.invoke(manager, annotatedType); + // injectionTarget.inject(o, creationalContext); + _inject.invoke(_injectionTarget, o, _creationalContext); + } + + public void destroy(Object o) throws Throwable + { + _dispose.invoke(_injectionTarget, o); + _release.invoke(_creationalContext); + } + } +} diff --git a/jetty-cdi/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer b/jetty-cdi/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer new file mode 100644 index 00000000000..4e6d2237721 --- /dev/null +++ b/jetty-cdi/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer @@ -0,0 +1 @@ +org.eclipse.jetty.cdi.CdiServletContainerInitializer diff --git a/jetty-cdi/test-cdi-it/pom.xml b/jetty-cdi/test-cdi-it/pom.xml deleted file mode 100644 index 2ab623e0b39..00000000000 --- a/jetty-cdi/test-cdi-it/pom.xml +++ /dev/null @@ -1,204 +0,0 @@ - - - - org.eclipse.jetty.cdi - jetty-cdi-parent - 9.4.7-SNAPSHOT - - 4.0.0 - cdi-webapp-it - jar - Jetty :: CDI :: Test :: WebApp Integration Tests - http://www.eclipse.org/jetty - - UTF-8 - UTF-8 - ${project.groupId}.cdi.webapp.it - ${project.basedir}/src/test/scripts - ${project.build.directory}/test-base - ${project.build.directory}/test-home - - - - org.eclipse.jetty - jetty-distribution - ${project.version} - zip - runtime - - - org.eclipse.jetty.cdi - test-cdi-webapp - ${project.version} - war - runtime - - - org.eclipse.jetty.toolchain - jetty-test-helper - test - - - - - - org.apache.maven.plugins - maven-deploy-plugin - - - true - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-apps-for-testing - process-test-resources - - copy-dependencies - - - test-cdi-webapp - runtime - war - true - true - true - ${test-base-dir}/webapps - - - - unpack-jetty-distro - process-test-resources - - unpack-dependencies - - - jetty-distribution - runtime - zip - true - ${test-home-dir} - true - true - - - - - - org.apache.maven.plugins - maven-failsafe-plugin - - - - integration-test - verify - - - - - - org.apache.maven.plugins - maven-antrun-plugin - - - start-jetty - pre-integration-test - - run - - - - - - Integration Test : Setup Jetty - - - - - - - - - Integration Test : Starting Jetty ... - - - - - - - - - - - Integration Test : Jetty is now available - - - - - stop-jetty - post-integration-test - - run - - - - - - Integration Test : Stop Jetty - - - - - - - - - - - - - - - - - it-windows - - - Windows - - - - cmd - /c - start-jetty.bat - stop-jetty.bat - - - - it-unix - - - unix - - - - sh - -- - setup-jetty.sh - start-jetty.sh - stop-jetty.sh - - - - diff --git a/jetty-cdi/test-cdi-it/src/test/java/org/eclipse/jetty/tests/ServerInfoIT.java b/jetty-cdi/test-cdi-it/src/test/java/org/eclipse/jetty/tests/ServerInfoIT.java deleted file mode 100644 index 53eeb45b5d6..00000000000 --- a/jetty-cdi/test-cdi-it/src/test/java/org/eclipse/jetty/tests/ServerInfoIT.java +++ /dev/null @@ -1,47 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.tests; - -import static org.hamcrest.Matchers.*; -import static org.junit.jupiter.api.Assertions.*; - -import java.net.URI; - -import org.eclipse.jetty.toolchain.test.SimpleRequest; -import org.junit.jupiter.api.Test; - -public class ServerInfoIT -{ - @Test - public void testGET() throws Exception { - URI serverURI = new URI("http://localhost:58080/cdi-webapp/"); - SimpleRequest req = new SimpleRequest(serverURI); - - // Typical response: - // context = ServletContext@o.e.j.w.WebAppContext@37cb63fd{/cdi-webapp, - // file:///tmp/jetty-0.0.0.0-58080-cdi-webapp.war-_cdi-webapp-any-417759194514596377.dir/webapp/,AVAILABLE} - // {/cdi-webapp.war}\ncontext.contextPath = /cdi-webapp\ncontext.effective-version = 3.1\n - assertThat(req.getString("serverinfo"), - allOf( - containsString("context = ServletContext@"), - containsString("context.contextPath = /cdi-webapp"), - containsString("context.effective-version = 3.1") - )); - } -} diff --git a/jetty-cdi/test-cdi-it/src/test/java/org/eclipse/jetty/tests/ws/SessionInfoIT.java b/jetty-cdi/test-cdi-it/src/test/java/org/eclipse/jetty/tests/ws/SessionInfoIT.java deleted file mode 100644 index 9ff3c239045..00000000000 --- a/jetty-cdi/test-cdi-it/src/test/java/org/eclipse/jetty/tests/ws/SessionInfoIT.java +++ /dev/null @@ -1,106 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.tests.ws; - -import static org.hamcrest.Matchers.*; -import static org.junit.jupiter.api.Assertions.*; - -import java.net.URI; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import javax.websocket.ClientEndpoint; -import javax.websocket.CloseReason; -import javax.websocket.ContainerProvider; -import javax.websocket.OnClose; -import javax.websocket.OnMessage; -import javax.websocket.OnOpen; -import javax.websocket.Session; -import javax.websocket.WebSocketContainer; - -import org.eclipse.jetty.toolchain.test.EventQueue; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.junit.jupiter.api.Test; - -public class SessionInfoIT -{ - @ClientEndpoint - public static class ClientSessionInfoSocket - { - private static final Logger LOG = Log.getLogger(SessionInfoIT.ClientSessionInfoSocket.class); - - public CountDownLatch openLatch = new CountDownLatch(1); - public CountDownLatch closeLatch = new CountDownLatch(1); - public Session session; - public EventQueue messages = new EventQueue<>(); - public CloseReason closeReason; - - @OnOpen - public void onOpen(Session session) - { - LOG.info("onOpen(): {}", session); - this.session = session; - this.openLatch.countDown(); - } - - @OnClose - public void onClose(CloseReason close) - { - LOG.info("onClose(): {}", close); - this.session = null; - this.closeReason = close; - this.closeLatch.countDown(); - } - - @OnMessage - public void onMessage(String message) - { - LOG.info("onMessage(): {}", message); - this.messages.offer(message); - } - } - - @Test - public void testSessionInfo() throws Exception - { - URI serverURI = new URI("ws://localhost:58080/cdi-webapp/"); - - WebSocketContainer container = ContainerProvider.getWebSocketContainer(); - - ClientSessionInfoSocket socket = new ClientSessionInfoSocket(); - - container.connectToServer(socket,serverURI.resolve("sessioninfo")); - - assertThat("Await open", socket.openLatch.await(1,TimeUnit.SECONDS), is(true)); - - socket.session.getBasicRemote().sendText("info"); - socket.messages.awaitEventCount(1,2,TimeUnit.SECONDS); - - System.out.printf("socket.messages.size = %s%n",socket.messages.size()); - - String msg = socket.messages.poll(); - System.out.printf("Message is [%s]%n",msg); - - assertThat("Message", msg, containsString("HttpSession = HttpSession")); - - socket.session.getBasicRemote().sendText("close"); - assertThat("Await close", socket.closeLatch.await(1,TimeUnit.SECONDS),is(true)); - } -} diff --git a/jetty-cdi/test-cdi-it/src/test/resources/jetty-logging.properties b/jetty-cdi/test-cdi-it/src/test/resources/jetty-logging.properties deleted file mode 100644 index 6e5209e3846..00000000000 --- a/jetty-cdi/test-cdi-it/src/test/resources/jetty-logging.properties +++ /dev/null @@ -1,10 +0,0 @@ -org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog -# org.jboss.LEVEL=DEBUG -org.eclipse.jetty.LEVEL=INFO - -# org.eclipse.jetty.util.DecoratedObjectFactory.LEVEL=DEBUG - -# org.eclipse.jetty.LEVEL=DEBUG -# org.eclipse.jetty.websocket.LEVEL=DEBUG -# org.eclipse.jetty.websocket.client.LEVEL=DEBUG - diff --git a/jetty-cdi/test-cdi-it/src/test/scripts/setup-jetty.sh b/jetty-cdi/test-cdi-it/src/test/scripts/setup-jetty.sh deleted file mode 100755 index 3dc240f073f..00000000000 --- a/jetty-cdi/test-cdi-it/src/test/scripts/setup-jetty.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env bash - -JAVA_HOME=$1 -JETTY_HOME=$2 -JETTY_BASE=$3 - -echo \${java.home} : $JAVA_HOME -echo \${jetty.home} : $JETTY_HOME -echo \${jetty.base} : $JETTY_BASE - -cd "$JETTY_BASE" - -"$JAVA_HOME/bin/java" -jar "$JETTY_HOME/start.jar" \ - --approve-all-licenses \ - --add-to-start=deploy,http,annotations,websocket,cdi,logging - -"$JAVA_HOME/bin/java" -jar "$JETTY_HOME/start.jar" \ - --version - diff --git a/jetty-cdi/test-cdi-it/src/test/scripts/start-jetty.sh b/jetty-cdi/test-cdi-it/src/test/scripts/start-jetty.sh deleted file mode 100755 index ea7843bf256..00000000000 --- a/jetty-cdi/test-cdi-it/src/test/scripts/start-jetty.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env bash - -JAVA_HOME=$1 -JETTY_HOME=$2 -JETTY_BASE=$3 - -echo \${java.home} : $JAVA_HOME -echo \${jetty.home} : $JETTY_HOME -echo \${jetty.base} : $JETTY_BASE - -cd "$JETTY_BASE" - -"$JAVA_HOME/bin/java" -jar "$JETTY_HOME/start.jar" \ - jetty.http.port=58080 \ - STOP.PORT=58181 STOP.KEY=it - - diff --git a/jetty-cdi/test-cdi-it/src/test/scripts/stop-jetty.sh b/jetty-cdi/test-cdi-it/src/test/scripts/stop-jetty.sh deleted file mode 100755 index 32e40774908..00000000000 --- a/jetty-cdi/test-cdi-it/src/test/scripts/stop-jetty.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash - -JAVA_HOME=$1 -JETTY_HOME=$2 -JETTY_BASE=$3 - -cd "$JETTY_BASE" -"$JAVA_HOME/bin/java" -jar "$JETTY_HOME/start.jar" \ - --stop STOP.PORT=58181 STOP.KEY=it - - diff --git a/jetty-cdi/test-cdi-webapp/pom.xml b/jetty-cdi/test-cdi-webapp/pom.xml deleted file mode 100644 index 8c4b0aabc35..00000000000 --- a/jetty-cdi/test-cdi-webapp/pom.xml +++ /dev/null @@ -1,87 +0,0 @@ - - - - org.eclipse.jetty.cdi - jetty-cdi-parent - 9.4.13-SNAPSHOT - - 4.0.0 - test-cdi-webapp - war - Jetty :: CDI :: Test :: WebApp - http://www.eclipse.org/jetty - - UTF-8 - ${project.groupId}.cdi.webapp.noweld - - - - javax.servlet - javax.servlet-api - provided - - - javax.websocket - javax.websocket-api - provided - - - javax.enterprise - cdi-api - 1.1 - provided - - - org.jboss.weld.servlet - weld-servlet - ${weld.version} - test - - - - cdi-webapp - - - org.apache.maven.plugins - maven-deploy-plugin - - - true - - - - org.apache.maven.plugins - maven-assembly-plugin - - - with-weld - package - - single - - - - src/assembly/with-weld.xml - - - - - - - org.eclipse.jetty - jetty-maven-plugin - ${project.version} - - - - - org.eclipse.jetty.cdi - cdi-full-servlet - ${project.version} - pom - - - - - - diff --git a/jetty-cdi/test-cdi-webapp/src/assembly/with-weld.xml b/jetty-cdi/test-cdi-webapp/src/assembly/with-weld.xml deleted file mode 100644 index ca1747115dd..00000000000 --- a/jetty-cdi/test-cdi-webapp/src/assembly/with-weld.xml +++ /dev/null @@ -1,31 +0,0 @@ - - with-weld - - war - - false - - - ${project.basedir}/src/main/webapp - / - - - ${project.build.outputDirectory} - /WEB-INF/classes - - - - - /WEB-INF/lib - true - false - test - - *:cdi-api - *:weld-servlet - - - - diff --git a/jetty-cdi/test-cdi-webapp/src/main/java/org/eclipse/jetty/tests/ws/SessionInfoSocket.java b/jetty-cdi/test-cdi-webapp/src/main/java/org/eclipse/jetty/tests/ws/SessionInfoSocket.java deleted file mode 100644 index 64701462a69..00000000000 --- a/jetty-cdi/test-cdi-webapp/src/main/java/org/eclipse/jetty/tests/ws/SessionInfoSocket.java +++ /dev/null @@ -1,98 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.tests.ws; - -import javax.inject.Inject; -import javax.servlet.http.HttpSession; -import javax.websocket.OnMessage; -import javax.websocket.OnOpen; -import javax.websocket.RemoteEndpoint; -import javax.websocket.Session; -import javax.websocket.server.ServerEndpoint; - -import org.eclipse.jetty.tests.logging.JULog; - -@ServerEndpoint(value = "/sessioninfo") -public class SessionInfoSocket -{ - @Inject - private JULog LOG; - - @Inject - private HttpSession httpSession; - - private Session wsSession; - - @OnOpen - public void onOpen(Session session) - { - LOG.info("onOpen({0})",asClassId(session)); - this.wsSession = session; - } - - @OnMessage - public void onMessage(String message) - { - LOG.info("onMessage({0})",quoted(message)); - - try - { - RemoteEndpoint.Basic remote = wsSession.getBasicRemote(); - LOG.info("Remote.Basic: {0}", remote); - - if ("info".equalsIgnoreCase(message)) - { - LOG.info("returning 'info' details"); - remote.sendText("HttpSession = " + httpSession); - } - else if ("close".equalsIgnoreCase(message)) - { - LOG.info("closing session"); - wsSession.close(); - } - else - { - LOG.info("echoing message as-is"); - remote.sendText(message); - } - } - catch (Throwable t) - { - LOG.warn(t); - } - } - - private String asClassId(Object obj) - { - if (obj == null) - { - return ""; - } - return String.format("%s@%X",obj.getClass().getName(),obj.hashCode()); - } - - private String quoted(String str) - { - if (str == null) - { - return ""; - } - return '"' + str + '"'; - } -} diff --git a/jetty-cdi/test-cdi-webapp/src/main/webapp/WEB-INF/beans.xml b/jetty-cdi/test-cdi-webapp/src/main/webapp/WEB-INF/beans.xml deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/jetty-client/pom.xml b/jetty-client/pom.xml index 6062d1e3c03..b17719f1640 100644 --- a/jetty-client/pom.xml +++ b/jetty-client/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 @@ -105,6 +105,7 @@ ${project.version} true + org.eclipse.jetty jetty-server @@ -117,6 +118,17 @@ ${project.version} test + + org.apache.kerby + kerb-simplekdc + 1.1.1 + test + + + org.slf4j + slf4j-simple + test + org.eclipse.jetty.toolchain jetty-test-helper diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/AbstractConnectionPool.java b/jetty-client/src/main/java/org/eclipse/jetty/client/AbstractConnectionPool.java index 29d85e8fd79..b3b307b96bc 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/AbstractConnectionPool.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/AbstractConnectionPool.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -28,7 +28,6 @@ import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; -import org.eclipse.jetty.util.component.ContainerLifeCycle; import org.eclipse.jetty.util.component.Dumpable; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -39,7 +38,7 @@ public abstract class AbstractConnectionPool implements ConnectionPool, Dumpable private static final Logger LOG = Log.getLogger(AbstractConnectionPool.class); private final AtomicBoolean closed = new AtomicBoolean(); - + /** * The connectionCount encodes both the total connections plus the pending connection counts, so both can be atomically changed. * The bottom 32 bits represent the total connections and the top 32 bits represent the pending connections. @@ -107,18 +106,18 @@ public abstract class AbstractConnectionPool implements ConnectionPool, Dumpable int total = AtomicBiInteger.getLo(encoded); if (LOG.isDebugEnabled()) - LOG.debug("tryCreate {}/{} connections {}/{} pending",total,maxConnections,pending,maxPending); - + LOG.debug("tryCreate {}/{} connections {}/{} pending", total, maxConnections, pending, maxPending); + if (total >= maxConnections) return; - if (maxPending>=0 && pending>=maxPending) + if (maxPending >= 0 && pending >= maxPending) return; - - if (connections.compareAndSet(encoded,pending+1,total+1)) + + if (connections.compareAndSet(encoded, pending + 1, total + 1)) { if (LOG.isDebugEnabled()) - LOG.debug("newConnection {}/{} connections {}/{} pending", total+1, maxConnections, pending+1, maxPending); + LOG.debug("newConnection {}/{} connections {}/{} pending", total + 1, maxConnections, pending + 1, maxPending); destination.newConnection(new Promise() { @@ -126,8 +125,8 @@ public abstract class AbstractConnectionPool implements ConnectionPool, Dumpable public void succeeded(Connection connection) { if (LOG.isDebugEnabled()) - LOG.debug("Connection {}/{} creation succeeded {}", total+1, maxConnections, connection); - connections.add(-1,0); + LOG.debug("Connection {}/{} creation succeeded {}", total + 1, maxConnections, connection); + connections.add(-1, 0); onCreated(connection); proceed(); } @@ -136,8 +135,8 @@ public abstract class AbstractConnectionPool implements ConnectionPool, Dumpable public void failed(Throwable x) { if (LOG.isDebugEnabled()) - LOG.debug("Connection " + (total+1) + "/" + maxConnections + " creation failed", x); - connections.add(-1,-1); + LOG.debug("Connection " + (total + 1) + "/" + maxConnections + " creation failed", x); + connections.add(-1, -1); requester.failed(x); } }); @@ -200,7 +199,7 @@ public abstract class AbstractConnectionPool implements ConnectionPool, Dumpable { if (closed.compareAndSet(false, true)) { - connections.set(0,0); + connections.set(0, 0); } } @@ -212,6 +211,6 @@ public abstract class AbstractConnectionPool implements ConnectionPool, Dumpable @Override public String dump() { - return ContainerLifeCycle.dump(this); + return Dumpable.dump(this); } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/AbstractConnectorHttpClientTransport.java b/jetty-client/src/main/java/org/eclipse/jetty/client/AbstractConnectorHttpClientTransport.java index 669ba41d757..faa502daf3b 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/AbstractConnectorHttpClientTransport.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/AbstractConnectorHttpClientTransport.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -118,9 +118,9 @@ public abstract class AbstractConnectorHttpClientTransport extends AbstractHttpC if (channel != null) channel.close(); } - catch (IOException xx) + catch (IOException ignored) { - LOG.ignore(xx); + LOG.ignore(ignored); } finally { @@ -148,6 +148,11 @@ public abstract class AbstractConnectorHttpClientTransport extends AbstractHttpC return new ClientSelectorManager(client, getSelectors()); } + protected SelectorManager getSelectorManager() + { + return selectorManager; + } + protected class ClientSelectorManager extends SelectorManager { private final HttpClient client; diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/AbstractHttpClientTransport.java b/jetty-client/src/main/java/org/eclipse/jetty/client/AbstractHttpClientTransport.java index fcbeb0a17c7..3a601f7c237 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/AbstractHttpClientTransport.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/AbstractHttpClientTransport.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/AsyncContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/AsyncContentProvider.java index ccd55245b57..9c7aa73d68e 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/AsyncContentProvider.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/AsyncContentProvider.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -30,16 +30,16 @@ public interface AsyncContentProvider extends ContentProvider /** * @param listener the listener to be notified of content availability */ - public void setListener(Listener listener); + void setListener(Listener listener); /** * A listener that is notified of content availability */ - public interface Listener extends EventListener + interface Listener extends EventListener { /** * Callback method invoked when content is available */ - public void onContent(); + void onContent(); } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/AuthenticationProtocolHandler.java b/jetty-client/src/main/java/org/eclipse/jetty/client/AuthenticationProtocolHandler.java index b0441b334cb..4f3d3a48fa7 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/AuthenticationProtocolHandler.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/AuthenticationProtocolHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -23,6 +23,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -37,19 +38,20 @@ import org.eclipse.jetty.client.api.Result; import org.eclipse.jetty.client.util.BufferingResponseListener; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.QuotedCSV; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; public abstract class AuthenticationProtocolHandler implements ProtocolHandler { - public static final int DEFAULT_MAX_CONTENT_LENGTH = 16*1024; + public static final int DEFAULT_MAX_CONTENT_LENGTH = 16 * 1024; public static final Logger LOG = Log.getLogger(AuthenticationProtocolHandler.class); private final HttpClient client; private final int maxContentLength; private final ResponseNotifier notifier; - private static final Pattern CHALLENGE_PATTERN = Pattern.compile("(?[!#$%&'*+\\-.^_`|~0-9A-Za-z]+)|(?:(?[!#$%&'*+\\-.^_`|~0-9A-Za-z]+)\\s+)?(?:(?[a-zA-Z0-9\\-._~+\\/]+=*)|(?[!#$%&'*+\\-.^_`|~0-9A-Za-z]+)\\s*=\\s*(?:(?.*)))"); + private static final Pattern CHALLENGE_PATTERN = Pattern.compile("(?[!#$%&'*+\\-.^_`|~0-9A-Za-z]+)|(?:(?[!#$%&'*+\\-.^_`|~0-9A-Za-z]+)\\s+)?(?:(?[a-zA-Z0-9\\-._~+/]+=*)|(?[!#$%&'*+\\-.^_`|~0-9A-Za-z]+)\\s*=\\s*(?:(?.*)))"); protected AuthenticationProtocolHandler(HttpClient client, int maxContentLength) { @@ -78,18 +80,17 @@ public abstract class AuthenticationProtocolHandler implements ProtocolHandler return new AuthenticationListener(); } - protected List getHeaderInfo(String header) throws IllegalArgumentException { List headerInfos = new ArrayList<>(); Matcher m; - for(String value : new QuotedCSV(true, header)) + for (String value : new QuotedCSV(true, header)) { m = CHALLENGE_PATTERN.matcher(value); if (m.matches()) { - if(m.group("schemeOnly") != null) + if (m.group("schemeOnly") != null) { headerInfos.add(new HeaderInfo(getAuthorizationHeader(), m.group(1), new HashMap<>())); continue; @@ -122,7 +123,6 @@ public abstract class AuthenticationProtocolHandler implements ProtocolHandler return headerInfos; } - private class AuthenticationListener extends BufferingResponseListener { private AuthenticationListener() @@ -217,6 +217,8 @@ public abstract class AuthenticationProtocolHandler implements ProtocolHandler path = request.getPath(); } Request newRequest = client.copyRequest(request, requestURI); + // Disable the timeout so that only the one from the initial request applies. + newRequest.timeout(0, TimeUnit.MILLISECONDS); if (path != null) newRequest.path(path); @@ -225,13 +227,12 @@ public abstract class AuthenticationProtocolHandler implements ProtocolHandler copyIfAbsent(request, newRequest, HttpHeader.AUTHORIZATION); copyIfAbsent(request, newRequest, HttpHeader.PROXY_AUTHORIZATION); - newRequest.onResponseSuccess(r -> client.getAuthenticationStore().addAuthenticationResult(authnResult)); - + AfterAuthenticationListener listener = new AfterAuthenticationListener(authnResult); Connection connection = (Connection)request.getAttributes().get(Connection.class.getName()); if (connection != null) - connection.send(newRequest, null); + connection.send(newRequest, listener); else - newRequest.send(null); + newRequest.send(listener); } catch (Throwable x) { @@ -289,7 +290,7 @@ public abstract class AuthenticationProtocolHandler implements ProtocolHandler { result.addAll(getHeaderInfo(value)); } - catch(IllegalArgumentException e) + catch (IllegalArgumentException e) { if (LOG.isDebugEnabled()) LOG.debug("Failed to parse authentication header", e); @@ -298,4 +299,22 @@ public abstract class AuthenticationProtocolHandler implements ProtocolHandler return result; } } + + private class AfterAuthenticationListener extends Response.Listener.Adapter + { + private final Authentication.Result authenticationResult; + + private AfterAuthenticationListener(Authentication.Result authenticationResult) + { + this.authenticationResult = authenticationResult; + } + + @Override + public void onSuccess(Response response) + { + int status = response.getStatus(); + if (HttpStatus.isSuccess(status) || HttpStatus.isRedirection(status)) + client.getAuthenticationStore().addAuthenticationResult(authenticationResult); + } + } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/ConnectionPool.java b/jetty-client/src/main/java/org/eclipse/jetty/client/ConnectionPool.java index d2895b64fd8..7cd8a3088de 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/ConnectionPool.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/ConnectionPool.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/ContentDecoder.java b/jetty-client/src/main/java/org/eclipse/jetty/client/ContentDecoder.java index ad7e78332e6..36201e7bd3f 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/ContentDecoder.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/ContentDecoder.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -33,7 +33,16 @@ public interface ContentDecoder * @param buffer the buffer containing encoded bytes * @return a buffer containing decoded bytes, if any */ - public abstract ByteBuffer decode(ByteBuffer buffer); + ByteBuffer decode(ByteBuffer buffer); + + /** + *

    Releases the ByteBuffer returned by {@link #decode(ByteBuffer)}.

    + * + * @param decoded the ByteBuffer returned by {@link #decode(ByteBuffer)} + */ + default void release(ByteBuffer decoded) + { + } /** * Factory for {@link ContentDecoder}s; subclasses must implement {@link #newContentDecoder()}. @@ -44,7 +53,7 @@ public interface ContentDecoder * {@link Factory} instances are configured in {@link HttpClient} via * {@link HttpClient#getContentDecoderFactories()}. */ - public static abstract class Factory + abstract class Factory { private final String encoding; @@ -64,8 +73,10 @@ public interface ContentDecoder @Override public boolean equals(Object obj) { - if (this == obj) return true; - if (!(obj instanceof Factory)) return false; + if (this == obj) + return true; + if (!(obj instanceof Factory)) + return false; Factory that = (Factory)obj; return encoding.equals(that.encoding); } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/ContinueProtocolHandler.java b/jetty-client/src/main/java/org/eclipse/jetty/client/ContinueProtocolHandler.java index 16825e704a2..fde872d55ce 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/ContinueProtocolHandler.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/ContinueProtocolHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/DuplexConnectionPool.java b/jetty-client/src/main/java/org/eclipse/jetty/client/DuplexConnectionPool.java index 5261751a62f..bfccf42c6b3 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/DuplexConnectionPool.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/DuplexConnectionPool.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -35,7 +35,8 @@ import org.eclipse.jetty.client.api.Destination; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; -import org.eclipse.jetty.util.component.ContainerLifeCycle; +import org.eclipse.jetty.util.component.Dumpable; +import org.eclipse.jetty.util.component.DumpableCollection; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.thread.Sweeper; @@ -239,20 +240,24 @@ public class DuplexConnectionPool extends AbstractConnectionPool implements Swee @Override public void dump(Appendable out, String indent) throws IOException { - List connections = new ArrayList<>(); + DumpableCollection active; + DumpableCollection idle; lock(); try { - connections.addAll(activeConnections); - connections.addAll(idleConnections); + active = new DumpableCollection("active", new ArrayList<>(activeConnections)); + idle = new DumpableCollection("idle", new ArrayList<>(idleConnections)); } finally { unlock(); } + dump(out, indent, active, idle); + } - ContainerLifeCycle.dumpObject(out, this); - ContainerLifeCycle.dump(out, indent, connections); + protected void dump(Appendable out, String indent, Object... items) throws IOException + { + Dumpable.dumpObjects(out, indent, this, items); } @Override @@ -263,8 +268,8 @@ public class DuplexConnectionPool extends AbstractConnectionPool implements Swee try { toSweep = activeConnections.stream() - .filter(connection -> connection instanceof Sweeper.Sweepable) - .collect(Collectors.toList()); + .filter(connection -> connection instanceof Sweeper.Sweepable) + .collect(Collectors.toList()); } finally { @@ -277,11 +282,11 @@ public class DuplexConnectionPool extends AbstractConnectionPool implements Swee { boolean removed = remove(connection, true); LOG.warn("Connection swept: {}{}{} from active connections{}{}", - connection, - System.lineSeparator(), - removed ? "Removed" : "Not removed", - System.lineSeparator(), - dump()); + connection, + System.lineSeparator(), + removed ? "Removed" : "Not removed", + System.lineSeparator(), + dump()); } } @@ -305,11 +310,11 @@ public class DuplexConnectionPool extends AbstractConnectionPool implements Swee } return String.format("%s@%x[c=%d/%d,a=%d,i=%d]", - getClass().getSimpleName(), - hashCode(), - getConnectionCount(), - getMaxConnectionCount(), - activeSize, - idleSize); + getClass().getSimpleName(), + hashCode(), + getConnectionCount(), + getMaxConnectionCount(), + activeSize, + idleSize); } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/GZIPContentDecoder.java b/jetty-client/src/main/java/org/eclipse/jetty/client/GZIPContentDecoder.java index bedd8a61ae8..7699a98dad8 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/GZIPContentDecoder.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/GZIPContentDecoder.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,6 +18,8 @@ package org.eclipse.jetty.client; +import java.nio.ByteBuffer; + import org.eclipse.jetty.io.ByteBufferPool; /** @@ -25,7 +27,7 @@ import org.eclipse.jetty.io.ByteBufferPool; */ public class GZIPContentDecoder extends org.eclipse.jetty.http.GZIPContentDecoder implements ContentDecoder { - private static final int DEFAULT_BUFFER_SIZE = 2048; + public static final int DEFAULT_BUFFER_SIZE = 8192; public GZIPContentDecoder() { @@ -34,7 +36,7 @@ public class GZIPContentDecoder extends org.eclipse.jetty.http.GZIPContentDecode public GZIPContentDecoder(int bufferSize) { - this(null,bufferSize); + this(null, bufferSize); } public GZIPContentDecoder(ByteBufferPool byteBufferPool, int bufferSize) @@ -42,6 +44,13 @@ public class GZIPContentDecoder extends org.eclipse.jetty.http.GZIPContentDecode super(byteBufferPool, bufferSize); } + @Override + protected boolean decodedChunk(ByteBuffer chunk) + { + super.decodedChunk(chunk); + return true; + } + /** * Specialized {@link ContentDecoder.Factory} for the "gzip" encoding. */ diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpAuthenticationStore.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpAuthenticationStore.java index 359c0a77575..54122c17d9a 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpAuthenticationStore.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpAuthenticationStore.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpChannel.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpChannel.java index 37230b902ec..a8699fba543 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpChannel.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpChannel.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -40,7 +40,7 @@ public abstract class HttpChannel { _totalTimeout.destroy(); } - + public HttpDestination getHttpDestination() { return _destination; diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java index 308e79daf6c..82b418f6911 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,6 +18,7 @@ package org.eclipse.jetty.client; +import java.io.IOException; import java.net.CookieManager; import java.net.CookiePolicy; import java.net.CookieStore; @@ -70,6 +71,7 @@ import org.eclipse.jetty.util.SocketAddressResolver; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.component.ContainerLifeCycle; +import org.eclipse.jetty.util.component.DumpableCollection; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.ssl.SslContextFactory; @@ -179,12 +181,17 @@ public class HttpClient extends ContainerLifeCycle public HttpClient(HttpClientTransport transport, SslContextFactory sslContextFactory) { this.transport = transport; - if (sslContextFactory == null) - { - sslContextFactory = new SslContextFactory(false); - sslContextFactory.setEndpointIdentificationAlgorithm("HTTPS"); - } + addBean(transport); this.sslContextFactory = sslContextFactory; + addBean(sslContextFactory); + addBean(handlers); + addBean(decoderFactories); + } + + @Override + public void dump(Appendable out, String indent) throws IOException + { + dumpObjects(out, indent, new DumpableCollection("requestListeners", requestListeners)); } public HttpClientTransport getTransport() @@ -204,34 +211,24 @@ public class HttpClient extends ContainerLifeCycle @Override protected void doStart() throws Exception { - if (sslContextFactory != null) - addBean(sslContextFactory); - if (executor == null) { QueuedThreadPool threadPool = new QueuedThreadPool(); threadPool.setName(name); - executor = threadPool; + setExecutor(threadPool); } - addBean(executor); - + if (byteBufferPool == null) - byteBufferPool = new MappedByteBufferPool(2048, + setByteBufferPool(new MappedByteBufferPool(2048, executor instanceof ThreadPool.SizedThreadPool - ? ((ThreadPool.SizedThreadPool)executor).getMaxThreads()/2 - : ProcessorUtils.availableProcessors()*2); - addBean(byteBufferPool); + ? ((ThreadPool.SizedThreadPool)executor).getMaxThreads() / 2 + : ProcessorUtils.availableProcessors() * 2)); if (scheduler == null) - scheduler = new ScheduledExecutorScheduler(name + "-scheduler", false); - addBean(scheduler); - - transport.setHttpClient(this); - addBean(transport); + setScheduler(new ScheduledExecutorScheduler(name + "-scheduler", false)); if (resolver == null) - resolver = new SocketAddressResolver.Async(executor, scheduler, getAddressResolutionTimeout()); - addBean(resolver); + setSocketAddressResolver(new SocketAddressResolver.Async(executor, scheduler, getAddressResolutionTimeout())); handlers.put(new ContinueProtocolHandler()); handlers.put(new RedirectProtocolHandler(this)); @@ -243,6 +240,7 @@ public class HttpClient extends ContainerLifeCycle cookieManager = newCookieManager(); cookieStore = cookieManager.getCookieStore(); + transport.setHttpClient(this); super.doStart(); } @@ -258,7 +256,9 @@ public class HttpClient extends ContainerLifeCycle handlers.clear(); for (HttpDestination destination : destinations.values()) + { destination.close(); + } destinations.clear(); requestListeners.clear(); @@ -334,6 +334,8 @@ public class HttpClient extends ContainerLifeCycle return decoderFactories; } + // @checkstyle-disable-check : MethodNameCheck + /** * Performs a GET request to the specified URI. * @@ -455,11 +457,11 @@ public class HttpClient extends ContainerLifeCycle { Request newRequest = newHttpRequest(oldRequest.getConversation(), newURI); newRequest.method(oldRequest.getMethod()) - .version(oldRequest.getVersion()) - .content(oldRequest.getContent()) - .idleTimeout(oldRequest.getIdleTimeout(), TimeUnit.MILLISECONDS) - .timeout(oldRequest.getTimeout(), TimeUnit.MILLISECONDS) - .followRedirects(oldRequest.isFollowRedirects()); + .version(oldRequest.getVersion()) + .content(oldRequest.getContent()) + .idleTimeout(oldRequest.getIdleTimeout(), TimeUnit.MILLISECONDS) + .timeout(oldRequest.getTimeout(), TimeUnit.MILLISECONDS) + .followRedirects(oldRequest.isFollowRedirects()); for (HttpField field : oldRequest.getHeaders()) { HttpHeader header = field.getHeader(); @@ -477,7 +479,7 @@ public class HttpClient extends ContainerLifeCycle // Remove authorization headers. if (HttpHeader.AUTHORIZATION == header || - HttpHeader.PROXY_AUTHORIZATION == header) + HttpHeader.PROXY_AUTHORIZATION == header) continue; String name = field.getName(); @@ -530,7 +532,7 @@ public class HttpClient extends ContainerLifeCycle protected HttpDestination destinationFor(String scheme, String host, int port) { if (!HttpScheme.HTTP.is(scheme) && !HttpScheme.HTTPS.is(scheme) && - !HttpScheme.WS.is(scheme) && !HttpScheme.WSS.is(scheme)) + !HttpScheme.WS.is(scheme) && !HttpScheme.WSS.is(scheme)) throw new IllegalArgumentException("Invalid protocol " + scheme); scheme = scheme.toLowerCase(Locale.ENGLISH); @@ -645,6 +647,9 @@ public class HttpClient extends ContainerLifeCycle */ public void setByteBufferPool(ByteBufferPool byteBufferPool) { + if (isStarted()) + LOG.warn("Calling setByteBufferPool() while started is deprecated"); + updateBean(this.byteBufferPool, byteBufferPool); this.byteBufferPool = byteBufferPool; } @@ -796,6 +801,9 @@ public class HttpClient extends ContainerLifeCycle */ public void setExecutor(Executor executor) { + if (isStarted()) + LOG.warn("Calling setExecutor() while started is deprecated"); + updateBean(this.executor, executor); this.executor = executor; } @@ -812,6 +820,9 @@ public class HttpClient extends ContainerLifeCycle */ public void setScheduler(Scheduler scheduler) { + if (isStarted()) + LOG.warn("Calling setScheduler() while started is deprecated"); + updateBean(this.scheduler, scheduler); this.scheduler = scheduler; } @@ -828,6 +839,9 @@ public class HttpClient extends ContainerLifeCycle */ public void setSocketAddressResolver(SocketAddressResolver resolver) { + if (isStarted()) + LOG.warn("Calling setSocketAddressResolver() while started is deprecated"); + updateBean(this.resolver, resolver); this.resolver = resolver; } @@ -918,7 +932,7 @@ public class HttpClient extends ContainerLifeCycle } /** - * @return the max number of HTTP redirects that are followed + * @return the max number of HTTP redirects that are followed in a conversation * @see #setMaxRedirects(int) */ public int getMaxRedirects() @@ -927,7 +941,7 @@ public class HttpClient extends ContainerLifeCycle } /** - * @param maxRedirects the max number of HTTP redirects that are followed + * @param maxRedirects the max number of HTTP redirects that are followed in a conversation, or -1 for unlimited redirects * @see #setFollowRedirects(boolean) */ public void setMaxRedirects(int maxRedirects) @@ -975,7 +989,7 @@ public class HttpClient extends ContainerLifeCycle * may be set to false. * * @param dispatchIO true to dispatch I/O operations in a different thread, - * false to execute them in the selector thread + * false to execute them in the selector thread */ @Deprecated public void setDispatchIO(boolean dispatchIO) @@ -996,6 +1010,7 @@ public class HttpClient extends ContainerLifeCycle /** * Sets the http compliance mode for parsing http responses. * This affect how weak the {@link HttpParser} parses http responses and which http protocol level is supported + * * @param httpCompliance The compliance level which is used to actually parse http responses */ public void setHttpCompliance(HttpCompliance httpCompliance) @@ -1283,7 +1298,7 @@ public class HttpClient extends ContainerLifeCycle else { StringBuilder value = new StringBuilder(); - for (Iterator iterator = set.iterator(); iterator.hasNext();) + for (Iterator iterator = set.iterator(); iterator.hasNext(); ) { ContentDecoder.Factory decoderFactory = iterator.next(); value.append(decoderFactory.getEncoding()); diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClientTransport.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClientTransport.java index a2ba6d8b145..35b12c0c3f1 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClientTransport.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClientTransport.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -28,7 +28,7 @@ import org.eclipse.jetty.io.ClientConnectionFactory; * in order to plug-in a different transport for {@link HttpClient}. *

    * While the {@link HttpClient} APIs define the HTTP semantic (request, response, headers, etc.) - * how a HTTP exchange is carried over the network depends on implementations of this class. + * how an HTTP exchange is carried over the network depends on implementations of this class. *

    * The default implementation uses the HTTP protocol to carry over the network the HTTP exchange, * but the HTTP exchange may also be carried using the FCGI protocol, the HTTP/2 protocol or, @@ -36,8 +36,8 @@ import org.eclipse.jetty.io.ClientConnectionFactory; */ public interface HttpClientTransport extends ClientConnectionFactory { - public static final String HTTP_DESTINATION_CONTEXT_KEY = "http.destination"; - public static final String HTTP_CONNECTION_PROMISE_CONTEXT_KEY = "http.connection.promise"; + String HTTP_DESTINATION_CONTEXT_KEY = "http.destination"; + String HTTP_CONNECTION_PROMISE_CONTEXT_KEY = "http.connection.promise"; /** * Sets the {@link HttpClient} instance on this transport. @@ -48,7 +48,7 @@ public interface HttpClientTransport extends ClientConnectionFactory * * @param client the {@link HttpClient} that uses this transport. */ - public void setHttpClient(HttpClient client); + void setHttpClient(HttpClient client); /** * Creates a new, transport-specific, {@link HttpDestination} object. @@ -59,23 +59,23 @@ public interface HttpClientTransport extends ClientConnectionFactory * @param origin the destination origin * @return a new, transport-specific, {@link HttpDestination} object */ - public HttpDestination newHttpDestination(Origin origin); + HttpDestination newHttpDestination(Origin origin); /** * Establishes a physical connection to the given {@code address}. * - * @param address the address to connect to + * @param address the address to connect to * @param context the context information to establish the connection */ - public void connect(InetSocketAddress address, Map context); + void connect(InetSocketAddress address, Map context); /** * @return the factory for ConnectionPool instances */ - public ConnectionPool.Factory getConnectionPoolFactory(); + ConnectionPool.Factory getConnectionPoolFactory(); /** * @param factory the factory for ConnectionPool instances */ - public void setConnectionPoolFactory(ConnectionPool.Factory factory); + void setConnectionPoolFactory(ConnectionPool.Factory factory); } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConnection.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConnection.java index 19c6f7d1bd1..8e70a0353ca 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConnection.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConnection.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -68,7 +68,7 @@ public abstract class HttpConnection implements Connection HttpRequest httpRequest = (HttpRequest)request; ArrayList listeners = new ArrayList<>(httpRequest.getResponseListeners()); - + httpRequest.sent(); if (listener != null) listeners.add(listener); diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContent.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContent.java index 0f02a6d970d..17c8d3ab1bd 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContent.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContent.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -32,7 +32,7 @@ import org.eclipse.jetty.util.log.Logger; /** * {@link HttpContent} is a stateful, linear representation of the request content provided * by a {@link ContentProvider} that can be traversed one-way to obtain content buffers to - * send to a HTTP server. + * send to an HTTP server. *

    * {@link HttpContent} offers the notion of a one-way cursor to traverse the content. * The cursor starts in a virtual "before" position and can be advanced using {@link #advance()} @@ -78,11 +78,10 @@ public class HttpContent implements Callback, Closeable public HttpContent(ContentProvider provider) { this.provider = provider; - this.iterator = provider == null ? Collections.emptyIterator() : provider.iterator(); + this.iterator = provider == null ? Collections.emptyIterator() : provider.iterator(); } /** - * @param buffer * @return true if the buffer is the sentinel instance {@link CLOSE} */ private static boolean isTheCloseBuffer(ByteBuffer buffer) @@ -91,7 +90,7 @@ public class HttpContent implements Callback, Closeable boolean isTheCloseBuffer = (buffer == CLOSE); return isTheCloseBuffer; } - + /** * @return whether there is any content at all */ @@ -234,11 +233,11 @@ public class HttpContent implements Callback, Closeable public String toString() { return String.format("%s@%x - has=%b,last=%b,consumed=%b,buffer=%s", - getClass().getSimpleName(), - hashCode(), - hasContent(), - isLast(), - isConsumed(), - BufferUtil.toDetailString(getContent())); + getClass().getSimpleName(), + hashCode(), + hasContent(), + isLast(), + isConsumed(), + BufferUtil.toDetailString(getContent())); } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContentResponse.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContentResponse.java index 8ae0497e1cb..2a1aec0cc4b 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContentResponse.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContentResponse.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -129,10 +129,10 @@ public class HttpContentResponse implements ContentResponse public String toString() { return String.format("%s[%s %d %s - %d bytes]", - HttpContentResponse.class.getSimpleName(), - getVersion(), - getStatus(), - getReason(), - getContent().length); + HttpContentResponse.class.getSimpleName(), + getVersion(), + getStatus(), + getReason(), + getContent().length); } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConversation.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConversation.java index 6db4e96a9f4..d1151d27b63 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConversation.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConversation.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -25,9 +25,13 @@ import java.util.concurrent.ConcurrentLinkedDeque; import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.util.AttributesMap; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; public class HttpConversation extends AttributesMap { + private static final Logger LOG = Log.getLogger(HttpConversation.class); + private final Deque exchanges = new ConcurrentLinkedDeque<>(); private volatile List listeners; @@ -41,46 +45,46 @@ public class HttpConversation extends AttributesMap * This list changes as the conversation proceeds, as follows: *

      *
    1. - * request R1 send => conversation.updateResponseListeners(null) - *
        - *
      • exchanges in conversation: E1
      • - *
      • listeners to be notified: E1.listeners
      • - *
      + * request R1 send => conversation.updateResponseListeners(null) + *
        + *
      • exchanges in conversation: E1
      • + *
      • listeners to be notified: E1.listeners
      • + *
      *
    2. *
    3. - * response R1 arrived, 401 => conversation.updateResponseListeners(AuthenticationProtocolHandler.listener) - *
        - *
      • exchanges in conversation: E1
      • - *
      • listeners to be notified: AuthenticationProtocolHandler.listener
      • - *
      + * response R1 arrived, 401 => conversation.updateResponseListeners(AuthenticationProtocolHandler.listener) + *
        + *
      • exchanges in conversation: E1
      • + *
      • listeners to be notified: AuthenticationProtocolHandler.listener
      • + *
      *
    4. *
    5. - * request R2 send => conversation.updateResponseListeners(null) - *
        - *
      • exchanges in conversation: E1 + E2
      • - *
      • listeners to be notified: E2.listeners + E1.listeners
      • - *
      + * request R2 send => conversation.updateResponseListeners(null) + *
        + *
      • exchanges in conversation: E1 + E2
      • + *
      • listeners to be notified: E2.listeners + E1.listeners
      • + *
      *
    6. *
    7. - * response R2 arrived, 302 => conversation.updateResponseListeners(RedirectProtocolHandler.listener) - *
        - *
      • exchanges in conversation: E1 + E2
      • - *
      • listeners to be notified: E2.listeners + RedirectProtocolHandler.listener
      • - *
      + * response R2 arrived, 302 => conversation.updateResponseListeners(RedirectProtocolHandler.listener) + *
        + *
      • exchanges in conversation: E1 + E2
      • + *
      • listeners to be notified: E2.listeners + RedirectProtocolHandler.listener
      • + *
      *
    8. *
    9. - * request R3 send => conversation.updateResponseListeners(null) - *
        - *
      • exchanges in conversation: E1 + E2 + E3
      • - *
      • listeners to be notified: E3.listeners + E1.listeners
      • - *
      + * request R3 send => conversation.updateResponseListeners(null) + *
        + *
      • exchanges in conversation: E1 + E2 + E3
      • + *
      • listeners to be notified: E3.listeners + E1.listeners
      • + *
      *
    10. *
    11. - * response R3 arrived, 200 => conversation.updateResponseListeners(null) - *
        - *
      • exchanges in conversation: E1 + E2 + E3
      • - *
      • listeners to be notified: E3.listeners + E1.listeners
      • - *
      + * response R3 arrived, 200 => conversation.updateResponseListeners(null) + *
        + *
      • exchanges in conversation: E1 + E2 + E3
      • + *
      • listeners to be notified: E3.listeners + E1.listeners
      • + *
      *
    12. *
    * Basically the override conversation listener replaces the first exchange response listener, @@ -118,6 +122,7 @@ public class HttpConversation extends AttributesMap HttpExchange lastExchange = exchanges.peekLast(); if (firstExchange == lastExchange) { + // We don't have a conversation, just a single request. if (overrideListener != null) listeners.add(overrideListener); else @@ -125,13 +130,16 @@ public class HttpConversation extends AttributesMap } else { - // Order is important, we want to notify the last exchange first + // We have a conversation (e.g. redirect, authentication). + // Order is important, we want to notify the last exchange first. listeners.addAll(lastExchange.getResponseListeners()); if (overrideListener != null) listeners.add(overrideListener); else listeners.addAll(firstExchange.getResponseListeners()); } + if (LOG.isDebugEnabled()) + LOG.debug("Exchanges in conversation {}, override={}, listeners={}", exchanges.size(), overrideListener, listeners); this.listeners = listeners; } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java index a19613ee3b9..e1868cc54dc 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -22,7 +22,6 @@ import java.io.Closeable; import java.io.IOException; import java.nio.channels.AsynchronousCloseException; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Queue; import java.util.concurrent.RejectedExecutionException; @@ -77,7 +76,7 @@ public abstract class HttpDestination extends ContainerLifeCycle implements Dest this.requestNotifier = new RequestNotifier(client); this.responseNotifier = new ResponseNotifier(); - + this.timeout = new TimeoutTask(client.getScheduler()); ProxyConfiguration proxyConfig = client.getProxyConfiguration(); @@ -236,7 +235,7 @@ public abstract class HttpDestination extends ContainerLifeCycle implements Dest } protected void send(HttpRequest request, List listeners) - { + { if (!getScheme().equalsIgnoreCase(request.getScheme())) throw new IllegalArgumentException("Invalid request scheme " + request.getScheme() + " for destination " + this); if (!getHost().equalsIgnoreCase(request.getHost())) @@ -450,7 +449,9 @@ public abstract class HttpDestination extends ContainerLifeCycle implements Dest // and we don't want to fail it immediately as if it was queued before the failure. // The call to Request.abort() will remove the exchange from the exchanges queue. for (HttpExchange exchange : new ArrayList<>(exchanges)) + { exchange.getRequest().abort(cause); + } if (exchanges.isEmpty()) tryRemoveIdleDestination(); } @@ -472,8 +473,7 @@ public abstract class HttpDestination extends ContainerLifeCycle implements Dest @Override public void dump(Appendable out, String indent) throws IOException { - super.dump(out, indent); - ContainerLifeCycle.dump(out, indent, Collections.singleton(new DumpableCollection("exchanges", exchanges))); + dumpObjects(out, indent, new DumpableCollection("exchanges", exchanges)); } public String asString() @@ -485,15 +485,19 @@ public abstract class HttpDestination extends ContainerLifeCycle implements Dest public String toString() { return String.format("%s[%s]@%x%s,queue=%d,pool=%s", - HttpDestination.class.getSimpleName(), - asString(), - hashCode(), - proxy == null ? "" : "(via " + proxy + ")", - exchanges.size(), - connectionPool); + HttpDestination.class.getSimpleName(), + asString(), + hashCode(), + proxy == null ? "" : "(via " + proxy + ")", + exchanges.size(), + connectionPool); } - - // The TimeoutTask that expires when the next check of expiry is needed + + /** + * This class enforces the total timeout for exchanges that are still in the queue. + * The total timeout for exchanges that are not in the destination queue is enforced + * by {@link HttpChannel}. + */ private class TimeoutTask extends CyclicTimeout { private final AtomicLong nextTimeout = new AtomicLong(Long.MAX_VALUE); @@ -506,10 +510,13 @@ public abstract class HttpDestination extends ContainerLifeCycle implements Dest @Override public void onTimeoutExpired() { + if (LOG.isDebugEnabled()) + LOG.debug("{} timeout expired", this); + nextTimeout.set(Long.MAX_VALUE); long now = System.nanoTime(); long nextExpiresAt = Long.MAX_VALUE; - + // Check all queued exchanges for those that have expired // and to determine when the next check must be. for (HttpExchange exchange : exchanges) @@ -523,7 +530,7 @@ public abstract class HttpDestination extends ContainerLifeCycle implements Dest else if (expiresAt < nextExpiresAt) nextExpiresAt = expiresAt; } - + if (nextExpiresAt < Long.MAX_VALUE && client.isRunning()) schedule(nextExpiresAt); } @@ -538,12 +545,16 @@ public abstract class HttpDestination extends ContainerLifeCycle implements Dest if (timeoutAt != expiresAt) { long delay = expiresAt - System.nanoTime(); - if (LOG.isDebugEnabled()) - LOG.debug("Scheduled timeout in {} ms", TimeUnit.NANOSECONDS.toMillis(delay)); if (delay <= 0) + { onTimeoutExpired(); + } else + { schedule(delay, TimeUnit.NANOSECONDS); + if (LOG.isDebugEnabled()) + LOG.debug("{} scheduled timeout in {} ms", this, TimeUnit.NANOSECONDS.toMillis(delay)); + } } } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpExchange.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpExchange.java index 7c15d534adc..74d66ffd797 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpExchange.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpExchange.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -291,10 +291,10 @@ public class HttpExchange synchronized (this) { return String.format("%s@%x req=%s/%s@%h res=%s/%s@%h", - HttpExchange.class.getSimpleName(), - hashCode(), - requestState, requestFailure, requestFailure, - responseState, responseFailure, responseFailure); + HttpExchange.class.getSimpleName(), + hashCode(), + requestState, requestFailure, requestFailure, + responseState, responseFailure, responseFailure); } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpProxy.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpProxy.java index 986add411ce..07511ff3c5b 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpProxy.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpProxy.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -105,7 +105,7 @@ public class HttpProxy extends ProxyConfiguration.Proxy else { throw new IOException("Cannot tunnel request, missing " + - SslContextFactory.class.getName() + " in " + HttpClient.class.getName()); + SslContextFactory.class.getName() + " in " + HttpClient.class.getName()); } } else @@ -156,11 +156,11 @@ public class HttpProxy extends ProxyConfiguration.Proxy HttpClient httpClient = destination.getHttpClient(); long connectTimeout = httpClient.getConnectTimeout(); Request connect = httpClient.newRequest(proxyAddress.getHost(), proxyAddress.getPort()) - .method(HttpMethod.CONNECT) - .path(target) - .header(HttpHeader.HOST, target) - .idleTimeout(2 * connectTimeout, TimeUnit.MILLISECONDS) - .timeout(connectTimeout, TimeUnit.MILLISECONDS); + .method(HttpMethod.CONNECT) + .path(target) + .header(HttpHeader.HOST, target) + .idleTimeout(2 * connectTimeout, TimeUnit.MILLISECONDS) + .timeout(connectTimeout, TimeUnit.MILLISECONDS); ProxyConfiguration.Proxy proxy = destination.getProxy(); if (proxy != null && proxy.isSecure()) connect.scheme(HttpScheme.HTTPS.asString()); @@ -184,7 +184,7 @@ public class HttpProxy extends ProxyConfiguration.Proxy else { HttpResponseException failure = new HttpResponseException("Unexpected " + response + - " for " + result.getRequest(), response); + " for " + result.getRequest(), response); tunnelFailed(endPoint, failure); } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java index 813672fb72c..991768f1121 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -21,7 +21,6 @@ package org.eclipse.jetty.client; import java.io.IOException; import java.net.URI; import java.nio.ByteBuffer; -import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; @@ -37,7 +36,7 @@ import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.CountingCallback; +import org.eclipse.jetty.util.IteratingNestedCallback; import org.eclipse.jetty.util.component.Destroyable; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -52,7 +51,7 @@ import org.eclipse.jetty.util.log.Logger; *
      *
    1. {@link #responseBegin(HttpExchange)}, when the HTTP response data containing the HTTP status code * is available
    2. - *
    3. {@link #responseHeader(HttpExchange, HttpField)}, when a HTTP field is available
    4. + *
    5. {@link #responseHeader(HttpExchange, HttpField)}, when an HTTP field is available
    6. *
    7. {@link #responseHeaders(HttpExchange)}, when all HTTP headers are available
    8. *
    9. {@link #responseContent(HttpExchange, ByteBuffer, Callback)}, when HTTP content is available
    10. *
    11. {@link #responseSuccess(HttpExchange)}, when the response is successful
    12. @@ -159,7 +158,8 @@ public abstract class HttpReceiver */ protected boolean responseHeader(HttpExchange exchange, HttpField field) { - out: while (true) + out: + while (true) { ResponseState current = responseState.get(); switch (current) @@ -241,7 +241,8 @@ public abstract class HttpReceiver */ protected boolean responseHeaders(HttpExchange exchange) { - out: while (true) + out: + while (true) { ResponseState current = responseState.get(); switch (current) @@ -267,9 +268,9 @@ public abstract class HttpReceiver List responseListeners = exchange.getConversation().getResponseListeners(); notifier.notifyHeaders(responseListeners, response); contentListeners = responseListeners.stream() - .filter(Response.AsyncContentListener.class::isInstance) - .map(Response.AsyncContentListener.class::cast) - .collect(Collectors.toList()); + .filter(Response.AsyncContentListener.class::isInstance) + .map(Response.AsyncContentListener.class::cast) + .collect(Collectors.toList()); Enumeration contentEncodings = response.getHeaders().getValues(HttpHeader.CONTENT_ENCODING.asString(), ","); if (contentEncodings != null) @@ -306,7 +307,8 @@ public abstract class HttpReceiver */ protected boolean responseContent(HttpExchange exchange, ByteBuffer buffer, Callback callback) { - out: while (true) + out: + while (true) { ResponseState current = responseState.get(); switch (current) @@ -339,35 +341,7 @@ public abstract class HttpReceiver } else { - try - { - List decodeds = new ArrayList<>(2); - while (buffer.hasRemaining()) - { - ByteBuffer decoded = decoder.decode(buffer); - if (!decoded.hasRemaining()) - continue; - decodeds.add(decoded); - if (LOG.isDebugEnabled()) - LOG.debug("Response content decoded ({}) {}{}{}", decoder, response, System.lineSeparator(), BufferUtil.toDetailString(decoded)); - } - - if (decodeds.isEmpty()) - { - callback.succeeded(); - } - else - { - int size = decodeds.size(); - CountingCallback counter = new CountingCallback(callback, size); - for (ByteBuffer decoded : decodeds) - notifier.notifyContent(response, decoded, counter, contentListeners); - } - } - catch (Throwable x) - { - callback.failed(x); - } + new Decoder(notifier, response, decoder, buffer, callback).iterate(); } if (updateResponseState(ResponseState.TRANSIENT, ResponseState.CONTENT)) @@ -512,7 +486,8 @@ public abstract class HttpReceiver { // Update the state to avoid more response processing. boolean terminate; - out: while (true) + out: + while (true) { ResponseState current = responseState.get(); switch (current) @@ -550,14 +525,14 @@ public abstract class HttpReceiver // respect to concurrency between request and response. Result result = exchange.terminateResponse(); terminateResponse(exchange, result); + return true; } else { if (LOG.isDebugEnabled()) LOG.debug("Concurrent failure: response termination skipped, performed by helpers"); + return false; } - - return true; } private boolean updateResponseState(ResponseState from, ResponseState to) @@ -575,10 +550,10 @@ public abstract class HttpReceiver public String toString() { return String.format("%s@%x(rsp=%s,failure=%s)", - getClass().getSimpleName(), - hashCode(), - responseState, - failure); + getClass().getSimpleName(), + hashCode(), + responseState, + failure); } /** @@ -615,4 +590,47 @@ public abstract class HttpReceiver */ FAILURE } + + private class Decoder extends IteratingNestedCallback + { + private final ResponseNotifier notifier; + private final HttpResponse response; + private final ContentDecoder decoder; + private final ByteBuffer buffer; + private ByteBuffer decoded; + + public Decoder(ResponseNotifier notifier, HttpResponse response, ContentDecoder decoder, ByteBuffer buffer, Callback callback) + { + super(callback); + this.notifier = notifier; + this.response = response; + this.decoder = decoder; + this.buffer = buffer; + } + + @Override + protected Action process() throws Throwable + { + while (true) + { + decoded = decoder.decode(buffer); + if (decoded.hasRemaining()) + break; + if (!buffer.hasRemaining()) + return Action.SUCCEEDED; + } + if (LOG.isDebugEnabled()) + LOG.debug("Response content decoded ({}) {}{}{}", decoder, response, System.lineSeparator(), BufferUtil.toDetailString(decoded)); + + notifier.notifyContent(response, decoded, this, contentListeners); + return Action.SCHEDULED; + } + + @Override + public void succeeded() + { + decoder.release(decoded); + super.succeeded(); + } + } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRedirector.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRedirector.java index 9d50b01e8c6..565a092f64d 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRedirector.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRedirector.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -23,6 +23,7 @@ import java.net.URISyntaxException; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -61,10 +62,10 @@ public class HttpRedirector { private static final Logger LOG = Log.getLogger(HttpRedirector.class); private static final String SCHEME_REGEXP = "(^https?)"; - private static final String AUTHORITY_REGEXP = "([^/\\?#]+)"; + private static final String AUTHORITY_REGEXP = "([^/?#]+)"; // The location may be relative so the scheme://authority part may be missing private static final String DESTINATION_REGEXP = "(" + SCHEME_REGEXP + "://" + AUTHORITY_REGEXP + ")?"; - private static final String PATH_REGEXP = "([^\\?#]*)"; + private static final String PATH_REGEXP = "([^?#]*)"; private static final String QUERY_REGEXP = "([^#]*)"; private static final String FRAGMENT_REGEXP = "(.*)"; private static final Pattern URI_PATTERN = Pattern.compile(DESTINATION_REGEXP + PATH_REGEXP + QUERY_REGEXP + FRAGMENT_REGEXP); @@ -81,7 +82,7 @@ public class HttpRedirector /** * @param response the response to check for redirects - * @return whether the response code is a HTTP redirect code + * @return whether the response code is an HTTP redirect code */ public boolean isRedirect(Response response) { @@ -118,9 +119,9 @@ public class HttpRedirector public void onComplete(Result result) { resultRef.set(new Result(result.getRequest(), - result.getRequestFailure(), - new HttpContentResponse(result.getResponse(), getContent(), getMediaType(), getEncoding()), - result.getResponseFailure())); + result.getRequestFailure(), + new HttpContentResponse(result.getResponse(), getContent(), getMediaType(), getEncoding()), + result.getResponseFailure())); latch.countDown(); } }); @@ -217,7 +218,7 @@ public class HttpRedirector { return new URI(scheme, authority, path, query, fragment); } - catch (URISyntaxException xx) + catch (URISyntaxException ex) { // Give up } @@ -292,7 +293,8 @@ public class HttpRedirector Integer redirects = (Integer)conversation.getAttribute(ATTRIBUTE); if (redirects == null) redirects = 0; - if (redirects < client.getMaxRedirects()) + int maxRedirects = client.getMaxRedirects(); + if (maxRedirects < 0 || redirects < maxRedirects) { ++redirects; conversation.setAttribute(ATTRIBUTE, redirects); @@ -310,19 +312,17 @@ public class HttpRedirector try { Request redirect = client.copyRequest(httpRequest, location); + // Disable the timeout so that only the one from the initial request applies. + redirect.timeout(0, TimeUnit.MILLISECONDS); // Use given method redirect.method(method); - redirect.onRequestBegin(new Request.BeginListener() + redirect.onRequestBegin(request -> { - @Override - public void onBegin(Request redirect) - { - Throwable cause = httpRequest.getAbortCause(); - if (cause != null) - redirect.abort(cause); - } + Throwable cause = httpRequest.getAbortCause(); + if (cause != null) + request.abort(cause); }); redirect.send(listener); diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java index 7ae3fbb56d2..0ede8794655 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -76,7 +76,7 @@ public class HttpRequest implements Request private String query; private String method = HttpMethod.GET.asString(); private HttpVersion version = HttpVersion.HTTP_1_1; - private long idleTimeout; + private long idleTimeout = -1; private long timeout; private long timeoutAt; private ContentProvider content; @@ -99,7 +99,6 @@ public class HttpRequest implements Request extractParams(query); followRedirects(client.isFollowRedirects()); - idleTimeout = client.getIdleTimeout(); HttpField acceptEncodingField = client.getAcceptEncodingField(); if (acceptEncodingField != null) headers.put(acceptEncodingField); @@ -108,7 +107,7 @@ public class HttpRequest implements Request headers.put(userAgentField); } - protected HttpConversation getConversation() + public HttpConversation getConversation() { return conversation; } @@ -204,7 +203,7 @@ public class HttpRequest implements Request { if (uri == null) uri = buildURI(true); - + @SuppressWarnings("ReferenceEquality") boolean isNullURI = (uri == NULL_URI); return isNullURI ? null : uri; @@ -301,7 +300,7 @@ public class HttpRequest implements Request @Override public List getCookies() { - return cookies != null ? cookies : Collections.emptyList(); + return cookies != null ? cookies : Collections.emptyList(); } @Override @@ -325,7 +324,7 @@ public class HttpRequest implements Request @Override public Map getAttributes() { - return attributes != null ? attributes : Collections.emptyMap(); + return attributes != null ? attributes : Collections.emptyMap(); } @Override @@ -341,12 +340,14 @@ public class HttpRequest implements Request // This method is invoked often in a request/response conversation, // so we avoid allocation if there is no need to filter. if (type == null || requestListeners == null) - return requestListeners != null ? (List)requestListeners : Collections.emptyList(); + return requestListeners != null ? (List)requestListeners : Collections.emptyList(); ArrayList result = new ArrayList<>(); for (RequestListener listener : requestListeners) + { if (type.isInstance(listener)) result.add((T)listener); + } return result; } @@ -684,7 +685,7 @@ public class HttpRequest implements Request return listener.get(); } catch (ExecutionException x) - { + { // Previously this method used a timed get on the future, which was in a race // with the timeouts implemented in HttpDestination and HttpConnection. The change to // make those timeouts relative to the timestamp taken in sent() has made that race @@ -696,7 +697,7 @@ public class HttpRequest implements Request // Thus for backwards compatibility we unwrap the timeout exception here if (x.getCause() instanceof TimeoutException) { - TimeoutException t = (TimeoutException) (x.getCause()); + TimeoutException t = (TimeoutException)(x.getCause()); abort(t); throw t; } @@ -705,7 +706,7 @@ public class HttpRequest implements Request throw x; } catch (Throwable x) - { + { // Differently from the Future, the semantic of this method is that if // the send() is interrupted or times out, we abort the request. abort(x); @@ -718,7 +719,7 @@ public class HttpRequest implements Request { send(this, listener); } - + private void send(HttpRequest request, Response.CompleteListener listener) { if (listener != null) @@ -732,7 +733,7 @@ public class HttpRequest implements Request long timeout = getTimeout(); timeoutAt = timeout > 0 ? System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(timeout) : -1; } - + /** * @return The nanoTime at which the timeout expires or -1 if there is no timeout. * @see #timeout(long, TimeUnit) @@ -741,7 +742,7 @@ public class HttpRequest implements Request { return timeoutAt; } - + protected List getResponseListeners() { return responseListeners; @@ -868,7 +869,7 @@ public class HttpRequest implements Request } catch (URISyntaxException x) { - // The "path" of a HTTP request may not be a URI, + // The "path" of an HTTP request may not be a URI, // for example for CONNECT 127.0.0.1:8080. return null; } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequestException.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequestException.java index 54938a27836..ac383844e6c 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequestException.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequestException.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpResponse.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpResponse.java index e37e2758225..b4a82af8d6c 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpResponse.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpResponse.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -96,8 +96,10 @@ public class HttpResponse implements Response { ArrayList result = new ArrayList<>(); for (ResponseListener listener : listeners) + { if (type == null || type.isInstance(listener)) result.add((T)listener); + } return result; } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpResponseException.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpResponseException.java index e494170c34e..9477ae736c8 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpResponseException.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpResponseException.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -26,7 +26,12 @@ public class HttpResponseException extends RuntimeException public HttpResponseException(String message, Response response) { - super(message); + this(message, response, null); + } + + public HttpResponseException(String message, Response response, Throwable cause) + { + super(message, cause); this.response = response; } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpSender.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpSender.java index d2d620c5e9a..e9e74b7c6f4 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpSender.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpSender.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,13 +19,13 @@ package org.eclipse.jetty.client; import java.nio.ByteBuffer; +import java.util.concurrent.Executor; +import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Supplier; import org.eclipse.jetty.client.api.ContentProvider; import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.api.Result; -import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeaderValue; import org.eclipse.jetty.util.BufferUtil; @@ -65,7 +65,6 @@ public abstract class HttpSender implements AsyncContentProvider.Listener private final AtomicReference senderState = new AtomicReference<>(SenderState.IDLE); private final Callback commitCallback = new CommitCallback(); private final IteratingCallback contentCallback = new ContentCallback(); - private final Callback trailersCallback = new TrailersCallback(); private final Callback lastCallback = new LastCallback(); private final HttpChannel channel; private HttpContent content; @@ -181,7 +180,8 @@ public abstract class HttpSender implements AsyncContentProvider.Listener if (expects100Continue(request)) newSenderState = content.hasContent() ? SenderState.EXPECTING_WITH_CONTENT : SenderState.EXPECTING; - out: while (true) + out: + while (true) { SenderState current = senderState.get(); switch (current) @@ -338,18 +338,31 @@ public abstract class HttpSender implements AsyncContentProvider.Listener } } - protected boolean anyToFailure(Throwable failure) + private void anyToFailure(Throwable failure) { HttpExchange exchange = getHttpExchange(); if (exchange == null) - return false; + return; // Mark atomically the request as completed, with respect // to concurrency between request success and request failure. if (exchange.requestComplete(failure)) - return abort(exchange, failure); + executeAbort(exchange, failure); + } - return false; + private void executeAbort(HttpExchange exchange, Throwable failure) + { + try + { + Executor executor = getHttpChannel().getHttpDestination().getHttpClient().getExecutor(); + executor.execute(() -> abort(exchange, failure)); + } + catch (RejectedExecutionException x) + { + if (LOG.isDebugEnabled()) + LOG.debug(x); + abort(exchange, failure); + } } private void terminateRequest(HttpExchange exchange) @@ -429,15 +442,6 @@ public abstract class HttpSender implements AsyncContentProvider.Listener */ protected abstract void sendContent(HttpExchange exchange, HttpContent content, Callback callback); - /** - * Implementations should send the HTTP trailers and notify the given {@code callback} of the - * result of this operation. - * - * @param exchange the exchange to send - * @param callback the callback to notify - */ - protected abstract void sendTrailers(HttpExchange exchange, Callback callback); - protected void reset() { HttpContent content = this.content; @@ -527,7 +531,8 @@ public abstract class HttpSender implements AsyncContentProvider.Listener { // Update the state to avoid more request processing. boolean terminate; - out: while (true) + out: + while (true) { RequestState current = requestState.get(); switch (current) @@ -564,14 +569,14 @@ public abstract class HttpSender implements AsyncContentProvider.Listener // respect to concurrency between request and response. Result result = exchange.terminateRequest(); terminateRequest(exchange, failure, result); + return true; } else { if (LOG.isDebugEnabled()) LOG.debug("Concurrent failure: request termination skipped, performed by helpers"); + return false; } - - return true; } private boolean updateRequestState(RequestState from, RequestState to) @@ -599,11 +604,11 @@ public abstract class HttpSender implements AsyncContentProvider.Listener public String toString() { return String.format("%s@%x(req=%s,snd=%s,failure=%s)", - getClass().getSimpleName(), - hashCode(), - requestState, - senderState, - failure); + getClass().getSimpleName(), + hashCode(), + requestState, + senderState, + failure); } /** @@ -726,28 +731,18 @@ public abstract class HttpSender implements AsyncContentProvider.Listener if (!headersToCommit(exchange)) return; - HttpContent content = HttpSender.this.content; + HttpContent content = HttpSender.this.content; if (content == null) return; - HttpRequest request = exchange.getRequest(); - Supplier trailers = request.getTrailers(); - boolean hasContent = content.hasContent(); - if (!hasContent) + if (!content.hasContent()) { - if (trailers == null) - { - // No trailers or content to send, we are done. - someToSuccess(exchange); - } - else - { - sendTrailers(exchange, lastCallback); - } + // No content to send, we are done. + someToSuccess(exchange); } else { - // Was any content sent while committing ? + // Was any content sent while committing? ByteBuffer contentBuffer = content.getContent(); if (contentBuffer != null) { @@ -844,9 +839,7 @@ public abstract class HttpSender implements AsyncContentProvider.Listener if (lastContent) { - HttpRequest request = exchange.getRequest(); - Supplier trailers = request.getTrailers(); - sendContent(exchange, content, trailers == null ? lastCallback : trailersCallback); + sendContent(exchange, content, lastCallback); return Action.IDLE; } @@ -910,28 +903,6 @@ public abstract class HttpSender implements AsyncContentProvider.Listener } } - private class TrailersCallback implements Callback - { - @Override - public void succeeded() - { - HttpExchange exchange = getHttpExchange(); - if (exchange == null) - return; - sendTrailers(exchange, lastCallback); - } - - @Override - public void failed(Throwable x) - { - HttpContent content = HttpSender.this.content; - if (content == null) - return; - content.failed(x); - anyToFailure(x); - } - } - private class LastCallback implements Callback { @Override diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/LeakTrackingConnectionPool.java b/jetty-client/src/main/java/org/eclipse/jetty/client/LeakTrackingConnectionPool.java index 55cf45a5a0c..d631511dbc1 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/LeakTrackingConnectionPool.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/LeakTrackingConnectionPool.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/MultiplexConnectionPool.java b/jetty-client/src/main/java/org/eclipse/jetty/client/MultiplexConnectionPool.java index 179d66e9ca3..1759c893ff4 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/MultiplexConnectionPool.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/MultiplexConnectionPool.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -31,7 +31,8 @@ import java.util.stream.Collectors; import org.eclipse.jetty.client.api.Connection; import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.component.ContainerLifeCycle; +import org.eclipse.jetty.util.component.Dumpable; +import org.eclipse.jetty.util.component.DumpableCollection; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.thread.Sweeper; @@ -68,8 +69,8 @@ public class MultiplexConnectionPool extends AbstractConnectionPool implements C connection = activate(); } return connection; - } - + } + protected void lock() { lock.lock(); @@ -116,9 +117,7 @@ public class MultiplexConnectionPool extends AbstractConnectionPool implements C { if (muxedConnections.containsKey(connection)) return true; - if (busyConnections.containsKey(connection)) - return true; - return false; + return busyConnections.containsKey(connection); } finally { @@ -261,7 +260,7 @@ public class MultiplexConnectionPool extends AbstractConnectionPool implements C if (holder == null) { activeRemoved = false; - for (Iterator iterator = idleConnections.iterator(); iterator.hasNext();) + for (Iterator iterator = idleConnections.iterator(); iterator.hasNext(); ) { holder = iterator.next(); if (holder.connection == connection) @@ -310,21 +309,22 @@ public class MultiplexConnectionPool extends AbstractConnectionPool implements C @Override public void dump(Appendable out, String indent) throws IOException { - List connections = new ArrayList<>(); + DumpableCollection busy; + DumpableCollection muxed; + DumpableCollection idle; lock(); try { - connections.addAll(busyConnections.values()); - connections.addAll(muxedConnections.values()); - connections.addAll(idleConnections); + busy = new DumpableCollection("busy", new ArrayList<>(busyConnections.values())); + muxed = new DumpableCollection("muxed", new ArrayList<>(muxedConnections.values())); + idle = new DumpableCollection("idle", new ArrayList<>(idleConnections)); } finally { unlock(); } - ContainerLifeCycle.dumpObject(out, this); - ContainerLifeCycle.dump(out, indent, connections); + Dumpable.dumpObjects(out, indent, this, busy, muxed, idle); } @Override @@ -335,13 +335,13 @@ public class MultiplexConnectionPool extends AbstractConnectionPool implements C try { busyConnections.values().stream() - .map(holder -> holder.connection) - .filter(connection -> connection instanceof Sweeper.Sweepable) - .collect(Collectors.toCollection(() -> toSweep)); + .map(holder -> holder.connection) + .filter(connection -> connection instanceof Sweeper.Sweepable) + .collect(Collectors.toCollection(() -> toSweep)); muxedConnections.values().stream() - .map(holder -> holder.connection) - .filter(connection -> connection instanceof Sweeper.Sweepable) - .collect(Collectors.toCollection(() -> toSweep)); + .map(holder -> holder.connection) + .filter(connection -> connection instanceof Sweeper.Sweepable) + .collect(Collectors.toCollection(() -> toSweep)); } finally { @@ -354,11 +354,11 @@ public class MultiplexConnectionPool extends AbstractConnectionPool implements C { boolean removed = remove(connection, true); LOG.warn("Connection swept: {}{}{} from active connections{}{}", - connection, - System.lineSeparator(), - removed ? "Removed" : "Not removed", - System.lineSeparator(), - dump()); + connection, + System.lineSeparator(), + removed ? "Removed" : "Not removed", + System.lineSeparator(), + dump()); } } @@ -383,13 +383,13 @@ public class MultiplexConnectionPool extends AbstractConnectionPool implements C unlock(); } return String.format("%s@%x[c=%d/%d,b=%d,m=%d,i=%d]", - getClass().getSimpleName(), - hashCode(), - getConnectionCount(), - getMaxConnectionCount(), - busySize, - muxedSize, - idleSize); + getClass().getSimpleName(), + hashCode(), + getConnectionCount(), + getMaxConnectionCount(), + busySize, + muxedSize, + idleSize); } private static class Holder diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/MultiplexHttpDestination.java b/jetty-client/src/main/java/org/eclipse/jetty/client/MultiplexHttpDestination.java index 44c264a36cf..544422c3dc9 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/MultiplexHttpDestination.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/MultiplexHttpDestination.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/Origin.java b/jetty-client/src/main/java/org/eclipse/jetty/client/Origin.java index 39defb6cfe3..0587b8348e0 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/Origin.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/Origin.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -58,8 +58,10 @@ public class Origin @Override public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null || getClass() != obj.getClass()) return false; + if (this == obj) + return true; + if (obj == null || getClass() != obj.getClass()) + return false; Origin that = (Origin)obj; return scheme.equals(that.scheme) && address.equals(that.address); } @@ -96,8 +98,10 @@ public class Origin @Override public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null || getClass() != obj.getClass()) return false; + if (this == obj) + return true; + if (obj == null || getClass() != obj.getClass()) + return false; Address that = (Address)obj; return host.equals(that.host) && port == that.port; } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/PoolingHttpDestination.java b/jetty-client/src/main/java/org/eclipse/jetty/client/PoolingHttpDestination.java index 066184c6909..1da6f1e4859 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/PoolingHttpDestination.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/PoolingHttpDestination.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/ProtocolHandler.java b/jetty-client/src/main/java/org/eclipse/jetty/client/ProtocolHandler.java index b55aefddca1..0d6c4de9197 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/ProtocolHandler.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/ProtocolHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -34,7 +34,7 @@ public interface ProtocolHandler /** * @return a unique name among protocol handlers */ - public String getName(); + String getName(); /** *

      Inspects the given {@code request} and {@code response} @@ -44,15 +44,15 @@ public interface ProtocolHandler *

      This method is being called just after the response line has * been parsed, and before the response headers are available.

      * - * @param request the request to accept + * @param request the request to accept * @param response the response to accept * @return true if this protocol handler can handle the given request and response */ - public boolean accept(Request request, Response response); + boolean accept(Request request, Response response); /** * @return a response listener that will handle the request and response * on behalf of the application. */ - public Response.Listener getResponseListener(); + Response.Listener getResponseListener(); } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/ProtocolHandlers.java b/jetty-client/src/main/java/org/eclipse/jetty/client/ProtocolHandlers.java index 0d552f5ff42..fd34210d916 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/ProtocolHandlers.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/ProtocolHandlers.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,16 +18,18 @@ package org.eclipse.jetty.client; +import java.io.IOException; import java.util.LinkedHashMap; import java.util.Map; import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.api.Response; +import org.eclipse.jetty.util.component.Dumpable; /** *

      A container for {@link ProtocolHandler}s accessible from {@link HttpClient#getProtocolHandlers()}.

      */ -public class ProtocolHandlers +public class ProtocolHandlers implements Dumpable { private final Map handlers = new LinkedHashMap<>(); @@ -77,7 +79,7 @@ public class ProtocolHandlers * {@link ProtocolHandler#accept(Request, Response) accepts} * the given request and response.

      * - * @param request the request to accept + * @param request the request to accept * @param response the response to accept * @return the protocol handler that accepted the request and response, * or null if none of the protocol handlers accepted the request and response @@ -91,4 +93,16 @@ public class ProtocolHandlers } return null; } + + @Override + public String dump() + { + return Dumpable.dump(this); + } + + @Override + public void dump(Appendable out, String indent) throws IOException + { + Dumpable.dumpObjects(out, indent, this, handlers); + } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/ProxyAuthenticationProtocolHandler.java b/jetty-client/src/main/java/org/eclipse/jetty/client/ProxyAuthenticationProtocolHandler.java index f0655c9b1c9..207a0ac020c 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/ProxyAuthenticationProtocolHandler.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/ProxyAuthenticationProtocolHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/ProxyConfiguration.java b/jetty-client/src/main/java/org/eclipse/jetty/client/ProxyConfiguration.java index 4db6a99d013..d8e8acbbc05 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/ProxyConfiguration.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/ProxyConfiguration.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -57,7 +57,7 @@ public class ProxyConfiguration return null; } - public static abstract class Proxy + public abstract static class Proxy { // TO use IPAddress Map private final Set included = new HashSet<>(); @@ -154,7 +154,7 @@ public class ProxyConfiguration HostPort hostPort = new HostPort(pattern); String host = hostPort.getHost(); int port = hostPort.getPort(); - return host.equals(address.getHost()) && ( port<=0 || port==address.getPort() ); + return host.equals(address.getHost()) && (port <= 0 || port == address.getPort()); } /** @@ -169,5 +169,4 @@ public class ProxyConfiguration return address.toString(); } } - } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/RedirectProtocolHandler.java b/jetty-client/src/main/java/org/eclipse/jetty/client/RedirectProtocolHandler.java index 34ecdfd0304..6b0cb3e0bb8 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/RedirectProtocolHandler.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/RedirectProtocolHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/RequestNotifier.java b/jetty-client/src/main/java/org/eclipse/jetty/client/RequestNotifier.java index e93c1ef4e95..9d27f62187b 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/RequestNotifier.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/RequestNotifier.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/ResponseNotifier.java b/jetty-client/src/main/java/org/eclipse/jetty/client/ResponseNotifier.java index e879fd56d88..c9a034230bc 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/ResponseNotifier.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/ResponseNotifier.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -30,7 +30,6 @@ import org.eclipse.jetty.client.api.Result; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.CountingCallback; -import org.eclipse.jetty.util.Retainable; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -107,9 +106,9 @@ public class ResponseNotifier public void notifyContent(List listeners, Response response, ByteBuffer buffer, Callback callback) { List contentListeners = listeners.stream() - .filter(Response.AsyncContentListener.class::isInstance) - .map(Response.AsyncContentListener.class::cast) - .collect(Collectors.toList()); + .filter(Response.AsyncContentListener.class::isInstance) + .map(Response.AsyncContentListener.class::cast) + .collect(Collectors.toList()); notifyContent(response, buffer, callback, contentListeners); } @@ -122,11 +121,8 @@ public class ResponseNotifier else { CountingCallback counter = new CountingCallback(callback, contentListeners.size()); - Retainable retainable = callback instanceof Retainable ? (Retainable)callback : null; for (Response.AsyncContentListener listener : contentListeners) { - if (retainable != null) - retainable.retain(); notifyContent(listener, response, buffer.slice(), counter); } } @@ -210,7 +206,7 @@ public class ResponseNotifier public void forwardSuccess(List listeners, Response response) { notifyBegin(listeners, response); - for (Iterator iterator = response.getHeaders().iterator(); iterator.hasNext();) + for (Iterator iterator = response.getHeaders().iterator(); iterator.hasNext(); ) { HttpField field = iterator.next(); if (!notifyHeader(listeners, response, field)) @@ -231,7 +227,7 @@ public class ResponseNotifier public void forwardFailure(List listeners, Response response, Throwable failure) { notifyBegin(listeners, response); - for (Iterator iterator = response.getHeaders().iterator(); iterator.hasNext();) + for (Iterator iterator = response.getHeaders().iterator(); iterator.hasNext(); ) { HttpField field = iterator.next(); if (!notifyHeader(listeners, response, field)) diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/RoundRobinConnectionPool.java b/jetty-client/src/main/java/org/eclipse/jetty/client/RoundRobinConnectionPool.java index f69cbf63eea..d16af4f2d87 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/RoundRobinConnectionPool.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/RoundRobinConnectionPool.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -26,7 +26,7 @@ import org.eclipse.jetty.client.api.Connection; import org.eclipse.jetty.client.api.Destination; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.annotation.ManagedObject; -import org.eclipse.jetty.util.component.ContainerLifeCycle; +import org.eclipse.jetty.util.component.Dumpable; @ManagedObject public class RoundRobinConnectionPool extends AbstractConnectionPool implements ConnectionPool.Multiplexable @@ -45,7 +45,9 @@ public class RoundRobinConnectionPool extends AbstractConnectionPool implements super(destination, maxConnections, requester); entries = new ArrayList<>(maxConnections); for (int i = 0; i < maxConnections; ++i) + { entries.add(new Entry()); + } this.maxMultiplex = maxMultiplex; } @@ -192,8 +194,7 @@ public class RoundRobinConnectionPool extends AbstractConnectionPool implements { connections = new ArrayList<>(entries); } - ContainerLifeCycle.dumpObject(out, this); - ContainerLifeCycle.dump(out, indent, connections); + Dumpable.dumpObjects(out, indent, out, connections); } @Override @@ -214,11 +215,11 @@ public class RoundRobinConnectionPool extends AbstractConnectionPool implements } } return String.format("%s@%x[c=%d/%d,a=%d]", - getClass().getSimpleName(), - hashCode(), - present, - getMaxConnectionCount(), - active + getClass().getSimpleName(), + hashCode(), + present, + getMaxConnectionCount(), + active ); } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/SendFailure.java b/jetty-client/src/main/java/org/eclipse/jetty/client/SendFailure.java index eccf899eed8..53df9eb3449 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/SendFailure.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/SendFailure.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/Socks4Proxy.java b/jetty-client/src/main/java/org/eclipse/jetty/client/Socks4Proxy.java index 2c35a85ff4a..677867f1f6a 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/Socks4Proxy.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/Socks4Proxy.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -112,7 +112,9 @@ public class Socks4Proxy extends ProxyConfiguration.Proxy ByteBuffer buffer = ByteBuffer.allocate(9); buffer.put((byte)4).put((byte)1).putShort(port); for (int i = 1; i <= 4; ++i) + { buffer.put((byte)Integer.parseInt(matcher.group(i))); + } buffer.put((byte)0); buffer.flip(); getEndPoint().write(this, buffer); diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/Synchronizable.java b/jetty-client/src/main/java/org/eclipse/jetty/client/Synchronizable.java index 67be28fd9ab..40307346426 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/Synchronizable.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/Synchronizable.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -41,5 +41,5 @@ public interface Synchronizable /** * @return the lock object to synchronize on */ - public Object getLock(); + Object getLock(); } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/TimeoutCompleteListener.java b/jetty-client/src/main/java/org/eclipse/jetty/client/TimeoutCompleteListener.java index e5f8832766a..7a3121a755b 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/TimeoutCompleteListener.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/TimeoutCompleteListener.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -26,7 +26,6 @@ import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.api.Result; import org.eclipse.jetty.io.CyclicTimeout; -import org.eclipse.jetty.util.component.Destroyable; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.thread.Scheduler; @@ -47,7 +46,7 @@ public class TimeoutCompleteListener extends CyclicTimeout implements Response.C { Request request = this.request.getAndSet(null); if (LOG.isDebugEnabled()) - LOG.debug("Total timeout {} ms elapsed for {}", request.getTimeout(), request); + LOG.debug("Total timeout {} ms elapsed for {} on {}", request.getTimeout(), request, this); if (request != null) request.abort(new TimeoutException("Total timeout " + request.getTimeout() + " ms elapsed")); } @@ -60,7 +59,7 @@ public class TimeoutCompleteListener extends CyclicTimeout implements Response.C { boolean cancelled = cancel(); if (LOG.isDebugEnabled()) - LOG.debug("Cancelled ({}) timeout for {}", cancelled, request); + LOG.debug("Cancelled ({}) timeout for {} on {}", cancelled, request, this); } } @@ -69,12 +68,16 @@ public class TimeoutCompleteListener extends CyclicTimeout implements Response.C if (this.request.compareAndSet(null, request)) { long delay = timeoutAt - System.nanoTime(); - if (LOG.isDebugEnabled()) - LOG.debug("Scheduled timeout in {} ms for {}", TimeUnit.NANOSECONDS.toMillis(delay), request); if (delay <= 0) + { onTimeoutExpired(); + } else + { schedule(delay, TimeUnit.NANOSECONDS); + if (LOG.isDebugEnabled()) + LOG.debug("Scheduled timeout in {} ms for {} on {}", TimeUnit.NANOSECONDS.toMillis(delay), request, this); + } } } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/ValidatingConnectionPool.java b/jetty-client/src/main/java/org/eclipse/jetty/client/ValidatingConnectionPool.java index 5d539284ee3..9f6e2e7d475 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/ValidatingConnectionPool.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/ValidatingConnectionPool.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -23,12 +23,13 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Stream; import org.eclipse.jetty.client.api.Connection; import org.eclipse.jetty.client.api.Destination; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.annotation.ManagedAttribute; -import org.eclipse.jetty.util.component.ContainerLifeCycle; +import org.eclipse.jetty.util.component.DumpableCollection; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.thread.Scheduler; @@ -129,10 +130,10 @@ public class ValidatingConnectionPool extends DuplexConnectionPool } @Override - public void dump(Appendable out, String indent) throws IOException + protected void dump(Appendable out, String indent, Object... items) throws IOException { - super.dump(out, indent); - ContainerLifeCycle.dump(out, indent, quarantine.values()); + DumpableCollection toDump = new DumpableCollection("quarantine", quarantine.values()); + super.dump(out, indent, Stream.concat(Stream.of(items), Stream.of(toDump))); } @Override @@ -202,8 +203,8 @@ public class ValidatingConnectionPool extends DuplexConnectionPool public String toString() { return String.format("%s[validationLeft=%dms]", - connection, - timeout - TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - timestamp) + connection, + timeout - TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - timestamp) ); } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/WWWAuthenticationProtocolHandler.java b/jetty-client/src/main/java/org/eclipse/jetty/client/WWWAuthenticationProtocolHandler.java index 3f6f13867f4..2ab13b00446 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/WWWAuthenticationProtocolHandler.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/WWWAuthenticationProtocolHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Authentication.java b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Authentication.java index 6333a377f35..f24522f2c9e 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Authentication.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Authentication.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -42,12 +42,14 @@ public interface Authentication { /** * Constant used to indicate that any realm will match. + * * @see #matches(String, URI, String) */ - public static final String ANY_REALM = "<>"; + String ANY_REALM = "<>"; /** * Matches {@link Authentication}s based on the given parameters + * * @param type the {@link Authentication} type such as "Basic" or "Digest" * @param uri the request URI * @param realm the authentication realm as provided in the {@code WWW-Authenticate} response header @@ -66,9 +68,9 @@ public interface Authentication * @param request the request to execute the authentication mechanism for * @param response the 401 response obtained in the previous attempt to request the protected resource * @param headerInfo the {@code WWW-Authenticate} (or {@code Proxy-Authenticate}) header chosen for this - * authentication (among the many that the response may contain) + * authentication (among the many that the response may contain) * @param context the conversation context in case the authentication needs multiple exchanges - * to be completed and information needs to be stored across exchanges + * to be completed and information needs to be stored across exchanges * @return the authentication result, or null if the authentication could not be performed */ Result authenticate(Request request, ContentResponse response, HeaderInfo headerInfo, Attributes context); @@ -76,20 +78,19 @@ public interface Authentication /** * Structure holding information about the {@code WWW-Authenticate} (or {@code Proxy-Authenticate}) header. */ - public static class HeaderInfo + class HeaderInfo { private final HttpHeader header; private final String type; - private final Map params; + private final Map params; - - public HeaderInfo(HttpHeader header, String type, Map params) throws IllegalArgumentException + public HeaderInfo(HttpHeader header, String type, Map params) throws IllegalArgumentException { this.header = header; this.type = type; this.params = params; } - + /** * @return the authentication type (for example "Basic" or "Digest") */ @@ -113,7 +114,7 @@ public interface Authentication { return params.get("base64"); } - + /** * @return additional authentication parameters */ @@ -121,7 +122,7 @@ public interface Authentication { return params; } - + /** * @return specified authentication parameter or null if does not exist */ @@ -142,7 +143,7 @@ public interface Authentication /** * {@link Result} holds the information needed to authenticate a {@link Request} via {@link org.eclipse.jetty.client.api.Authentication.Result#apply(org.eclipse.jetty.client.api.Request)}. */ - public static interface Result + interface Result { /** * @return the URI of the request that has been used to generate this {@link Result} diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/api/AuthenticationStore.java b/jetty-client/src/main/java/org/eclipse/jetty/client/api/AuthenticationStore.java index 5fffdc33a5a..eeffc9124e9 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/api/AuthenticationStore.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/api/AuthenticationStore.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -28,17 +28,17 @@ public interface AuthenticationStore /** * @param authentication the {@link Authentication} to add */ - public void addAuthentication(Authentication authentication); + void addAuthentication(Authentication authentication); /** * @param authentication the {@link Authentication} to remove */ - public void removeAuthentication(Authentication authentication); + void removeAuthentication(Authentication authentication); /** * Removes all {@link Authentication}s stored */ - public void clearAuthentications(); + void clearAuthentications(); /** * Returns the authentication that matches the given type (for example, "Basic" or "Digest"), @@ -50,22 +50,22 @@ public interface AuthenticationStore * @param realm the authentication realm * @return the authentication that matches the given parameters, or null */ - public Authentication findAuthentication(String type, URI uri, String realm); + Authentication findAuthentication(String type, URI uri, String realm); /** * @param result the {@link Authentication.Result} to add */ - public void addAuthenticationResult(Authentication.Result result); + void addAuthenticationResult(Authentication.Result result); /** * @param result the {@link Authentication.Result} to remove */ - public void removeAuthenticationResult(Authentication.Result result); + void removeAuthenticationResult(Authentication.Result result); /** * Removes all authentication results stored */ - public void clearAuthenticationResults(); + void clearAuthenticationResults(); /** * Returns an {@link Authentication.Result} that matches the given URI, or null if no @@ -74,5 +74,5 @@ public interface AuthenticationStore * @param uri the request URI * @return the {@link Authentication.Result} that matches the given URI, or null */ - public Authentication.Result findAuthenticationResult(URI uri); + Authentication.Result findAuthenticationResult(URI uri); } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Connection.java b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Connection.java index 26e548ae1bd..b50bead1881 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Connection.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Connection.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/api/ContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/api/ContentProvider.java index 41293cfb898..9cab9324f82 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/api/ContentProvider.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/api/ContentProvider.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -69,12 +69,12 @@ public interface ContentProvider extends Iterable * An extension of {@link ContentProvider} that provides a content type string * to be used as a {@code Content-Type} HTTP header in requests. */ - public interface Typed extends ContentProvider + interface Typed extends ContentProvider { /** * @return the content type string such as "application/octet-stream" or * "application/json;charset=UTF8", or null if no content type must be set */ - public String getContentType(); + String getContentType(); } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/api/ContentResponse.java b/jetty-client/src/main/java/org/eclipse/jetty/client/api/ContentResponse.java index 074191bb366..01e22efa62b 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/api/ContentResponse.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/api/ContentResponse.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Destination.java b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Destination.java index 491ef11796e..2325657c0fb 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Destination.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Destination.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Request.java b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Request.java index edd2d3a9d8b..0442940df5e 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Request.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Request.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -40,7 +40,7 @@ import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.util.Fields; /** - *

      {@link Request} represents a HTTP request, and offers a fluent interface to customize + *

      {@link Request} represents an HTTP request, and offers a fluent interface to customize * various attributes such as the path, the headers, the content, etc.

      *

      You can create {@link Request} objects via {@link HttpClient#newRequest(String)} and * you can send them using either {@link #send()} for a blocking semantic, or @@ -243,7 +243,7 @@ public interface Request /** * @param accepts the media types that are acceptable in the response, such as - * "text/plain;q=0.5" or "text/html" (corresponds to the {@code Accept} header) + * "text/plain;q=0.5" or "text/html" (corresponds to the {@code Accept} header) * @return this request object */ Request accept(String... accepts); @@ -261,12 +261,14 @@ public interface Request Request idleTimeout(long timeout, TimeUnit unit); /** - * @return the total timeout for this request, in milliseconds + * @return the total timeout for this request, in milliseconds; + * zero or negative if the timeout is disabled */ long getTimeout(); /** - * @param timeout the total timeout for the request/response conversation + * @param timeout the total timeout for the request/response conversation; + * use zero or a negative value to disable the timeout * @param unit the timeout unit * @return this request object */ @@ -285,8 +287,8 @@ public interface Request /** * @param listenerClass the class of the listener, or null for all listeners classes - * @return the listeners for request events of the given class * @param the type of listener class + * @return the listeners for request events of the given class */ List getRequestListeners(Class listenerClass); @@ -435,27 +437,27 @@ public interface Request /** * Common, empty, super-interface for request listeners. */ - public interface RequestListener extends EventListener + interface RequestListener extends EventListener { } /** * Listener for the request queued event. */ - public interface QueuedListener extends RequestListener + interface QueuedListener extends RequestListener { /** * Callback method invoked when the request is queued, waiting to be sent * * @param request the request being queued */ - public void onQueued(Request request); + void onQueued(Request request); } /** * Listener for the request begin event. */ - public interface BeginListener extends RequestListener + interface BeginListener extends RequestListener { /** * Callback method invoked when the request begins being processed in order to be sent. @@ -463,86 +465,90 @@ public interface Request * * @param request the request that begins being processed */ - public void onBegin(Request request); + void onBegin(Request request); } /** * Listener for the request headers event. */ - public interface HeadersListener extends RequestListener + interface HeadersListener extends RequestListener { /** * Callback method invoked when the request headers (and perhaps small content) are ready to be sent. * The request has been converted into bytes, but not yet sent to the server, and further modifications * to the request may have no effect. + * * @param request the request that is about to be committed */ - public void onHeaders(Request request); + void onHeaders(Request request); } /** * Listener for the request committed event. */ - public interface CommitListener extends RequestListener + interface CommitListener extends RequestListener { /** * Callback method invoked when the request headers (and perhaps small content) have been sent. * The request is now committed, and in transit to the server, and further modifications to the * request may have no effect. + * * @param request the request that has been committed */ - public void onCommit(Request request); + void onCommit(Request request); } /** * Listener for the request content event. */ - public interface ContentListener extends RequestListener + interface ContentListener extends RequestListener { /** * Callback method invoked when a chunk of request content has been sent successfully. * Changes to bytes in the given buffer have no effect, as the content has already been sent. + * * @param request the request that has been committed * @param content the content */ - public void onContent(Request request, ByteBuffer content); + void onContent(Request request, ByteBuffer content); } /** * Listener for the request succeeded event. */ - public interface SuccessListener extends RequestListener + interface SuccessListener extends RequestListener { /** * Callback method invoked when the request has been successfully sent. * * @param request the request sent */ - public void onSuccess(Request request); + void onSuccess(Request request); } /** * Listener for the request failed event. */ - public interface FailureListener extends RequestListener + interface FailureListener extends RequestListener { /** * Callback method invoked when the request has failed to be sent + * * @param request the request that failed * @param failure the failure */ - public void onFailure(Request request, Throwable failure); + void onFailure(Request request, Throwable failure); } /** * Listener for all request events. */ - public interface Listener extends QueuedListener, BeginListener, HeadersListener, CommitListener, ContentListener, SuccessListener, FailureListener + interface Listener extends QueuedListener, BeginListener, HeadersListener, CommitListener, ContentListener, SuccessListener, FailureListener { /** * An empty implementation of {@link Listener} */ - public static class Adapter implements Listener + class Adapter implements Listener { @Override public void onQueued(Request request) diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Response.java b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Response.java index 562a9f77144..99d37164ddf 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Response.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Response.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -29,7 +29,7 @@ import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.util.Callback; /** - *

      {@link Response} represents a HTTP response and offers methods to retrieve status code, HTTP version + *

      {@link Response} represents an HTTP response and offers methods to retrieve status code, HTTP version * and headers.

      *

      {@link Response} objects are passed as parameters to {@link Response.Listener} callbacks, or as * future result of {@link Request#send()}.

      @@ -47,8 +47,8 @@ public interface Response /** * @param listenerClass the listener class - * @return the response listener passed to {@link org.eclipse.jetty.client.api.Request#send(org.eclipse.jetty.client.api.Response.CompleteListener)} * @param the type of class + * @return the response listener passed to {@link org.eclipse.jetty.client.api.Request#send(org.eclipse.jetty.client.api.Response.CompleteListener)} */ List getListeners(Class listenerClass); @@ -83,14 +83,14 @@ public interface Response /** * Common, empty, super-interface for response listeners */ - public interface ResponseListener extends EventListener + interface ResponseListener extends EventListener { } /** * Listener for the response begin event. */ - public interface BeginListener extends ResponseListener + interface BeginListener extends ResponseListener { /** * Callback method invoked when the response line containing HTTP version, @@ -100,13 +100,13 @@ public interface Response * * @param response the response containing the response line data */ - public void onBegin(Response response); + void onBegin(Response response); } /** * Listener for a response header event. */ - public interface HeaderListener extends ResponseListener + interface HeaderListener extends ResponseListener { /** * Callback method invoked when a response header has been received, @@ -116,26 +116,26 @@ public interface Response * @param field the header received * @return true to process the header, false to skip processing of the header */ - public boolean onHeader(Response response, HttpField field); + boolean onHeader(Response response, HttpField field); } /** * Listener for the response headers event. */ - public interface HeadersListener extends ResponseListener + interface HeadersListener extends ResponseListener { /** * Callback method invoked when the response headers have been received and parsed. * * @param response the response containing the response line data and the headers */ - public void onHeaders(Response response); + void onHeaders(Response response); } /** * Listener for the response content events. */ - public interface ContentListener extends ResponseListener + interface ContentListener extends ResponseListener { /** * Callback method invoked when the response content has been received. @@ -145,10 +145,10 @@ public interface Response * @param response the response containing the response line data and the headers * @param content the content bytes received */ - public void onContent(Response response, ByteBuffer content); + void onContent(Response response, ByteBuffer content); } - public interface AsyncContentListener extends ResponseListener + interface AsyncContentListener extends ResponseListener { /** * Callback method invoked asynchronously when the response content has been received. @@ -157,26 +157,26 @@ public interface Response * @param content the content bytes received * @param callback the callback to call when the content is consumed. */ - public void onContent(Response response, ByteBuffer content, Callback callback); + void onContent(Response response, ByteBuffer content, Callback callback); } /** * Listener for the response succeeded event. */ - public interface SuccessListener extends ResponseListener + interface SuccessListener extends ResponseListener { /** * Callback method invoked when the whole response has been successfully received. * * @param response the response containing the response line data and the headers */ - public void onSuccess(Response response); + void onSuccess(Response response); } /** * Listener for the response failure event. */ - public interface FailureListener extends ResponseListener + interface FailureListener extends ResponseListener { /** * Callback method invoked when the response has failed in the process of being received @@ -184,13 +184,13 @@ public interface Response * @param response the response containing data up to the point the failure happened * @param failure the failure happened */ - public void onFailure(Response response, Throwable failure); + void onFailure(Response response, Throwable failure); } /** * Listener for the request and response completed event. */ - public interface CompleteListener extends ResponseListener + interface CompleteListener extends ResponseListener { /** * Callback method invoked when the request and the response have been processed, @@ -206,18 +206,18 @@ public interface Response * * @param result the result of the request / response exchange */ - public void onComplete(Result result); + void onComplete(Result result); } /** * Listener for all response events. */ - public interface Listener extends BeginListener, HeaderListener, HeadersListener, ContentListener, AsyncContentListener, SuccessListener, FailureListener, CompleteListener + interface Listener extends BeginListener, HeaderListener, HeadersListener, ContentListener, AsyncContentListener, SuccessListener, FailureListener, CompleteListener { /** * An empty implementation of {@link Listener} */ - public static class Adapter implements Listener + class Adapter implements Listener { @Override public void onBegin(Response response) diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Result.java b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Result.java index 08e9e7cc8d0..d354c881607 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Result.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Result.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -120,9 +120,9 @@ public class Result public String toString() { return String.format("%s[%s > %s] %s", - Result.class.getSimpleName(), - request, - response, - getFailure()); + Result.class.getSimpleName(), + request, + response, + getFailure()); } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/api/package-info.java b/jetty-client/src/main/java/org/eclipse/jetty/client/api/package-info.java index 066cf981d48..b038f552a1b 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/api/package-info.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/api/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpChannelOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpChannelOverHTTP.java index a73a88ca5a1..6bd8cd84d9d 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpChannelOverHTTP.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpChannelOverHTTP.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -82,7 +82,7 @@ public class HttpChannelOverHTTP extends HttpChannel public void send(HttpExchange exchange) { outMessages.increment(); - sender.send( exchange ); + sender.send(exchange); } @Override @@ -98,28 +98,28 @@ public class HttpChannelOverHTTP extends HttpChannel return result; HttpResponse response = exchange.getResponse(); - - if ((response.getVersion() == HttpVersion.HTTP_1_1) && + + if ((response.getVersion() == HttpVersion.HTTP_1_1) && (response.getStatus() == HttpStatus.SWITCHING_PROTOCOLS_101)) { - String next_connection = response.getHeaders().get(HttpHeader.CONNECTION); - if ((next_connection == null) || !next_connection.toLowerCase(Locale.US).contains("upgrade")) + String nextConnection = response.getHeaders().get(HttpHeader.CONNECTION); + if ((nextConnection == null) || !nextConnection.toLowerCase(Locale.US).contains("upgrade")) { - return new Result(result,new HttpResponseException("101 Switching Protocols without Connection: Upgrade not supported",response)); + return new Result(result, new HttpResponseException("101 Switching Protocols without Connection: Upgrade not supported", response)); } - + // Upgrade Response HttpRequest request = exchange.getRequest(); - if (request instanceof HttpConnectionUpgrader) + HttpConnectionUpgrader upgrader = (HttpConnectionUpgrader)request.getConversation().getAttribute(HttpConnectionUpgrader.class.getName()); + if (upgrader != null) { - HttpConnectionUpgrader listener = (HttpConnectionUpgrader)request; try { - listener.upgrade(response,getHttpConnection()); + upgrader.upgrade(response, getHttpConnection()); } catch (Throwable x) { - return new Result(result,x); + return new Result(result, x); } } } @@ -197,9 +197,8 @@ public class HttpChannelOverHTTP extends HttpChannel public String toString() { return String.format("%s[send=%s,recv=%s]", - super.toString(), - sender, - receiver); + super.toString(), + sender, + receiver); } - } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpClientTransportOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpClientTransportOverHTTP.java index d91bc1da02a..298f5286a3a 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpClientTransportOverHTTP.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpClientTransportOverHTTP.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -36,7 +36,7 @@ public class HttpClientTransportOverHTTP extends AbstractConnectorHttpClientTran { public HttpClientTransportOverHTTP() { - this(Math.max( 1, ProcessorUtils.availableProcessors() / 2)); + this(Math.max(1, ProcessorUtils.availableProcessors() / 2)); } public HttpClientTransportOverHTTP(int selectors) diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpConnectionOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpConnectionOverHTTP.java index 2e344c3c840..85c56b31d0e 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpConnectionOverHTTP.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpConnectionOverHTTP.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -93,7 +93,6 @@ public class HttpConnectionOverHTTP extends AbstractConnection implements Connec return bytesOut.longValue(); } - protected void addBytesOut(long bytesOut) { this.bytesOut.add(bytesOut); @@ -209,9 +208,7 @@ public class HttpConnectionOverHTTP extends AbstractConnection implements Connec { if (!closed.get()) return false; - if (sweeps.incrementAndGet() < 4) - return false; - return true; + return sweeps.incrementAndGet() >= 4; } public void remove() @@ -247,7 +244,9 @@ public class HttpConnectionOverHTTP extends AbstractConnection implements Connec // Save the old idle timeout to restore it. EndPoint endPoint = getEndPoint(); idleTimeout = endPoint.getIdleTimeout(); - endPoint.setIdleTimeout(request.getIdleTimeout()); + long requestIdleTimeout = request.getIdleTimeout(); + if (requestIdleTimeout >= 0) + endPoint.setIdleTimeout(requestIdleTimeout); // One channel per connection, just delegate the send. return send(channel, exchange); diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpConnectionUpgrader.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpConnectionUpgrader.java index e09c9f274ab..b56969bc45f 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpConnectionUpgrader.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpConnectionUpgrader.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -22,5 +22,5 @@ import org.eclipse.jetty.client.HttpResponse; public interface HttpConnectionUpgrader { - public void upgrade(HttpResponse response, HttpConnectionOverHTTP connection); + void upgrade(HttpResponse response, HttpConnectionOverHTTP connection); } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpDestinationOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpDestinationOverHTTP.java index d6293859373..85660039ea7 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpDestinationOverHTTP.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpDestinationOverHTTP.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java index 2613e3a44b4..15e239eee06 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -161,7 +161,7 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res } /** - * Parses a HTTP response in the receivers buffer. + * Parses an HTTP response in the receivers buffer. * * @return true to indicate that parsing should be interrupted (and will be resumed by another thread). */ @@ -230,7 +230,7 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res String method = exchange.getRequest().getMethod(); parser.setHeadResponse(HttpMethod.HEAD.is(method) || - (HttpMethod.CONNECT.is(method) && status == HttpStatus.OK_200)); + (HttpMethod.CONNECT.is(method) && status == HttpStatus.OK_200)); exchange.getResponse().version(version).status(status).reason(reason); return !responseBegin(exchange); @@ -320,11 +320,8 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res if (status == HttpStatus.SWITCHING_PROTOCOLS_101) return true; - if (HttpMethod.CONNECT.is(exchange.getRequest().getMethod()) && - status == HttpStatus.OK_200) - return true; - - return false; + return HttpMethod.CONNECT.is(exchange.getRequest().getMethod()) && + status == HttpStatus.OK_200; } @Override @@ -346,7 +343,7 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res { HttpResponse response = exchange.getResponse(); response.status(failure.getCode()).reason(failure.getReason()); - failAndClose(new HttpResponseException("HTTP protocol violation: bad response on " + getHttpConnection(), response)); + failAndClose(new HttpResponseException("HTTP protocol violation: bad response on " + getHttpConnection(), response, failure)); } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpSenderOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpSenderOverHTTP.java index 003d685f9c6..1edae133609 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpSenderOverHTTP.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpSenderOverHTTP.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -59,7 +59,7 @@ public class HttpSenderOverHTTP extends HttpSender { try { - new HeadersCallback(exchange, content, callback, getHttpChannel().getHttpConnection()).iterate(); + new HeadersCallback(exchange, content, callback).iterate(); } catch (Throwable x) { @@ -83,8 +83,8 @@ public class HttpSenderOverHTTP extends HttpSender HttpGenerator.Result result = generator.generateRequest(null, null, chunk, contentBuffer, lastContent); if (LOG.isDebugEnabled()) LOG.debug("Generated content ({} bytes) - {}/{}", - contentBuffer == null ? -1 : contentBuffer.remaining(), - result, generator); + contentBuffer == null ? -1 : contentBuffer.remaining(), + result, generator); switch (result) { case NEED_CHUNK: @@ -94,8 +94,8 @@ public class HttpSenderOverHTTP extends HttpSender } case NEED_CHUNK_TRAILER: { - callback.succeeded(); - return; + chunk = bufferPool.acquire(httpClient.getRequestBufferSize(), false); + break; } case FLUSH: { @@ -138,21 +138,6 @@ public class HttpSenderOverHTTP extends HttpSender } } - @Override - protected void sendTrailers(HttpExchange exchange, Callback callback) - { - try - { - new TrailersCallback(callback).iterate(); - } - catch (Throwable x) - { - if (LOG.isDebugEnabled()) - LOG.debug(x); - callback.failed(x); - } - } - @Override protected void reset() { @@ -191,19 +176,17 @@ public class HttpSenderOverHTTP extends HttpSender private final HttpExchange exchange; private final Callback callback; private final MetaData.Request metaData; - private final HttpConnectionOverHTTP httpConnectionOverHTTP; private ByteBuffer headerBuffer; private ByteBuffer chunkBuffer; private ByteBuffer contentBuffer; private boolean lastContent; private boolean generated; - public HeadersCallback(HttpExchange exchange, HttpContent content, Callback callback, HttpConnectionOverHTTP httpConnectionOverHTTP) + public HeadersCallback(HttpExchange exchange, HttpContent content, Callback callback) { super(false); this.exchange = exchange; this.callback = callback; - this.httpConnectionOverHTTP = httpConnectionOverHTTP; HttpRequest request = exchange.getRequest(); ContentProvider requestContent = request.getContent(); @@ -231,10 +214,10 @@ public class HttpSenderOverHTTP extends HttpSender HttpGenerator.Result result = generator.generateRequest(metaData, headerBuffer, chunkBuffer, contentBuffer, lastContent); if (LOG.isDebugEnabled()) LOG.debug("Generated headers ({} bytes), chunk ({} bytes), content ({} bytes) - {}/{}", - headerBuffer == null ? -1 : headerBuffer.remaining(), - chunkBuffer == null ? -1 : chunkBuffer.remaining(), - contentBuffer == null ? -1 : contentBuffer.remaining(), - result, generator); + headerBuffer == null ? -1 : headerBuffer.remaining(), + chunkBuffer == null ? -1 : chunkBuffer.remaining(), + contentBuffer == null ? -1 : contentBuffer.remaining(), + result, generator); switch (result) { case NEED_HEADER: @@ -249,7 +232,8 @@ public class HttpSenderOverHTTP extends HttpSender } case NEED_CHUNK_TRAILER: { - return Action.SUCCEEDED; + chunkBuffer = httpClient.getByteBufferPool().acquire(httpClient.getRequestBufferSize(), false); + break; } case FLUSH: { @@ -260,11 +244,8 @@ public class HttpSenderOverHTTP extends HttpSender chunkBuffer = BufferUtil.EMPTY_BUFFER; if (contentBuffer == null) contentBuffer = BufferUtil.EMPTY_BUFFER; - - httpConnectionOverHTTP.addBytesOut( BufferUtil.length(headerBuffer) - + BufferUtil.length(chunkBuffer) - + BufferUtil.length(contentBuffer)); - + long bytes = headerBuffer.remaining() + chunkBuffer.remaining() + contentBuffer.remaining(); + getHttpChannel().getHttpConnection().addBytesOut(bytes); endPoint.write(this, headerBuffer, chunkBuffer, contentBuffer); generated = true; return Action.SCHEDULED; @@ -331,83 +312,6 @@ public class HttpSenderOverHTTP extends HttpSender } } - private class TrailersCallback extends IteratingCallback - { - private final Callback callback; - private ByteBuffer chunkBuffer; - - public TrailersCallback(Callback callback) - { - this.callback = callback; - } - - @Override - protected Action process() throws Throwable - { - while (true) - { - HttpGenerator.Result result = generator.generateRequest(null, null, chunkBuffer, null, true); - if (LOG.isDebugEnabled()) - LOG.debug("Generated trailers {}/{}", result, generator); - switch (result) - { - case NEED_CHUNK_TRAILER: - { - chunkBuffer = httpClient.getByteBufferPool().acquire(httpClient.getRequestBufferSize(), false); - break; - } - case FLUSH: - { - EndPoint endPoint = getHttpChannel().getHttpConnection().getEndPoint(); - endPoint.write(this, chunkBuffer); - return Action.SCHEDULED; - } - case SHUTDOWN_OUT: - { - shutdownOutput(); - return Action.SUCCEEDED; - } - case DONE: - { - return Action.SUCCEEDED; - } - default: - { - throw new IllegalStateException(result.toString()); - } - } - } - } - - @Override - public void succeeded() - { - release(); - super.succeeded(); - } - - @Override - public void failed(Throwable x) - { - release(); - callback.failed(x); - super.failed(x); - } - - @Override - protected void onCompleteSuccess() - { - super.onCompleteSuccess(); - callback.succeeded(); - } - - private void release() - { - httpClient.getByteBufferPool().release(chunkBuffer); - chunkBuffer = null; - } - } - private class ByteBufferRecyclerCallback extends Callback.Nested { private final ByteBufferPool pool; @@ -435,7 +339,9 @@ public class HttpSenderOverHTTP extends HttpSender public void failed(Throwable x) { for (ByteBuffer buffer : buffers) + { pool.release(buffer); + } super.failed(x); } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/jmx/HttpClientMBean.java b/jetty-client/src/main/java/org/eclipse/jetty/client/jmx/HttpClientMBean.java index 6ec3ffcdcef..dac274d4ccf 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/jmx/HttpClientMBean.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/jmx/HttpClientMBean.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/package-info.java b/jetty-client/src/main/java/org/eclipse/jetty/client/package-info.java index 9eb109df1ee..af26327a722 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/package-info.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,7 +18,7 @@ /** * Jetty Client : Implementation and Core Classes - * + * * This package provides APIs, utility classes and an implementation of an asynchronous HTTP client. *

      * The core class is {@link org.eclipse.jetty.client.HttpClient}, which acts as a central configuration object (for example @@ -48,6 +48,3 @@ */ package org.eclipse.jetty.client; -import org.eclipse.jetty.client.api.Response; - - diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/AbstractAuthentication.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/AbstractAuthentication.java index 7ef2c4e8c1c..c0475d22ff5 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/AbstractAuthentication.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/AbstractAuthentication.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/AbstractTypedContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/AbstractTypedContentProvider.java index 6f368418c72..e2eba112dc7 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/AbstractTypedContentProvider.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/AbstractTypedContentProvider.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/BasicAuthentication.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/BasicAuthentication.java index 800d997b119..be22484dd0c 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/BasicAuthentication.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/BasicAuthentication.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,6 +20,7 @@ package org.eclipse.jetty.client.util; import java.net.URI; import java.nio.charset.StandardCharsets; +import java.util.Base64; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.api.AuthenticationStore; @@ -27,7 +28,6 @@ import org.eclipse.jetty.client.api.ContentResponse; import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.util.Attributes; -import org.eclipse.jetty.util.B64Code; /** * Implementation of the HTTP "Basic" authentication defined in RFC 2617. @@ -91,7 +91,8 @@ public class BasicAuthentication extends AbstractAuthentication { this.uri = uri; this.header = header; - this.value = "Basic " + B64Code.encode(user + ":" + password, StandardCharsets.ISO_8859_1); + byte[] authBytes = (user + ":" + password).getBytes(StandardCharsets.ISO_8859_1); + this.value = "Basic " + Base64.getEncoder().encodeToString(authBytes); } @Override @@ -103,7 +104,8 @@ public class BasicAuthentication extends AbstractAuthentication @Override public void apply(Request request) { - request.header(header, value); + if (!request.getHeaders().contains(header, value)) + request.header(header, value); } @Override diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/BufferingResponseListener.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/BufferingResponseListener.java index d0229b286b0..68e3313c416 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/BufferingResponseListener.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/BufferingResponseListener.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -39,6 +39,7 @@ import org.eclipse.jetty.util.BufferUtil; * specified to the constructors.

      *

      The content may be retrieved from {@link #onSuccess(Response)} or {@link #onComplete(Result)} * via {@link #getContent()} or {@link #getContentAsString()}.

      + *

      Instances of this class are not reusable, so one must be allocated for each request.

      */ public abstract class BufferingResponseListener extends Listener.Adapter { @@ -187,7 +188,7 @@ public abstract class BufferingResponseListener extends Listener.Adapter return null; return BufferUtil.toString(buffer, encoding); } - + /** * @return Content as InputStream */ diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/ByteBufferContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/ByteBufferContentProvider.java index d9e879c71b0..845d6eb0a33 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/ByteBufferContentProvider.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/ByteBufferContentProvider.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -47,7 +47,9 @@ public class ByteBufferContentProvider extends AbstractTypedContentProvider this.buffers = buffers; int length = 0; for (ByteBuffer buffer : buffers) + { length += buffer.remaining(); + } this.length = length; } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/BytesContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/BytesContentProvider.java index 551a33d1b3a..534b98ed7fa 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/BytesContentProvider.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/BytesContentProvider.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -43,7 +43,9 @@ public class BytesContentProvider extends AbstractTypedContentProvider this.bytes = bytes; long length = 0; for (byte[] buffer : bytes) + { length += buffer.length; + } this.length = length; } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/DeferredContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/DeferredContentProvider.java index 335c2eb0b98..29b8ed9a925 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/DeferredContentProvider.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/DeferredContentProvider.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -54,8 +54,8 @@ import org.eclipse.jetty.util.Callback; * However, it is possible for subclasses to override {@link #offer(ByteBuffer)} and {@link #close()} to copy * the content to another location (for example a file) and be able to support multiple invocations * of of {@link #iterator()} returning the iterator provided by this - * class on the first invocation, and an iterator on the bytes copied to the other location - * for subsequent invocations. + * class on the first invocation, and an iterator on the bytes copied to the other location + * for subsequent invocations. *

      * Typical usage of {@link DeferredContentProvider} is in asynchronous proxies, where HTTP headers arrive * separately from HTTP content chunks. @@ -107,7 +107,9 @@ public class DeferredContentProvider implements AsyncContentProvider, Callback, public DeferredContentProvider(ByteBuffer... buffers) { for (ByteBuffer buffer : buffers) + { offer(buffer); + } } @Override @@ -115,7 +117,7 @@ public class DeferredContentProvider implements AsyncContentProvider, Callback, { if (!this.listener.compareAndSet(null, listener)) throw new IllegalStateException(String.format("The same %s instance cannot be used in multiple requests", - AsyncContentProvider.class.getName())); + AsyncContentProvider.class.getName())); if (isClosed()) { @@ -123,7 +125,9 @@ public class DeferredContentProvider implements AsyncContentProvider, Callback, { long total = 0; for (Chunk chunk : chunks) + { total += chunk.buffer.remaining(); + } length = total; } } @@ -308,7 +312,9 @@ public class DeferredContentProvider implements AsyncContentProvider, Callback, lock.notify(); } for (Chunk chunk : chunks) + { chunk.callback.failed(x); + } } @Override diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/DigestAuthentication.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/DigestAuthentication.java index fc2fb8363d6..9d2079fd078 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/DigestAuthentication.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/DigestAuthentication.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -36,7 +36,6 @@ import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.util.Attributes; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.TypeUtil; -import org.eclipse.jetty.util.log.Log; /** * Implementation of the HTTP "Digest" authentication defined in RFC 2617. @@ -69,15 +68,14 @@ public class DigestAuthentication extends AbstractAuthentication return "Digest"; } - @Override public boolean matches(String type, URI uri, String realm) { // digest authenication requires a realm if (realm == null) return false; - - return super.matches(type,uri,realm); + + return super.matches(type, uri, realm); } @Override @@ -98,7 +96,7 @@ public class DigestAuthentication extends AbstractAuthentication String clientQOP = null; if (serverQOP != null) { - List serverQOPValues = StringUtil.csvSplit(null,serverQOP,0,serverQOP.length()); + List serverQOPValues = StringUtil.csvSplit(null, serverQOP, 0, serverQOP.length()); if (serverQOPValues.contains("auth")) clientQOP = "auth"; else if (serverQOPValues.contains("auth-int")) @@ -162,33 +160,33 @@ public class DigestAuthentication extends AbstractAuthentication if (digester == null) return; - String A1 = user + ":" + realm + ":" + password; - String hashA1 = toHexString(digester.digest(A1.getBytes(StandardCharsets.ISO_8859_1))); + String a1 = user + ":" + realm + ":" + password; + String hashA1 = toHexString(digester.digest(a1.getBytes(StandardCharsets.ISO_8859_1))); String query = request.getQuery(); String path = request.getPath(); String uri = (query == null) ? path : path + "?" + query; - String A2 = request.getMethod() + ":" + uri; + String a2 = request.getMethod() + ":" + uri; if ("auth-int".equals(qop)) - A2 += ":" + toHexString(digester.digest(content)); - String hashA2 = toHexString(digester.digest(A2.getBytes(StandardCharsets.ISO_8859_1))); + a2 += ":" + toHexString(digester.digest(content)); + String hashA2 = toHexString(digester.digest(a2.getBytes(StandardCharsets.ISO_8859_1))); String nonceCount; String clientNonce; - String A3; + String a3; if (qop != null) { nonceCount = nextNonceCount(); clientNonce = newClientNonce(); - A3 = hashA1 + ":" + nonce + ":" + nonceCount + ":" + clientNonce + ":" + qop + ":" + hashA2; + a3 = hashA1 + ":" + nonce + ":" + nonceCount + ":" + clientNonce + ":" + qop + ":" + hashA2; } else { nonceCount = null; clientNonce = null; - A3 = hashA1 + ":" + nonce + ":" + hashA2; + a3 = hashA1 + ":" + nonce + ":" + hashA2; } - String hashA3 = toHexString(digester.digest(A3.getBytes(StandardCharsets.ISO_8859_1))); + String hashA3 = toHexString(digester.digest(a3.getBytes(StandardCharsets.ISO_8859_1))); StringBuilder value = new StringBuilder("Digest"); value.append(" username=\"").append(user).append("\""); diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/FormContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/FormContentProvider.java index e39b70c3a10..8e04561ab2d 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/FormContentProvider.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/FormContentProvider.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/FutureResponseListener.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/FutureResponseListener.java index 5e1a0c87ac1..f848340fbd6 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/FutureResponseListener.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/FutureResponseListener.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/InputStreamContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/InputStreamContentProvider.java index 9f8e2ad168a..7077dbbe130 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/InputStreamContentProvider.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/InputStreamContentProvider.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/InputStreamResponseListener.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/InputStreamResponseListener.java index a5e56fbff05..c31a68b7d43 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/InputStreamResponseListener.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/InputStreamResponseListener.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/MultiPartContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/MultiPartContentProvider.java index 8e61f8ec453..e6441371d57 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/MultiPartContentProvider.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/MultiPartContentProvider.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -115,10 +115,10 @@ public class MultiPartContentProvider extends AbstractTypedContentProvider imple * {@code content} as part content.

      *

      The {@code Content-Type} of this part will be obtained from:

      *
        - *
      • the {@code Content-Type} header in the {@code fields} parameter; otherwise
      • - *
      • the {@link org.eclipse.jetty.client.api.ContentProvider.Typed#getContentType()} method if the {@code content} parameter - * implements {@link org.eclipse.jetty.client.api.ContentProvider.Typed}; otherwise
      • - *
      • "text/plain"
      • + *
      • the {@code Content-Type} header in the {@code fields} parameter; otherwise
      • + *
      • the {@link org.eclipse.jetty.client.api.ContentProvider.Typed#getContentType()} method if the {@code content} parameter + * implements {@link org.eclipse.jetty.client.api.ContentProvider.Typed}; otherwise
      • + *
      • "text/plain"
      • *
      * * @param name the part name @@ -135,10 +135,10 @@ public class MultiPartContentProvider extends AbstractTypedContentProvider imple * {@code fileName} as file name, and the given {@code content} as part content.

      *

      The {@code Content-Type} of this part will be obtained from:

      *
        - *
      • the {@code Content-Type} header in the {@code fields} parameter; otherwise
      • - *
      • the {@link org.eclipse.jetty.client.api.ContentProvider.Typed#getContentType()} method if the {@code content} parameter - * implements {@link org.eclipse.jetty.client.api.ContentProvider.Typed}; otherwise
      • - *
      • "application/octet-stream"
      • + *
      • the {@code Content-Type} header in the {@code fields} parameter; otherwise
      • + *
      • the {@link org.eclipse.jetty.client.api.ContentProvider.Typed#getContentType()} method if the {@code content} parameter + * implements {@link org.eclipse.jetty.client.api.ContentProvider.Typed}; otherwise
      • + *
      • "application/octet-stream"
      • *
      * * @param name the part name @@ -289,12 +289,12 @@ public class MultiPartContentProvider extends AbstractTypedContentProvider imple public String toString() { return String.format("%s@%x[name=%s,fileName=%s,length=%d,headers=%s]", - getClass().getSimpleName(), - hashCode(), - name, - fileName, - content.getLength(), - fields); + getClass().getSimpleName(), + hashCode(), + name, + fileName, + content.getLength(), + fields); } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/OutputStreamContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/OutputStreamContentProvider.java index c946f9b3ef9..096c4a85c17 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/OutputStreamContentProvider.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/OutputStreamContentProvider.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -29,7 +29,6 @@ import org.eclipse.jetty.client.api.ContentProvider; import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.thread.Invocable.InvocationType; /** * A {@link ContentProvider} that provides content asynchronously through an {@link OutputStream} @@ -84,7 +83,7 @@ public class OutputStreamContentProvider implements AsyncContentProvider, Callba { return deferred.getInvocationType(); } - + @Override public long getLength() { diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/PathContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/PathContentProvider.java index dc103dee615..aa562e5111b 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/PathContentProvider.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/PathContentProvider.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -126,9 +126,9 @@ public class PathContentProvider extends AbstractTypedContentProvider { if (channel == null) { - buffer = bufferPool == null ? - ByteBuffer.allocateDirect(bufferSize) : - bufferPool.acquire(bufferSize, true); + buffer = bufferPool == null + ? ByteBuffer.allocateDirect(bufferSize) + : bufferPool.acquire(bufferSize, true); channel = Files.newByteChannel(filePath, StandardOpenOption.READ); if (LOG.isDebugEnabled()) LOG.debug("Opened file {}", filePath); diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/SPNEGOAuthentication.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/SPNEGOAuthentication.java new file mode 100644 index 00000000000..b8dc609f011 --- /dev/null +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/SPNEGOAuthentication.java @@ -0,0 +1,377 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.client.util; + +import java.io.IOException; +import java.net.URI; +import java.nio.file.Path; +import java.security.PrivilegedAction; +import java.util.Arrays; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; +import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.login.AppConfigurationEntry; +import javax.security.auth.login.Configuration; +import javax.security.auth.login.LoginContext; +import javax.security.auth.login.LoginException; + +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.api.AuthenticationStore; +import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.client.api.Request; +import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.util.Attributes; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.ietf.jgss.GSSContext; +import org.ietf.jgss.GSSException; +import org.ietf.jgss.GSSManager; +import org.ietf.jgss.GSSName; +import org.ietf.jgss.Oid; + +/** + *

      Implementation of the SPNEGO (or "Negotiate") authentication defined in RFC 4559.

      + *

      A {@link #getUserName() user} is logged in via JAAS (either via userName/password or + * via userName/keyTab) once only.

      + *

      For every request that needs authentication, a {@link GSSContext} is initiated and + * later established after reading the response from the server.

      + *

      Applications should create objects of this class and add them to the + * {@link AuthenticationStore} retrieved from the {@link HttpClient} + * via {@link HttpClient#getAuthenticationStore()}.

      + */ +public class SPNEGOAuthentication extends AbstractAuthentication +{ + private static final Logger LOG = Log.getLogger(SPNEGOAuthentication.class); + private static final String NEGOTIATE = HttpHeader.NEGOTIATE.asString(); + + private final GSSManager gssManager = GSSManager.getInstance(); + private String userName; + private String userPassword; + private Path userKeyTabPath; + private String serviceName; + private boolean useTicketCache; + private Path ticketCachePath; + private boolean renewTGT; + + public SPNEGOAuthentication(URI uri) + { + super(uri, ANY_REALM); + } + + @Override + public String getType() + { + return NEGOTIATE; + } + + /** + * @return the user name of the user to login + */ + public String getUserName() + { + return userName; + } + + /** + * @param userName user name of the user to login + */ + public void setUserName(String userName) + { + this.userName = userName; + } + + /** + * @return the password of the user to login + */ + public String getUserPassword() + { + return userPassword; + } + + /** + * @param userPassword the password of the user to login + * @see #setUserKeyTabPath(Path) + */ + public void setUserPassword(String userPassword) + { + this.userPassword = userPassword; + } + + /** + * @return the path of the keyTab file with the user credentials + */ + public Path getUserKeyTabPath() + { + return userKeyTabPath; + } + + /** + * @param userKeyTabPath the path of the keyTab file with the user credentials + * @see #setUserPassword(String) + */ + public void setUserKeyTabPath(Path userKeyTabPath) + { + this.userKeyTabPath = userKeyTabPath; + } + + /** + * @return the name of the service to use + */ + public String getServiceName() + { + return serviceName; + } + + /** + * @param serviceName the name of the service to use + */ + public void setServiceName(String serviceName) + { + this.serviceName = serviceName; + } + + /** + * @return whether to use the ticket cache during login + */ + public boolean isUseTicketCache() + { + return useTicketCache; + } + + /** + * @param useTicketCache whether to use the ticket cache during login + * @see #setTicketCachePath(Path) + */ + public void setUseTicketCache(boolean useTicketCache) + { + this.useTicketCache = useTicketCache; + } + + /** + * @return the path of the ticket cache file + */ + public Path getTicketCachePath() + { + return ticketCachePath; + } + + /** + * @param ticketCachePath the path of the ticket cache file + * @see #setUseTicketCache(boolean) + */ + public void setTicketCachePath(Path ticketCachePath) + { + this.ticketCachePath = ticketCachePath; + } + + /** + * @return whether to renew the ticket granting ticket + */ + public boolean isRenewTGT() + { + return renewTGT; + } + + /** + * @param renewTGT whether to renew the ticket granting ticket + */ + public void setRenewTGT(boolean renewTGT) + { + this.renewTGT = renewTGT; + } + + @Override + public Result authenticate(Request request, ContentResponse response, HeaderInfo headerInfo, Attributes context) + { + SPNEGOContext spnegoContext = (SPNEGOContext)context.getAttribute(SPNEGOContext.ATTRIBUTE); + if (LOG.isDebugEnabled()) + LOG.debug("Authenticate with context {}", spnegoContext); + if (spnegoContext == null) + { + spnegoContext = login(); + context.setAttribute(SPNEGOContext.ATTRIBUTE, spnegoContext); + } + + String b64Input = headerInfo.getBase64(); + byte[] input = b64Input == null ? new byte[0] : Base64.getDecoder().decode(b64Input); + byte[] output = Subject.doAs(spnegoContext.subject, initGSSContext(spnegoContext, request.getHost(), input)); + String b64Output = output == null ? null : new String(Base64.getEncoder().encode(output)); + + // The result cannot be used for subsequent requests, + // so it always has a null URI to avoid being cached. + return new SPNEGOResult(null, b64Output); + } + + private SPNEGOContext login() + { + try + { + // First login via JAAS using the Kerberos AS_REQ call, with a client user. + // This will populate the Subject with the client user principal and the TGT. + String user = getUserName(); + if (LOG.isDebugEnabled()) + LOG.debug("Logging in user {}", user); + CallbackHandler callbackHandler = new PasswordCallbackHandler(); + LoginContext loginContext = new LoginContext("", null, callbackHandler, new SPNEGOConfiguration()); + loginContext.login(); + Subject subject = loginContext.getSubject(); + + SPNEGOContext spnegoContext = new SPNEGOContext(); + spnegoContext.subject = subject; + if (LOG.isDebugEnabled()) + LOG.debug("Initialized {}", spnegoContext); + return spnegoContext; + } + catch (LoginException x) + { + throw new RuntimeException(x); + } + } + + private PrivilegedAction initGSSContext(SPNEGOContext spnegoContext, String host, byte[] bytes) + { + return () -> + { + try + { + // The call to initSecContext with the service name will + // trigger the Kerberos TGS_REQ call, asking for the SGT, + // which will be added to the Subject credentials because + // initSecContext() is called from within Subject.doAs(). + GSSContext gssContext = spnegoContext.gssContext; + if (gssContext == null) + { + String principal = getServiceName() + "@" + host; + GSSName serviceName = gssManager.createName(principal, GSSName.NT_HOSTBASED_SERVICE); + Oid spnegoOid = new Oid("1.3.6.1.5.5.2"); + gssContext = gssManager.createContext(serviceName, spnegoOid, null, GSSContext.INDEFINITE_LIFETIME); + spnegoContext.gssContext = gssContext; + gssContext.requestMutualAuth(true); + } + byte[] result = gssContext.initSecContext(bytes, 0, bytes.length); + if (LOG.isDebugEnabled()) + LOG.debug("{} {}", gssContext.isEstablished() ? "Initialized" : "Initializing", gssContext); + return result; + } + catch (GSSException x) + { + throw new RuntimeException(x); + } + }; + } + + public static class SPNEGOResult implements Result + { + private final URI uri; + private final HttpHeader header; + private final String value; + + public SPNEGOResult(URI uri, String token) + { + this(uri, HttpHeader.AUTHORIZATION, token); + } + + public SPNEGOResult(URI uri, HttpHeader header, String token) + { + this.uri = uri; + this.header = header; + this.value = NEGOTIATE + (token == null ? "" : " " + token); + } + + @Override + public URI getURI() + { + return uri; + } + + @Override + public void apply(Request request) + { + request.header(header, value); + } + } + + private static class SPNEGOContext + { + private static final String ATTRIBUTE = SPNEGOContext.class.getName(); + + private Subject subject; + private GSSContext gssContext; + + @Override + public String toString() + { + return String.format("%s@%x[context=%s]", getClass().getSimpleName(), hashCode(), gssContext); + } + } + + private class PasswordCallbackHandler implements CallbackHandler + { + @Override + public void handle(Callback[] callbacks) throws IOException + { + PasswordCallback callback = Arrays.stream(callbacks) + .filter(PasswordCallback.class::isInstance) + .map(PasswordCallback.class::cast) + .findAny() + .filter(c -> c.getPrompt().contains(getUserName())) + .orElseThrow(IOException::new); + callback.setPassword(getUserPassword().toCharArray()); + } + } + + private class SPNEGOConfiguration extends Configuration + { + @Override + public AppConfigurationEntry[] getAppConfigurationEntry(String name) + { + Map options = new HashMap<>(); + if (LOG.isDebugEnabled()) + options.put("debug", "true"); + options.put("refreshKrb5Config", "true"); + options.put("principal", getUserName()); + options.put("isInitiator", "true"); + Path keyTabPath = getUserKeyTabPath(); + if (keyTabPath != null) + { + options.put("doNotPrompt", "true"); + options.put("useKeyTab", "true"); + options.put("keyTab", keyTabPath.toAbsolutePath().toString()); + options.put("storeKey", "true"); + } + boolean useTicketCache = isUseTicketCache(); + if (useTicketCache) + { + options.put("useTicketCache", "true"); + Path ticketCachePath = getTicketCachePath(); + if (ticketCachePath != null) + options.put("ticketCache", ticketCachePath.toAbsolutePath().toString()); + options.put("renewTGT", String.valueOf(isRenewTGT())); + } + + String moduleClass = "com.sun.security.auth.module.Krb5LoginModule"; + AppConfigurationEntry config = new AppConfigurationEntry(moduleClass, AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, options); + return new AppConfigurationEntry[]{config}; + } + } +} diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/StringContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/StringContentProvider.java index 86aed965940..0489e76e4c6 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/StringContentProvider.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/StringContentProvider.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/package-info.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/package-info.java index c0a3e0258f5..af36359f78e 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/package-info.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/AbstractHttpClientServerTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/AbstractHttpClientServerTest.java index 16858c0c879..13f88754e79 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/AbstractHttpClientServerTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/AbstractHttpClientServerTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,6 +19,7 @@ package org.eclipse.jetty.client; import java.nio.file.Path; +import java.util.function.Consumer; import java.util.stream.Stream; import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP; @@ -30,6 +31,8 @@ import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.util.SocketAddressResolver; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.thread.QueuedThreadPool; +import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler; +import org.eclipse.jetty.util.thread.Scheduler; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.params.provider.Arguments; @@ -55,7 +58,7 @@ public abstract class AbstractHttpClientServerTest serverThreads.setName("server"); server = new Server(serverThreads); } - connector = new ServerConnector(server, scenario.newSslContextFactory()); + connector = new ServerConnector(server, scenario.newServerSslContextFactory()); connector.setPort(0); server.addConnector(connector); server.setHandler(handler); @@ -64,19 +67,32 @@ public abstract class AbstractHttpClientServerTest protected void startClient(final Scenario scenario) throws Exception { - startClient(scenario, new HttpClientTransportOverHTTP(1)); + startClient(scenario, null, null); } - protected void startClient(final Scenario scenario, HttpClientTransport transport) throws Exception + protected void startClient(final Scenario scenario, HttpClientTransport transport, Consumer config) throws Exception { - QueuedThreadPool clientThreads = new QueuedThreadPool(); - clientThreads.setName("client"); - client = new HttpClient(transport, scenario.newSslContextFactory()); - client.setExecutor(clientThreads); + if (transport == null) + transport = new HttpClientTransportOverHTTP(1); + + QueuedThreadPool executor = new QueuedThreadPool(); + executor.setName("client"); + Scheduler scheduler = new ScheduledExecutorScheduler("client-scheduler", false); + client = newHttpClient(scenario, transport); + client.setExecutor(executor); + client.setScheduler(scheduler); client.setSocketAddressResolver(new SocketAddressResolver.Sync()); + if (config != null) + config.accept(client); + client.start(); } + public HttpClient newHttpClient(Scenario scenario, HttpClientTransport transport) + { + return new HttpClient(transport, scenario.newClientSslContextFactory()); + } + @AfterEach public void disposeClient() throws Exception { @@ -97,37 +113,54 @@ public abstract class AbstractHttpClientServerTest } } - public static class ScenarioProvider implements ArgumentsProvider { + public static class ScenarioProvider implements ArgumentsProvider + { @Override - public Stream provideArguments(ExtensionContext context) throws Exception + public Stream provideArguments(ExtensionContext context) { return Stream.of( - new NormalScenario(), - new SslScenario() - // TODO: add more ssl / non-ssl scenarios here + new NormalScenario(), + new SslScenario() + // TODO: add more ssl / non-ssl scenarios here ).map(Arguments::of); } } - public static class NonSslScenarioProvider implements ArgumentsProvider { + public static class NonSslScenarioProvider implements ArgumentsProvider + { @Override - public Stream provideArguments(ExtensionContext context) throws Exception + public Stream provideArguments(ExtensionContext context) { return Stream.of( - new NormalScenario() - // TODO: add more non-ssl scenarios here + new NormalScenario() + // TODO: add more non-ssl scenarios here ).map(Arguments::of); } } public interface Scenario { - default SslContextFactory newSslContextFactory() { return null; } + SslContextFactory newClientSslContextFactory(); + + SslContextFactory newServerSslContextFactory(); + String getScheme(); } public static class NormalScenario implements Scenario { + @Override + public SslContextFactory newClientSslContextFactory() + { + return null; + } + + @Override + public SslContextFactory newServerSslContextFactory() + { + return null; + } + @Override public String getScheme() { @@ -144,15 +177,27 @@ public abstract class AbstractHttpClientServerTest public static class SslScenario implements Scenario { @Override - public SslContextFactory newSslContextFactory() + public SslContextFactory newClientSslContextFactory() + { + SslContextFactory.Client result = new SslContextFactory.Client(); + result.setEndpointIdentificationAlgorithm(null); + configure(result); + return result; + } + + @Override + public SslContextFactory newServerSslContextFactory() + { + SslContextFactory.Server result = new SslContextFactory.Server(); + configure(result); + return result; + } + + private void configure(SslContextFactory ssl) { Path keystorePath = MavenTestingUtils.getTestResourcePath("keystore.jks"); - - SslContextFactory ssl = new SslContextFactory(); - ssl.setEndpointIdentificationAlgorithm(""); ssl.setKeyStorePath(keystorePath.toString()); ssl.setKeyStorePassword("storepwd"); - return ssl; } @Override diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ClientConnectionCloseTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ClientConnectionCloseTest.java index 85aa2a97be2..50381e3e8d2 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/ClientConnectionCloseTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ClientConnectionCloseTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,17 +18,11 @@ package org.eclipse.jetty.client; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.IOException; import java.io.InterruptedIOException; import java.nio.ByteBuffer; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; - import javax.servlet.ServletException; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; @@ -47,6 +41,11 @@ import org.eclipse.jetty.server.handler.AbstractHandler; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsSource; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +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 ClientConnectionCloseTest extends AbstractHttpClientServerTest { @ParameterizedTest @@ -91,15 +90,15 @@ public class ClientConnectionCloseTest extends AbstractHttpClientServerTest DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool(); ContentResponse response = client.newRequest(host, port) - .scheme(scenario.getScheme()) - .header(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString()) - .content(new StringContentProvider("0")) - .onRequestSuccess(request -> - { - HttpConnectionOverHTTP connection = (HttpConnectionOverHTTP)connectionPool.getActiveConnections().iterator().next(); - assertFalse(connection.getEndPoint().isOutputShutdown()); - }) - .send(); + .scheme(scenario.getScheme()) + .header(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString()) + .content(new StringContentProvider("0")) + .onRequestSuccess(request -> + { + HttpConnectionOverHTTP connection = (HttpConnectionOverHTTP)connectionPool.getActiveConnections().iterator().next(); + assertFalse(connection.getEndPoint().isOutputShutdown()); + }) + .send(); assertEquals(HttpStatus.OK_200, response.getStatus()); assertArrayEquals(data, response.getContent()); @@ -130,19 +129,19 @@ public class ClientConnectionCloseTest extends AbstractHttpClientServerTest CountDownLatch resultLatch = new CountDownLatch(1); long idleTimeout = 1000; client.newRequest(host, port) - .scheme(scenario.getScheme()) - .header(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString()) - .idleTimeout(idleTimeout, TimeUnit.MILLISECONDS) - .onRequestSuccess(request -> - { - HttpConnectionOverHTTP connection = (HttpConnectionOverHTTP)connectionPool.getActiveConnections().iterator().next(); - assertFalse(connection.getEndPoint().isOutputShutdown()); - }) - .send(result -> - { - if (result.isFailed()) - resultLatch.countDown(); - }); + .scheme(scenario.getScheme()) + .header(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString()) + .idleTimeout(idleTimeout, TimeUnit.MILLISECONDS) + .onRequestSuccess(request -> + { + HttpConnectionOverHTTP connection = (HttpConnectionOverHTTP)connectionPool.getActiveConnections().iterator().next(); + assertFalse(connection.getEndPoint().isOutputShutdown()); + }) + .send(result -> + { + if (result.isFailed()) + resultLatch.countDown(); + }); assertTrue(resultLatch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); assertEquals(0, connectionPool.getConnectionCount()); @@ -191,20 +190,20 @@ public class ClientConnectionCloseTest extends AbstractHttpClientServerTest DeferredContentProvider content = new DeferredContentProvider(ByteBuffer.allocate(8)); CountDownLatch resultLatch = new CountDownLatch(1); client.newRequest(host, port) - .scheme(scenario.getScheme()) - .header(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString()) - .content(content) - .idleTimeout(idleTimeout, TimeUnit.MILLISECONDS) - .onRequestSuccess(request -> - { - HttpConnectionOverHTTP connection = (HttpConnectionOverHTTP)connectionPool.getActiveConnections().iterator().next(); - assertFalse(connection.getEndPoint().isOutputShutdown()); - }) - .send(result -> - { - if (result.isFailed()) - resultLatch.countDown(); - }); + .scheme(scenario.getScheme()) + .header(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString()) + .content(content) + .idleTimeout(idleTimeout, TimeUnit.MILLISECONDS) + .onRequestSuccess(request -> + { + HttpConnectionOverHTTP connection = (HttpConnectionOverHTTP)connectionPool.getActiveConnections().iterator().next(); + assertFalse(connection.getEndPoint().isOutputShutdown()); + }) + .send(result -> + { + if (result.isFailed()) + resultLatch.countDown(); + }); content.offer(ByteBuffer.allocate(8)); content.close(); @@ -244,15 +243,15 @@ public class ClientConnectionCloseTest extends AbstractHttpClientServerTest DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool(); ContentResponse response = client.newRequest(host, port) - .scheme(scenario.getScheme()) - .header(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString()) - .onRequestSuccess(request -> - { - HttpConnectionOverHTTP connection = (HttpConnectionOverHTTP)connectionPool.getActiveConnections().iterator().next(); - assertFalse(connection.getEndPoint().isOutputShutdown()); - }) - .onResponseHeaders(r -> r.getHeaders().remove(HttpHeader.CONNECTION)) - .send(); + .scheme(scenario.getScheme()) + .header(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString()) + .onRequestSuccess(request -> + { + HttpConnectionOverHTTP connection = (HttpConnectionOverHTTP)connectionPool.getActiveConnections().iterator().next(); + assertFalse(connection.getEndPoint().isOutputShutdown()); + }) + .onResponseHeaders(r -> r.getHeaders().remove(HttpHeader.CONNECTION)) + .send(); assertEquals(HttpStatus.OK_200, response.getStatus()); assertEquals(0, connectionPool.getConnectionCount()); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ConnectionPoolTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ConnectionPoolTest.java index 26a810e3739..79942ba172b 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/ConnectionPoolTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ConnectionPoolTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,9 +18,6 @@ package org.eclipse.jetty.client; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -30,7 +27,6 @@ import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; import java.util.stream.IntStream; import java.util.stream.Stream; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -53,6 +49,9 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + @Disabled // Disabled by @gregw on issue #2540 - commit 621b946b10884e7308eacca241dcf8b5d6f6cff2 public class ConnectionPoolTest { @@ -63,12 +62,16 @@ public class ConnectionPoolTest public static Stream pools() { List pools = new ArrayList<>(); - pools.add(new Object[] { DuplexConnectionPool.class, - (ConnectionPool.Factory) - destination -> new DuplexConnectionPool(destination, 8, destination)}); - pools.add(new Object[] { RoundRobinConnectionPool.class, - (ConnectionPool.Factory) - destination -> new RoundRobinConnectionPool(destination, 8, destination)}); + pools.add(new Object[]{ + DuplexConnectionPool.class, + (ConnectionPool.Factory) + destination -> new DuplexConnectionPool(destination, 8, destination) + }); + pools.add(new Object[]{ + RoundRobinConnectionPool.class, + (ConnectionPool.Factory) + destination -> new RoundRobinConnectionPool(destination, 8, destination) + }); return pools.stream().map(Arguments::of); } @@ -154,8 +157,8 @@ public class ConnectionPoolTest CountDownLatch latch = new CountDownLatch(parallelism * runs); List failures = new CopyOnWriteArrayList<>(); IntStream.range(0, parallelism).parallel().forEach(i -> - IntStream.range(0, runs).forEach(j -> - run(latch, iterations, failures))); + IntStream.range(0, runs).forEach(j -> + run(latch, iterations, failures))); assertTrue(latch.await(iterations, TimeUnit.SECONDS)); assertTrue(failures.isEmpty(), failures.toString()); } @@ -164,7 +167,9 @@ public class ConnectionPoolTest { long begin = System.nanoTime(); for (int i = 0; i < iterations; ++i) + { test(failures); + } long end = System.nanoTime(); long elapsed = TimeUnit.NANOSECONDS.toMillis(end - begin); System.err.printf("%d requests in %d ms, %.3f req/s%n", iterations, elapsed, elapsed > 0 ? iterations * 1000D / elapsed : -1D); @@ -194,8 +199,8 @@ public class ConnectionPoolTest private void test(HttpMethod method, boolean clientClose, boolean serverClose, int contentLength, List failures) { Request request = client.newRequest("localhost", connector.getLocalPort()) - .path("/") - .method(method); + .path("/") + .method(method); if (clientClose) request.header(HttpHeader.CONNECTION, "close"); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ContentResponseTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ContentResponseTest.java index 201eaa53936..8c230c80858 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/ContentResponseTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ContentResponseTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,14 +18,9 @@ package org.eclipse.jetty.client; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; - import java.io.IOException; import java.util.Random; import java.util.concurrent.TimeUnit; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -37,6 +32,10 @@ import org.eclipse.jetty.server.handler.AbstractHandler; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsSource; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + public class ContentResponseTest extends AbstractHttpClientServerTest { @ParameterizedTest @@ -56,9 +55,9 @@ public class ContentResponseTest extends AbstractHttpClientServerTest }); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(200, response.getStatus()); assertArrayEquals(content, response.getContent()); @@ -84,9 +83,9 @@ public class ContentResponseTest extends AbstractHttpClientServerTest }); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(200, response.getStatus()); assertEquals(content, response.getContentAsString()); @@ -114,9 +113,9 @@ public class ContentResponseTest extends AbstractHttpClientServerTest }); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(200, response.getStatus()); assertEquals(content, response.getContentAsString()); @@ -144,9 +143,9 @@ public class ContentResponseTest extends AbstractHttpClientServerTest }); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(200, response.getStatus()); assertEquals(content, response.getContentAsString()); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/EmptyServerHandler.java b/jetty-client/src/test/java/org/eclipse/jetty/client/EmptyServerHandler.java index be39d16ee17..1287ed445e1 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/EmptyServerHandler.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/EmptyServerHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,14 +19,12 @@ package org.eclipse.jetty.client; import java.io.IOException; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; -import org.eclipse.jetty.util.log.Log; public class EmptyServerHandler extends AbstractHandler.ErrorDispatchHandler { @@ -39,6 +37,5 @@ public class EmptyServerHandler extends AbstractHandler.ErrorDispatchHandler protected void service(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - Log.getRootLogger().info("EMPTY service {}",target); } } diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ExternalSiteTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ExternalSiteTest.java index 9105a955ad3..40f9c1ab06f 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/ExternalSiteTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ExternalSiteTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,10 +18,6 @@ package org.eclipse.jetty.client; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assumptions.assumeTrue; - import java.net.Socket; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -34,8 +30,13 @@ import org.eclipse.jetty.util.ssl.SslContextFactory; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assumptions.assumeTrue; + @Disabled public class ExternalSiteTest { @@ -44,7 +45,7 @@ public class ExternalSiteTest @BeforeEach public void prepare() throws Exception { - client = new HttpClient(new SslContextFactory()); + client = new HttpClient(new SslContextFactory.Client()); client.start(); } @@ -54,6 +55,7 @@ public class ExternalSiteTest client.stop(); } + @Tag("external") @Test public void testExternalSite() throws Exception { @@ -64,37 +66,31 @@ public class ExternalSiteTest assumeCanConnectTo(host, port); final CountDownLatch latch1 = new CountDownLatch(1); - client.newRequest(host, port).send(new Response.CompleteListener() + client.newRequest(host, port).send(result -> { - @Override - public void onComplete(Result result) - { - if (!result.isFailed() && result.getResponse().getStatus() == 200) - latch1.countDown(); - } + assertTrue(result.isSucceeded()); + assertEquals(200, result.getResponse().getStatus()); + latch1.countDown(); }); - assertTrue(latch1.await(10, TimeUnit.SECONDS)); + assertTrue(latch1.await(15, TimeUnit.SECONDS)); // Try again the same URI, but without specifying the port final CountDownLatch latch2 = new CountDownLatch(1); - client.newRequest("http://" + host).send(new Response.CompleteListener() + client.newRequest("http://" + host).send(result -> { - @Override - public void onComplete(Result result) - { - assertTrue(result.isSucceeded()); - assertEquals(200, result.getResponse().getStatus()); - latch2.countDown(); - } + assertTrue(result.isSucceeded()); + assertEquals(200, result.getResponse().getStatus()); + latch2.countDown(); }); - assertTrue(latch2.await(10, TimeUnit.SECONDS)); + assertTrue(latch2.await(15, TimeUnit.SECONDS)); } + @Tag("external") @Test public void testExternalSSLSite() throws Exception { client.stop(); - client = new HttpClient(new SslContextFactory()); + client = new HttpClient(new SslContextFactory.Client()); client.start(); String host = "api-3t.paypal.com"; @@ -104,18 +100,16 @@ public class ExternalSiteTest assumeCanConnectTo(host, port); final CountDownLatch latch = new CountDownLatch(1); - client.newRequest(host, port).scheme("https").path("/nvp").send(new Response.CompleteListener() + client.newRequest(host, port).scheme("https").path("/nvp").send(result -> { - @Override - public void onComplete(Result result) - { - if (result.isSucceeded() && result.getResponse().getStatus() == 200) - latch.countDown(); - } + assertTrue(result.isSucceeded()); + assertEquals(200, result.getResponse().getStatus()); + latch.countDown(); }); - assertTrue(latch.await(5, TimeUnit.SECONDS)); + assertTrue(latch.await(15, TimeUnit.SECONDS)); } + @Tag("external") @Test public void testExternalSiteWrongProtocol() throws Exception { @@ -129,33 +123,27 @@ public class ExternalSiteTest { final CountDownLatch latch = new CountDownLatch(3); client.newRequest(host, port) - .onResponseFailure(new Response.FailureListener() + .onResponseFailure((response, failure) -> latch.countDown()) + .send(new Response.Listener.Adapter() + { + @Override + public void onFailure(Response response, Throwable failure) { - @Override - public void onFailure(Response response, Throwable failure) - { - latch.countDown(); - } - }) - .send(new Response.Listener.Adapter() - { - @Override - public void onFailure(Response response, Throwable failure) - { - latch.countDown(); - } + latch.countDown(); + } - @Override - public void onComplete(Result result) - { - assertTrue(result.isFailed()); - latch.countDown(); - } - }); - assertTrue(latch.await(10, TimeUnit.SECONDS)); + @Override + public void onComplete(Result result) + { + assertTrue(result.isFailed()); + latch.countDown(); + } + }); + assertTrue(latch.await(15, TimeUnit.SECONDS)); } } + @Tag("external") @Test public void testExternalSiteRedirect() throws Exception { @@ -166,9 +154,10 @@ public class ExternalSiteTest assumeCanConnectTo(host, port); ContentResponse response = client.newRequest(host, port) - .scheme(HttpScheme.HTTPS.asString()) - .path("/twitter") - .send(); + .scheme(HttpScheme.HTTPS.asString()) + .path("/twitter") + .timeout(15, TimeUnit.SECONDS) + .send(); assertEquals(200, response.getStatus()); } @@ -180,7 +169,7 @@ public class ExternalSiteTest } catch (Throwable x) { - assumeTrue(x == null, "Unable to connect"); + assumeTrue(false, "Unable to connect"); } } } diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/GZIPContentDecoderTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/GZIPContentDecoderTest.java deleted file mode 100644 index 333ff8c1c51..00000000000 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/GZIPContentDecoderTest.java +++ /dev/null @@ -1,288 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.client; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; -import java.util.zip.GZIPInputStream; -import java.util.zip.GZIPOutputStream; - -import org.junit.jupiter.api.Test; - -@Deprecated -public class GZIPContentDecoderTest -{ - @Test - public void testStreamNoBlocks() throws Exception - { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - GZIPOutputStream output = new GZIPOutputStream(baos); - output.close(); - byte[] bytes = baos.toByteArray(); - - GZIPInputStream input = new GZIPInputStream(new ByteArrayInputStream(bytes), 1); - int read = input.read(); - assertEquals(-1, read); - } - - @Test - public void testStreamBigBlockOneByteAtATime() throws Exception - { - String data = "0123456789ABCDEF"; - for (int i = 0; i < 10; ++i) - data += data; - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - GZIPOutputStream output = new GZIPOutputStream(baos); - output.write(data.getBytes(StandardCharsets.UTF_8)); - output.close(); - byte[] bytes = baos.toByteArray(); - - baos = new ByteArrayOutputStream(); - GZIPInputStream input = new GZIPInputStream(new ByteArrayInputStream(bytes), 1); - int read; - while ((read = input.read()) >= 0) - baos.write(read); - assertEquals(data, new String(baos.toByteArray(), StandardCharsets.UTF_8)); - } - - @Test - public void testNoBlocks() throws Exception - { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - GZIPOutputStream output = new GZIPOutputStream(baos); - output.close(); - byte[] bytes = baos.toByteArray(); - - GZIPContentDecoder decoder = new GZIPContentDecoder(); - ByteBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes)); - assertEquals(0, decoded.remaining()); - } - - @Test - public void testSmallBlock() throws Exception - { - String data = "0"; - - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - GZIPOutputStream output = new GZIPOutputStream(baos); - output.write(data.getBytes(StandardCharsets.UTF_8)); - output.close(); - byte[] bytes = baos.toByteArray(); - - GZIPContentDecoder decoder = new GZIPContentDecoder(); - ByteBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes)); - assertEquals(data, StandardCharsets.UTF_8.decode(decoded).toString()); - } - - @Test - public void testSmallBlockWithGZIPChunkedAtBegin() throws Exception - { - String data = "0"; - - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - GZIPOutputStream output = new GZIPOutputStream(baos); - output.write(data.getBytes(StandardCharsets.UTF_8)); - output.close(); - byte[] bytes = baos.toByteArray(); - - // The header is 10 bytes, chunk at 11 bytes - byte[] bytes1 = new byte[11]; - System.arraycopy(bytes, 0, bytes1, 0, bytes1.length); - byte[] bytes2 = new byte[bytes.length - bytes1.length]; - System.arraycopy(bytes, bytes1.length, bytes2, 0, bytes2.length); - - GZIPContentDecoder decoder = new GZIPContentDecoder(); - ByteBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes1)); - assertEquals(0, decoded.capacity()); - decoded = decoder.decode(ByteBuffer.wrap(bytes2)); - assertEquals(data, StandardCharsets.UTF_8.decode(decoded).toString()); - } - - @Test - public void testSmallBlockWithGZIPChunkedAtEnd() throws Exception - { - String data = "0"; - - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - GZIPOutputStream output = new GZIPOutputStream(baos); - output.write(data.getBytes(StandardCharsets.UTF_8)); - output.close(); - byte[] bytes = baos.toByteArray(); - - // The trailer is 8 bytes, chunk the last 9 bytes - byte[] bytes1 = new byte[bytes.length - 9]; - System.arraycopy(bytes, 0, bytes1, 0, bytes1.length); - byte[] bytes2 = new byte[bytes.length - bytes1.length]; - System.arraycopy(bytes, bytes1.length, bytes2, 0, bytes2.length); - - GZIPContentDecoder decoder = new GZIPContentDecoder(); - ByteBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes1)); - assertEquals(data, StandardCharsets.UTF_8.decode(decoded).toString()); - assertFalse(decoder.isFinished()); - decoded = decoder.decode(ByteBuffer.wrap(bytes2)); - assertEquals(0, decoded.remaining()); - assertTrue(decoder.isFinished()); - } - - @Test - public void testSmallBlockWithGZIPTrailerChunked() throws Exception - { - String data = "0"; - - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - GZIPOutputStream output = new GZIPOutputStream(baos); - output.write(data.getBytes(StandardCharsets.UTF_8)); - output.close(); - byte[] bytes = baos.toByteArray(); - - // The trailer is 4+4 bytes, chunk the last 3 bytes - byte[] bytes1 = new byte[bytes.length - 3]; - System.arraycopy(bytes, 0, bytes1, 0, bytes1.length); - byte[] bytes2 = new byte[bytes.length - bytes1.length]; - System.arraycopy(bytes, bytes1.length, bytes2, 0, bytes2.length); - - GZIPContentDecoder decoder = new GZIPContentDecoder(); - ByteBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes1)); - assertEquals(0, decoded.capacity()); - decoded = decoder.decode(ByteBuffer.wrap(bytes2)); - assertEquals(data, StandardCharsets.UTF_8.decode(decoded).toString()); - } - - @Test - public void testTwoSmallBlocks() throws Exception - { - String data1 = "0"; - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - GZIPOutputStream output = new GZIPOutputStream(baos); - output.write(data1.getBytes(StandardCharsets.UTF_8)); - output.close(); - byte[] bytes1 = baos.toByteArray(); - - String data2 = "1"; - baos = new ByteArrayOutputStream(); - output = new GZIPOutputStream(baos); - output.write(data2.getBytes(StandardCharsets.UTF_8)); - output.close(); - byte[] bytes2 = baos.toByteArray(); - - byte[] bytes = new byte[bytes1.length + bytes2.length]; - System.arraycopy(bytes1, 0, bytes, 0, bytes1.length); - System.arraycopy(bytes2, 0, bytes, bytes1.length, bytes2.length); - - GZIPContentDecoder decoder = new GZIPContentDecoder(); - ByteBuffer buffer = ByteBuffer.wrap(bytes); - ByteBuffer decoded = decoder.decode(buffer); - assertEquals(data1, StandardCharsets.UTF_8.decode(decoded).toString()); - assertTrue(decoder.isFinished()); - assertTrue(buffer.hasRemaining()); - decoded = decoder.decode(buffer); - assertEquals(data2, StandardCharsets.UTF_8.decode(decoded).toString()); - assertTrue(decoder.isFinished()); - assertFalse(buffer.hasRemaining()); - } - - @Test - public void testBigBlock() throws Exception - { - String data = "0123456789ABCDEF"; - for (int i = 0; i < 10; ++i) - data += data; - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - GZIPOutputStream output = new GZIPOutputStream(baos); - output.write(data.getBytes(StandardCharsets.UTF_8)); - output.close(); - byte[] bytes = baos.toByteArray(); - - String result = ""; - GZIPContentDecoder decoder = new GZIPContentDecoder(); - ByteBuffer buffer = ByteBuffer.wrap(bytes); - while (buffer.hasRemaining()) - { - ByteBuffer decoded = decoder.decode(buffer); - result += StandardCharsets.UTF_8.decode(decoded).toString(); - } - assertEquals(data, result); - } - - @Test - public void testBigBlockOneByteAtATime() throws Exception - { - String data = "0123456789ABCDEF"; - for (int i = 0; i < 10; ++i) - data += data; - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - GZIPOutputStream output = new GZIPOutputStream(baos); - output.write(data.getBytes(StandardCharsets.UTF_8)); - output.close(); - byte[] bytes = baos.toByteArray(); - - String result = ""; - GZIPContentDecoder decoder = new GZIPContentDecoder(64); - ByteBuffer buffer = ByteBuffer.wrap(bytes); - while (buffer.hasRemaining()) - { - ByteBuffer decoded = decoder.decode(ByteBuffer.wrap(new byte[]{buffer.get()})); - if (decoded.hasRemaining()) - result += StandardCharsets.UTF_8.decode(decoded).toString(); - } - assertEquals(data, result); - assertTrue(decoder.isFinished()); - } - - @Test - public void testBigBlockWithExtraBytes() throws Exception - { - String data1 = "0123456789ABCDEF"; - for (int i = 0; i < 10; ++i) - data1 += data1; - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - GZIPOutputStream output = new GZIPOutputStream(baos); - output.write(data1.getBytes(StandardCharsets.UTF_8)); - output.close(); - byte[] bytes1 = baos.toByteArray(); - - String data2 = "HELLO"; - byte[] bytes2 = data2.getBytes(StandardCharsets.UTF_8); - - byte[] bytes = new byte[bytes1.length + bytes2.length]; - System.arraycopy(bytes1, 0, bytes, 0, bytes1.length); - System.arraycopy(bytes2, 0, bytes, bytes1.length, bytes2.length); - - String result = ""; - GZIPContentDecoder decoder = new GZIPContentDecoder(64); - ByteBuffer buffer = ByteBuffer.wrap(bytes); - while (buffer.hasRemaining()) - { - ByteBuffer decoded = decoder.decode(buffer); - if (decoded.hasRemaining()) - result += StandardCharsets.UTF_8.decode(decoded).toString(); - if (decoder.isFinished()) - break; - } - assertEquals(data1, result); - assertTrue(buffer.hasRemaining()); - assertEquals(data2, StandardCharsets.UTF_8.decode(buffer).toString()); - } -} diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HostnameVerificationTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HostnameVerificationTest.java index 985ff01473d..9ce3ab9955e 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HostnameVerificationTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HostnameVerificationTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,14 +18,9 @@ package org.eclipse.jetty.client; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.fail; - import java.io.IOException; import java.security.cert.CertificateException; import java.util.concurrent.ExecutionException; - import javax.net.ssl.SSLHandshakeException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -40,11 +35,14 @@ import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.hamcrest.Matchers; import org.junit.jupiter.api.AfterEach; - import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.fail; + /** * This test class runs tests to make sure that hostname verification (http://www.ietf.org/rfc/rfc2818.txt * section 3.1) is configurable in SslContextFactory and works as expected. @@ -52,7 +50,7 @@ import org.junit.jupiter.api.Test; @Disabled public class HostnameVerificationTest { - private SslContextFactory clientSslContextFactory = new SslContextFactory(); + private SslContextFactory clientSslContextFactory = new SslContextFactory.Client(); private Server server; private HttpClient client; private NetworkConnector connector; @@ -64,7 +62,7 @@ public class HostnameVerificationTest serverThreads.setName("server"); server = new Server(serverThreads); - SslContextFactory serverSslContextFactory = new SslContextFactory(); + SslContextFactory serverSslContextFactory = new SslContextFactory.Server(); serverSslContextFactory.setKeyStorePath("src/test/resources/keystore.jks"); serverSslContextFactory.setKeyStorePassword("storepwd"); connector = new ServerConnector(server, serverSslContextFactory); @@ -102,7 +100,7 @@ public class HostnameVerificationTest /** * This test is supposed to verify that hostname verification works as described in: * http://www.ietf.org/rfc/rfc2818.txt section 3.1. It uses a certificate with a common name different to localhost - * and sends a request to localhost. This should fail with a SSLHandshakeException. + * and sends a request to localhost. This should fail with an SSLHandshakeException. * * @throws Exception on test failure */ @@ -112,7 +110,8 @@ public class HostnameVerificationTest clientSslContextFactory.setEndpointIdentificationAlgorithm("HTTPS"); String uri = "https://localhost:" + connector.getLocalPort() + "/"; - ExecutionException x = assertThrows(ExecutionException.class, ()->{ + ExecutionException x = assertThrows(ExecutionException.class, () -> + { client.GET(uri); }); Throwable cause = x.getCause(); @@ -126,7 +125,6 @@ public class HostnameVerificationTest * work fine. * * @throws Exception on test failure - * */ @Test public void simpleGetWithHostnameVerificationDisabledTest() throws Exception diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpAuthenticationStoreTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpAuthenticationStoreTest.java index 071e3614638..d775854090b 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpAuthenticationStoreTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpAuthenticationStoreTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,8 +18,6 @@ package org.eclipse.jetty.client; -import static org.junit.jupiter.api.Assertions.assertNotNull; - import java.net.URI; import org.eclipse.jetty.client.api.Authentication; @@ -27,9 +25,10 @@ import org.eclipse.jetty.client.api.AuthenticationStore; import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.util.BasicAuthentication; import org.eclipse.jetty.client.util.DigestAuthentication; - import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertNotNull; + public class HttpAuthenticationStoreTest { @Test diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientAsyncContentTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientAsyncContentTest.java index 8663ba4c999..ee980f6dc47 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientAsyncContentTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientAsyncContentTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,16 +18,12 @@ package org.eclipse.jetty.client; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.IOException; import java.nio.ByteBuffer; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; - import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; @@ -41,6 +37,9 @@ import org.eclipse.jetty.util.Callback; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsSource; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class HttpClientAsyncContentTest extends AbstractHttpClientServerTest { @ParameterizedTest @@ -64,25 +63,25 @@ public class HttpClientAsyncContentTest extends AbstractHttpClientServerTest final AtomicReference contentLatch = new AtomicReference<>(new CountDownLatch(1)); final CountDownLatch completeLatch = new CountDownLatch(1); client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .onResponseContentAsync(new Response.AsyncContentListener() + .scheme(scenario.getScheme()) + .onResponseContentAsync(new Response.AsyncContentListener() + { + @Override + public void onContent(Response response, ByteBuffer content, Callback callback) { - @Override - public void onContent(Response response, ByteBuffer content, Callback callback) - { - contentCount.incrementAndGet(); - callbackRef.set(callback); - contentLatch.get().countDown(); - } - }) - .send(new Response.CompleteListener() + contentCount.incrementAndGet(); + callbackRef.set(callback); + contentLatch.get().countDown(); + } + }) + .send(new Response.CompleteListener() + { + @Override + public void onComplete(Result result) { - @Override - public void onComplete(Result result) - { - completeLatch.countDown(); - } - }); + completeLatch.countDown(); + } + }); assertTrue(contentLatch.get().await(5, TimeUnit.SECONDS)); Callback callback = callbackRef.get(); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientAuthenticationTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientAuthenticationTest.java index 12a02716450..c6b0dd263dc 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientAuthenticationTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientAuthenticationTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,13 +18,6 @@ package org.eclipse.jetty.client; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalToIgnoringCase; -import static org.hamcrest.Matchers.equalTo; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.File; import java.io.IOException; import java.net.URI; @@ -38,7 +31,6 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.function.IntFunction; -import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -51,9 +43,11 @@ import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.api.Response.Listener; import org.eclipse.jetty.client.api.Result; +import org.eclipse.jetty.client.util.AbstractAuthentication; import org.eclipse.jetty.client.util.BasicAuthentication; import org.eclipse.jetty.client.util.DeferredContentProvider; import org.eclipse.jetty.client.util.DigestAuthentication; +import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.security.Authenticator; import org.eclipse.jetty.security.ConstraintMapping; @@ -64,7 +58,6 @@ import org.eclipse.jetty.security.authentication.BasicAuthenticator; import org.eclipse.jetty.security.authentication.DigestAuthenticator; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.util.Attributes; import org.eclipse.jetty.util.IO; @@ -74,6 +67,14 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsSource; +import static org.eclipse.jetty.client.api.Authentication.ANY_REALM; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalToIgnoringCase; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest { private String realm = "TestRealm"; @@ -137,7 +138,7 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest { startBasic(scenario, new EmptyServerHandler()); URI uri = URI.create(scenario.getScheme() + "://localhost:" + connector.getLocalPort()); - test_Authentication(scenario, new BasicAuthentication(uri, Authentication.ANY_REALM, "basic", "basic")); + test_Authentication(scenario, new BasicAuthentication(uri, ANY_REALM, "basic", "basic")); } @ParameterizedTest @@ -155,7 +156,7 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest { startDigest(scenario, new EmptyServerHandler()); URI uri = URI.create(scenario.getScheme() + "://localhost:" + connector.getLocalPort()); - test_Authentication(scenario, new DigestAuthentication(uri, Authentication.ANY_REALM, "digest", "digest")); + test_Authentication(scenario, new DigestAuthentication(uri, ANY_REALM, "digest", "digest")); } private void test_Authentication(final Scenario scenario, Authentication authentication) throws Exception @@ -227,16 +228,19 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest @ArgumentsSource(ScenarioProvider.class) public void test_BasicAuthentication_ThenRedirect(Scenario scenario) throws Exception { - startBasic(scenario, new AbstractHandler() + startBasic(scenario, new EmptyServerHandler() { private final AtomicInteger requests = new AtomicInteger(); @Override - public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + protected void service(String target, org.eclipse.jetty.server.Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException { - baseRequest.setHandled(true); - if (requests.incrementAndGet() == 1) - response.sendRedirect(URIUtil.newURI(scenario.getScheme(), request.getServerName(), request.getServerPort(), request.getRequestURI(), null)); + int r = requests.incrementAndGet(); + if (r == 1) + { + String path = request.getRequestURI() + "/" + r; + response.sendRedirect(URIUtil.newURI(scenario.getScheme(), request.getServerName(), request.getServerPort(), path, null)); + } } }); @@ -255,10 +259,10 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest client.getRequestListeners().add(requestListener); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path("/secure") - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .path("/secure") + .timeout(5, TimeUnit.SECONDS) + .send(); assertNotNull(response); assertEquals(200, response.getStatus()); assertTrue(requests.await(5, TimeUnit.SECONDS)); @@ -269,12 +273,11 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest @ArgumentsSource(ScenarioProvider.class) public void test_Redirect_ThenBasicAuthentication(Scenario scenario) throws Exception { - startBasic(scenario, new AbstractHandler() + startBasic(scenario, new EmptyServerHandler() { @Override - public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + protected void service(String target, org.eclipse.jetty.server.Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException { - baseRequest.setHandled(true); if (request.getRequestURI().endsWith("/redirect")) response.sendRedirect(URIUtil.newURI(scenario.getScheme(), request.getServerName(), request.getServerPort(), "/secure", null)); } @@ -295,10 +298,10 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest client.getRequestListeners().add(requestListener); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path("/redirect") - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .path("/redirect") + .timeout(5, TimeUnit.SECONDS) + .send(); assertNotNull(response); assertEquals(200, response.getStatus()); assertTrue(requests.await(5, TimeUnit.SECONDS)); @@ -369,6 +372,9 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest ContentResponse response = request.timeout(5, TimeUnit.SECONDS).send(); assertNotNull(response); assertEquals(401, response.getStatus()); + + Authentication.Result authenticationResult = authenticationStore.findAuthenticationResult(uri); + assertNull(authenticationResult); } @ParameterizedTest @@ -398,19 +404,15 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest final CountDownLatch latch = new CountDownLatch(1); client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path("/secure") - .timeout(5, TimeUnit.SECONDS) - .send(new Response.CompleteListener() - { - @Override - public void onComplete(Result result) - { - assertTrue(result.isFailed()); - assertEquals(cause, result.getFailure().getMessage()); - latch.countDown(); - } - }); + .scheme(scenario.getScheme()) + .path("/secure") + .timeout(5, TimeUnit.SECONDS) + .send(result -> + { + assertTrue(result.isFailed()); + assertEquals(cause, result.getFailure().getMessage()); + latch.countDown(); + }); assertTrue(latch.await(5, TimeUnit.SECONDS)); } @@ -436,10 +438,10 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest }); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path("/secure") - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .path("/secure") + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(200, response.getStatus()); assertEquals(1, requests.get()); @@ -467,8 +469,8 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest } }; Request request = client.newRequest(uri) - .path("/secure") - .content(content); + .path("/secure") + .content(content); request.send(result -> { if (result.isSucceeded() && result.getResponse().getStatus() == HttpStatus.UNAUTHORIZED_401) @@ -480,21 +482,19 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest assertTrue(resultLatch.await(5, TimeUnit.SECONDS)); } - @ParameterizedTest @ArgumentsSource(ScenarioProvider.class) public void test_RequestFailsAfterResponse(Scenario scenario) throws Exception - { + { startBasic(scenario, new EmptyServerHandler() { @Override - protected void service(String target, org.eclipse.jetty.server.Request jettyRequest, HttpServletRequest request, - HttpServletResponse response) throws IOException, ServletException + protected void service(String target, org.eclipse.jetty.server.Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException { - IO.readBytes(jettyRequest.getInputStream()); + IO.readBytes(jettyRequest.getInputStream()); } }); - + CountDownLatch authLatch = new CountDownLatch(1); client.getProtocolHandlers().remove(WWWAuthenticationProtocolHandler.NAME); client.getProtocolHandlers().put(new WWWAuthenticationProtocolHandler(client) @@ -519,7 +519,7 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest }; } }); - + AuthenticationStore authenticationStore = client.getAuthenticationStore(); URI uri = URI.create(scenario.getScheme() + "://localhost:" + connector.getLocalPort()); @@ -543,9 +543,10 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest { authLatch.await(); } - catch(InterruptedException e) - {} - + catch (InterruptedException ignored) + { + } + // Trigger request failure. throw new RuntimeException(); } @@ -553,26 +554,255 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest { return null; } - + default: throw new IllegalStateException(); } }); CountDownLatch resultLatch = new CountDownLatch(1); client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path("/secure") - .content(content) - .onResponseSuccess(r->authLatch.countDown()) - .send(result -> - { - if (result.isSucceeded() && result.getResponse().getStatus() == HttpStatus.OK_200) - resultLatch.countDown(); - }); + .scheme(scenario.getScheme()) + .path("/secure") + .content(content) + .onResponseSuccess(r -> authLatch.countDown()) + .send(result -> + { + if (result.isSucceeded() && result.getResponse().getStatus() == HttpStatus.OK_200) + resultLatch.countDown(); + }); assertTrue(resultLatch.await(5, TimeUnit.SECONDS)); } + @ParameterizedTest + @ArgumentsSource(ScenarioProvider.class) + public void test_InfiniteAuthentication(Scenario scenario) throws Exception + { + String authType = "Authenticate"; + start(scenario, new EmptyServerHandler() + { + @Override + protected void service(String target, org.eclipse.jetty.server.Request jettyRequest, HttpServletRequest request, HttpServletResponse response) + { + // Always reply with a 401 to see if the client + // can handle an infinite authentication loop. + response.setStatus(HttpStatus.UNAUTHORIZED_401); + response.setHeader(HttpHeader.WWW_AUTHENTICATE.asString(), authType); + } + }); + + AuthenticationStore authenticationStore = client.getAuthenticationStore(); + URI uri = URI.create(scenario.getScheme() + "://localhost:" + connector.getLocalPort()); + authenticationStore.addAuthentication(new AbstractAuthentication(uri, Authentication.ANY_REALM) + { + @Override + public String getType() + { + return authType; + } + + @Override + public Result authenticate(Request request, ContentResponse response, HeaderInfo headerInfo, Attributes context) + { + return new Result() + { + @Override + public URI getURI() + { + return uri; + } + + @Override + public void apply(Request request) + { + } + }; + } + }); + + ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) + .scheme(scenario.getScheme()) + .send(); + + assertEquals(HttpStatus.UNAUTHORIZED_401, response.getStatus()); + } + + @Test + public void testTestHeaderInfoParsing() + { + AuthenticationProtocolHandler aph = new WWWAuthenticationProtocolHandler(client); + + HeaderInfo headerInfo = aph.getHeaderInfo("Digest realm=\"thermostat\", qop=\"auth\", nonce=\"1523430383\"").get(0); + assertTrue(headerInfo.getType().equalsIgnoreCase("Digest")); + assertEquals("auth", headerInfo.getParameter("qop")); + assertEquals("thermostat", headerInfo.getParameter("realm")); + assertEquals("1523430383", headerInfo.getParameter("nonce")); + + headerInfo = aph.getHeaderInfo("Digest qop=\"auth\", realm=\"thermostat\", nonce=\"1523430383\"").get(0); + assertTrue(headerInfo.getType().equalsIgnoreCase("Digest")); + assertEquals("auth", headerInfo.getParameter("qop")); + assertEquals("thermostat", headerInfo.getParameter("realm")); + assertEquals("1523430383", headerInfo.getParameter("nonce")); + + headerInfo = aph.getHeaderInfo("Digest qop=\"auth\", nonce=\"1523430383\", realm=\"thermostat\"").get(0); + assertTrue(headerInfo.getType().equalsIgnoreCase("Digest")); + assertEquals("auth", headerInfo.getParameter("qop")); + assertEquals("thermostat", headerInfo.getParameter("realm")); + assertEquals("1523430383", headerInfo.getParameter("nonce")); + + headerInfo = aph.getHeaderInfo("Digest qop=\"auth\", nonce=\"1523430383\"").get(0); + assertTrue(headerInfo.getType().equalsIgnoreCase("Digest")); + assertEquals("auth", headerInfo.getParameter("qop")); + assertNull(headerInfo.getParameter("realm")); + assertEquals("1523430383", headerInfo.getParameter("nonce")); + + // test multiple authentications + List headerInfoList = aph.getHeaderInfo("Digest qop=\"auth\", realm=\"thermostat\", nonce=\"1523430383\", " + + "Digest realm=\"thermostat2\", qop=\"auth2\", nonce=\"4522530354\", " + + "Digest qop=\"auth3\", nonce=\"9523570528\", realm=\"thermostat3\", " + + "Digest qop=\"auth4\", nonce=\"3526435321\""); + + assertTrue(headerInfoList.get(0).getType().equalsIgnoreCase("Digest")); + assertEquals("auth", headerInfoList.get(0).getParameter("qop")); + assertEquals("thermostat", headerInfoList.get(0).getParameter("realm")); + assertEquals("1523430383", headerInfoList.get(0).getParameter("nonce")); + + assertTrue(headerInfoList.get(1).getType().equalsIgnoreCase("Digest")); + assertEquals("auth2", headerInfoList.get(1).getParameter("qop")); + assertEquals("thermostat2", headerInfoList.get(1).getParameter("realm")); + assertEquals("4522530354", headerInfoList.get(1).getParameter("nonce")); + + assertTrue(headerInfoList.get(2).getType().equalsIgnoreCase("Digest")); + assertEquals("auth3", headerInfoList.get(2).getParameter("qop")); + assertEquals("thermostat3", headerInfoList.get(2).getParameter("realm")); + assertEquals("9523570528", headerInfoList.get(2).getParameter("nonce")); + + assertTrue(headerInfoList.get(3).getType().equalsIgnoreCase("Digest")); + assertEquals("auth4", headerInfoList.get(3).getParameter("qop")); + assertNull(headerInfoList.get(3).getParameter("realm")); + assertEquals("3526435321", headerInfoList.get(3).getParameter("nonce")); + + List headerInfos = aph.getHeaderInfo("Newauth realm=\"apps\", type=1, title=\"Login to \\\"apps\\\"\", Basic realm=\"simple\""); + assertTrue(headerInfos.get(0).getType().equalsIgnoreCase("Newauth")); + assertEquals("apps", headerInfos.get(0).getParameter("realm")); + assertEquals("1", headerInfos.get(0).getParameter("type")); + + assertEquals(headerInfos.get(0).getParameter("title"), "Login to \"apps\""); + + assertTrue(headerInfos.get(1).getType().equalsIgnoreCase("Basic")); + assertEquals("simple", headerInfos.get(1).getParameter("realm")); + } + + @Test + public void testTestHeaderInfoParsingUnusualCases() + { + AuthenticationProtocolHandler aph = new WWWAuthenticationProtocolHandler(client); + + HeaderInfo headerInfo = aph.getHeaderInfo("Scheme").get(0); + assertTrue(headerInfo.getType().equalsIgnoreCase("Scheme")); + assertNull(headerInfo.getParameter("realm")); + + List headerInfos = aph.getHeaderInfo("Scheme1 , Scheme2 , Scheme3"); + assertEquals(3, headerInfos.size()); + assertTrue(headerInfos.get(0).getType().equalsIgnoreCase("Scheme1")); + assertTrue(headerInfos.get(1).getType().equalsIgnoreCase("Scheme2")); + assertTrue(headerInfos.get(2).getType().equalsIgnoreCase("Scheme3")); + + headerInfo = aph.getHeaderInfo("Scheme name=\"value\", other=\"value2\"").get(0); + assertTrue(headerInfo.getType().equalsIgnoreCase("Scheme")); + assertEquals("value", headerInfo.getParameter("name")); + assertEquals("value2", headerInfo.getParameter("other")); + + headerInfo = aph.getHeaderInfo("Scheme name = value , other = \"value2\" ").get(0); + assertTrue(headerInfo.getType().equalsIgnoreCase("Scheme")); + assertEquals("value", headerInfo.getParameter("name")); + assertEquals("value2", headerInfo.getParameter("other")); + + headerInfos = aph.getHeaderInfo(", , , , ,,,Scheme name=value, ,,Scheme2 name=value2,, ,,"); + assertEquals(headerInfos.size(), 2); + assertTrue(headerInfos.get(0).getType().equalsIgnoreCase("Scheme")); + assertEquals("value", headerInfos.get(0).getParameter("nAmE")); + assertTrue(headerInfos.get(1).getType().equalsIgnoreCase("Scheme2")); + + headerInfos = aph.getHeaderInfo("Scheme name=value, Scheme2 name=value2"); + assertEquals(headerInfos.size(), 2); + assertTrue(headerInfos.get(0).getType().equalsIgnoreCase("Scheme")); + assertEquals("value", headerInfos.get(0).getParameter("nAmE")); + assertThat(headerInfos.get(1).getType(), equalToIgnoringCase("Scheme2")); + + assertEquals("value2", headerInfos.get(1).getParameter("nAmE")); + + headerInfos = aph.getHeaderInfo("Scheme , ,, ,, name=value, Scheme2 name=value2"); + assertEquals(headerInfos.size(), 2); + assertTrue(headerInfos.get(0).getType().equalsIgnoreCase("Scheme")); + assertEquals("value", headerInfos.get(0).getParameter("name")); + assertTrue(headerInfos.get(1).getType().equalsIgnoreCase("Scheme2")); + assertEquals("value2", headerInfos.get(1).getParameter("name")); + + //Negotiate with base64 Content + headerInfo = aph.getHeaderInfo("Negotiate TlRMTVNTUAABAAAAB4IIogAAAAAAAAAAAAAAAAAAAAAFAs4OAAAADw==").get(0); + assertTrue(headerInfo.getType().equalsIgnoreCase("Negotiate")); + assertEquals("TlRMTVNTUAABAAAAB4IIogAAAAAAAAAAAAAAAAAAAAAFAs4OAAAADw==", headerInfo.getBase64()); + + headerInfos = aph.getHeaderInfo("Negotiate TlRMTVNTUAABAAAAAAAAAFAs4OAAAADw==, " + + "Negotiate YIIJvwYGKwYBBQUCoIIJszCCCa+gJDAi="); + assertTrue(headerInfos.get(0).getType().equalsIgnoreCase("Negotiate")); + assertEquals("TlRMTVNTUAABAAAAAAAAAFAs4OAAAADw==", headerInfos.get(0).getBase64()); + + assertTrue(headerInfos.get(1).getType().equalsIgnoreCase("Negotiate")); + assertEquals("YIIJvwYGKwYBBQUCoIIJszCCCa+gJDAi=", headerInfos.get(1).getBase64()); + } + + @Test + public void testEqualsInParam() + { + AuthenticationProtocolHandler aph = new WWWAuthenticationProtocolHandler(client); + HeaderInfo headerInfo; + + headerInfo = aph.getHeaderInfo("Digest realm=\"=the=rmo=stat=\", qop=\"=a=u=t=h=\", nonce=\"=1523430383=\"").get(0); + assertTrue(headerInfo.getType().equalsIgnoreCase("Digest")); + assertEquals("=a=u=t=h=", headerInfo.getParameter("qop")); + assertEquals("=the=rmo=stat=", headerInfo.getParameter("realm")); + assertEquals("=1523430383=", headerInfo.getParameter("nonce")); + + // test multiple authentications + List headerInfoList = aph.getHeaderInfo("Digest qop=\"=au=th=\", realm=\"=ther=mostat=\", nonce=\"=152343=0383=\", " + + "Digest realm=\"=thermostat2\", qop=\"=auth2\", nonce=\"=4522530354\", " + + "Digest qop=\"auth3=\", nonce=\"9523570528=\", realm=\"thermostat3=\", "); + + assertTrue(headerInfoList.get(0).getType().equalsIgnoreCase("Digest")); + assertEquals("=au=th=", headerInfoList.get(0).getParameter("qop")); + assertEquals("=ther=mostat=", headerInfoList.get(0).getParameter("realm")); + assertEquals("=152343=0383=", headerInfoList.get(0).getParameter("nonce")); + + assertTrue(headerInfoList.get(1).getType().equalsIgnoreCase("Digest")); + assertEquals("=auth2", headerInfoList.get(1).getParameter("qop")); + assertEquals("=thermostat2", headerInfoList.get(1).getParameter("realm")); + assertEquals("=4522530354", headerInfoList.get(1).getParameter("nonce")); + + assertTrue(headerInfoList.get(2).getType().equalsIgnoreCase("Digest")); + assertEquals("auth3=", headerInfoList.get(2).getParameter("qop")); + assertEquals("thermostat3=", headerInfoList.get(2).getParameter("realm")); + assertEquals("9523570528=", headerInfoList.get(2).getParameter("nonce")); + } + + @Test + public void testSingleChallengeLooksLikeMultipleChallenges() + { + AuthenticationProtocolHandler aph = new WWWAuthenticationProtocolHandler(client); + List headerInfoList = aph.getHeaderInfo("Digest param=\",f \""); + assertEquals(1, headerInfoList.size()); + + headerInfoList = aph.getHeaderInfo("Digest realm=\"thermostat\", qop=\",Digest realm=hello\", nonce=\"1523430383=\""); + assertEquals(1, headerInfoList.size()); + + HeaderInfo headerInfo = headerInfoList.get(0); + assertTrue(headerInfo.getType().equalsIgnoreCase("Digest")); + assertEquals(",Digest realm=hello", headerInfo.getParameter("qop")); + assertEquals("thermostat", headerInfo.getParameter("realm")); + assertEquals(headerInfo.getParameter("nonce"), "1523430383="); + } + private static class GeneratingContentProvider implements ContentProvider { private static final ByteBuffer DONE = ByteBuffer.allocate(0); @@ -629,182 +859,4 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest }; } } - - @Test - public void testTestHeaderInfoParsing() { - AuthenticationProtocolHandler aph = new WWWAuthenticationProtocolHandler(client); - - HeaderInfo headerInfo = aph.getHeaderInfo("Digest realm=\"thermostat\", qop=\"auth\", nonce=\"1523430383\"").get(0); - assertTrue(headerInfo.getType().equalsIgnoreCase("Digest")); - assertTrue(headerInfo.getParameter("qop").equals("auth")); - assertTrue(headerInfo.getParameter("realm").equals("thermostat")); - assertTrue(headerInfo.getParameter("nonce").equals("1523430383")); - - headerInfo = aph.getHeaderInfo("Digest qop=\"auth\", realm=\"thermostat\", nonce=\"1523430383\"").get(0); - assertTrue(headerInfo.getType().equalsIgnoreCase("Digest")); - assertTrue(headerInfo.getParameter("qop").equals("auth")); - assertTrue(headerInfo.getParameter("realm").equals("thermostat")); - assertTrue(headerInfo.getParameter("nonce").equals("1523430383")); - - headerInfo = aph.getHeaderInfo("Digest qop=\"auth\", nonce=\"1523430383\", realm=\"thermostat\"").get(0); - assertTrue(headerInfo.getType().equalsIgnoreCase("Digest")); - assertTrue(headerInfo.getParameter("qop").equals("auth")); - assertTrue(headerInfo.getParameter("realm").equals("thermostat")); - assertTrue(headerInfo.getParameter("nonce").equals("1523430383")); - - headerInfo = aph.getHeaderInfo("Digest qop=\"auth\", nonce=\"1523430383\"").get(0); - assertTrue(headerInfo.getType().equalsIgnoreCase("Digest")); - assertTrue(headerInfo.getParameter("qop").equals("auth")); - assertTrue(headerInfo.getParameter("realm") == null); - assertTrue(headerInfo.getParameter("nonce").equals("1523430383")); - - - // test multiple authentications - List headerInfoList = aph.getHeaderInfo("Digest qop=\"auth\", realm=\"thermostat\", nonce=\"1523430383\", " - + "Digest realm=\"thermostat2\", qop=\"auth2\", nonce=\"4522530354\", " - + "Digest qop=\"auth3\", nonce=\"9523570528\", realm=\"thermostat3\", " - + "Digest qop=\"auth4\", nonce=\"3526435321\""); - - assertTrue(headerInfoList.get(0).getType().equalsIgnoreCase("Digest")); - assertTrue(headerInfoList.get(0).getParameter("qop").equals("auth")); - assertTrue(headerInfoList.get(0).getParameter("realm").equals("thermostat")); - assertTrue(headerInfoList.get(0).getParameter("nonce").equals("1523430383")); - - assertTrue(headerInfoList.get(1).getType().equalsIgnoreCase("Digest")); - assertTrue(headerInfoList.get(1).getParameter("qop").equals("auth2")); - assertTrue(headerInfoList.get(1).getParameter("realm").equals("thermostat2")); - assertTrue(headerInfoList.get(1).getParameter("nonce").equals("4522530354")); - - assertTrue(headerInfoList.get(2).getType().equalsIgnoreCase("Digest")); - assertTrue(headerInfoList.get(2).getParameter("qop").equals("auth3")); - assertTrue(headerInfoList.get(2).getParameter("realm").equals("thermostat3")); - assertTrue(headerInfoList.get(2).getParameter("nonce").equals("9523570528")); - - assertTrue(headerInfoList.get(3).getType().equalsIgnoreCase("Digest")); - assertTrue(headerInfoList.get(3).getParameter("qop").equals("auth4")); - assertTrue(headerInfoList.get(3).getParameter("realm") == null); - assertTrue(headerInfoList.get(3).getParameter("nonce").equals("3526435321")); - - List headerInfos = aph.getHeaderInfo("Newauth realm=\"apps\", type=1, title=\"Login to \\\"apps\\\"\", Basic realm=\"simple\""); - assertTrue(headerInfos.get(0).getType().equalsIgnoreCase("Newauth")); - assertTrue(headerInfos.get(0).getParameter("realm").equals("apps")); - assertTrue(headerInfos.get(0).getParameter("type").equals("1")); - - assertEquals(headerInfos.get(0).getParameter("title"),"Login to \"apps\""); - - assertTrue(headerInfos.get(1).getType().equalsIgnoreCase("Basic")); - assertTrue(headerInfos.get(1).getParameter("realm").equals("simple")); - } - - @Test - public void testTestHeaderInfoParsingUnusualCases() { - AuthenticationProtocolHandler aph = new WWWAuthenticationProtocolHandler(client); - - HeaderInfo headerInfo = aph.getHeaderInfo("Scheme").get(0); - assertTrue(headerInfo.getType().equalsIgnoreCase("Scheme")); - assertTrue(headerInfo.getParameter("realm") == null); - - List headerInfos = aph.getHeaderInfo("Scheme1 , Scheme2 , Scheme3"); - assertEquals(3, headerInfos.size()); - assertTrue(headerInfos.get(0).getType().equalsIgnoreCase("Scheme1")); - assertTrue(headerInfos.get(1).getType().equalsIgnoreCase("Scheme2")); - assertTrue(headerInfos.get(2).getType().equalsIgnoreCase("Scheme3")); - - headerInfo = aph.getHeaderInfo("Scheme name=\"value\", other=\"value2\"").get(0); - assertTrue(headerInfo.getType().equalsIgnoreCase("Scheme")); - assertTrue(headerInfo.getParameter("name").equals("value")); - assertTrue(headerInfo.getParameter("other").equals("value2")); - - headerInfo = aph.getHeaderInfo("Scheme name = value , other = \"value2\" ").get(0); - assertTrue(headerInfo.getType().equalsIgnoreCase("Scheme")); - assertTrue(headerInfo.getParameter("name").equals("value")); - assertTrue(headerInfo.getParameter("other").equals("value2")); - - headerInfos = aph.getHeaderInfo(", , , , ,,,Scheme name=value, ,,Scheme2 name=value2,, ,,"); - assertEquals(headerInfos.size(), 2); - assertTrue(headerInfos.get(0).getType().equalsIgnoreCase("Scheme")); - assertTrue(headerInfos.get(0).getParameter("nAmE").equals("value")); - assertTrue(headerInfos.get(1).getType().equalsIgnoreCase("Scheme2")); - - headerInfos = aph.getHeaderInfo("Scheme name=value, Scheme2 name=value2"); - assertEquals(headerInfos.size(), 2); - assertTrue(headerInfos.get(0).getType().equalsIgnoreCase("Scheme")); - assertTrue(headerInfos.get(0).getParameter("nAmE").equals("value")); - assertThat(headerInfos.get(1).getType(), equalToIgnoringCase("Scheme2")); - - assertTrue(headerInfos.get(1).getParameter("nAmE").equals("value2")); - - headerInfos = aph.getHeaderInfo("Scheme , ,, ,, name=value, Scheme2 name=value2"); - assertEquals(headerInfos.size(), 2); - assertTrue(headerInfos.get(0).getType().equalsIgnoreCase("Scheme")); - assertTrue(headerInfos.get(0).getParameter("name").equals("value")); - assertTrue(headerInfos.get(1).getType().equalsIgnoreCase("Scheme2")); - assertTrue(headerInfos.get(1).getParameter("name").equals("value2")); - - //Negotiate with base64 Content - headerInfo = aph.getHeaderInfo("Negotiate TlRMTVNTUAABAAAAB4IIogAAAAAAAAAAAAAAAAAAAAAFAs4OAAAADw==").get(0); - assertTrue(headerInfo.getType().equalsIgnoreCase("Negotiate")); - assertTrue(headerInfo.getBase64().equals("TlRMTVNTUAABAAAAB4IIogAAAAAAAAAAAAAAAAAAAAAFAs4OAAAADw==")); - - headerInfos = aph.getHeaderInfo("Negotiate TlRMTVNTUAABAAAAAAAAAFAs4OAAAADw==, " - + "Negotiate YIIJvwYGKwYBBQUCoIIJszCCCa+gJDAi="); - assertTrue(headerInfos.get(0).getType().equalsIgnoreCase("Negotiate")); - assertTrue(headerInfos.get(0).getBase64().equals("TlRMTVNTUAABAAAAAAAAAFAs4OAAAADw==")); - - assertTrue(headerInfos.get(1).getType().equalsIgnoreCase("Negotiate")); - assertTrue(headerInfos.get(1).getBase64().equals("YIIJvwYGKwYBBQUCoIIJszCCCa+gJDAi=")); - } - - - - @Test - public void testEqualsInParam() - { - AuthenticationProtocolHandler aph = new WWWAuthenticationProtocolHandler(client); - HeaderInfo headerInfo; - - headerInfo = aph.getHeaderInfo("Digest realm=\"=the=rmo=stat=\", qop=\"=a=u=t=h=\", nonce=\"=1523430383=\"").get(0); - assertTrue(headerInfo.getType().equalsIgnoreCase("Digest")); - assertTrue(headerInfo.getParameter("qop").equals("=a=u=t=h=")); - assertTrue(headerInfo.getParameter("realm").equals("=the=rmo=stat=")); - assertTrue(headerInfo.getParameter("nonce").equals("=1523430383=")); - - - // test multiple authentications - List headerInfoList = aph.getHeaderInfo("Digest qop=\"=au=th=\", realm=\"=ther=mostat=\", nonce=\"=152343=0383=\", " - + "Digest realm=\"=thermostat2\", qop=\"=auth2\", nonce=\"=4522530354\", " - + "Digest qop=\"auth3=\", nonce=\"9523570528=\", realm=\"thermostat3=\", "); - - assertTrue(headerInfoList.get(0).getType().equalsIgnoreCase("Digest")); - assertTrue(headerInfoList.get(0).getParameter("qop").equals("=au=th=")); - assertTrue(headerInfoList.get(0).getParameter("realm").equals("=ther=mostat=")); - assertTrue(headerInfoList.get(0).getParameter("nonce").equals("=152343=0383=")); - - assertTrue(headerInfoList.get(1).getType().equalsIgnoreCase("Digest")); - assertTrue(headerInfoList.get(1).getParameter("qop").equals("=auth2")); - assertTrue(headerInfoList.get(1).getParameter("realm").equals("=thermostat2")); - assertTrue(headerInfoList.get(1).getParameter("nonce").equals("=4522530354")); - - assertTrue(headerInfoList.get(2).getType().equalsIgnoreCase("Digest")); - assertTrue(headerInfoList.get(2).getParameter("qop").equals("auth3=")); - assertTrue(headerInfoList.get(2).getParameter("realm").equals("thermostat3=")); - assertTrue(headerInfoList.get(2).getParameter("nonce").equals("9523570528=")); - } - - @Test - public void testSingleChallangeLooksLikeMultipleChallenge() - { - AuthenticationProtocolHandler aph = new WWWAuthenticationProtocolHandler(client); - List headerInfoList = aph.getHeaderInfo("Digest param=\",f \""); - assertEquals(1, headerInfoList.size()); - - headerInfoList = aph.getHeaderInfo("Digest realm=\"thermostat\", qop=\",Digest realm=hello\", nonce=\"1523430383=\""); - assertEquals(1, headerInfoList.size()); - - HeaderInfo headerInfo = headerInfoList.get(0); - assertTrue(headerInfo.getType().equalsIgnoreCase("Digest")); - assertTrue(headerInfo.getParameter("qop").equals(",Digest realm=hello")); - assertTrue(headerInfo.getParameter("realm").equals("thermostat")); - assertEquals(headerInfo.getParameter("nonce"), "1523430383="); - } } diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientChunkedContentTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientChunkedContentTest.java index 3704f0c5f03..f35bffdb027 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientChunkedContentTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientChunkedContentTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,9 +18,6 @@ package org.eclipse.jetty.client; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -40,9 +37,11 @@ import org.eclipse.jetty.client.util.FutureResponseListener; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.junit.jupiter.api.AfterEach; - import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class HttpClientChunkedContentTest { private HttpClient client; @@ -75,24 +74,24 @@ public class HttpClientChunkedContentTest final AtomicReference resultRef = new AtomicReference<>(); final CountDownLatch completeLatch = new CountDownLatch(1); client.newRequest("localhost", server.getLocalPort()) - .timeout(5, TimeUnit.SECONDS) - .send(new Response.CompleteListener() + .timeout(5, TimeUnit.SECONDS) + .send(new Response.CompleteListener() + { + @Override + public void onComplete(Result result) { - @Override - public void onComplete(Result result) - { - resultRef.set(result); - completeLatch.countDown(); - } - }); + resultRef.set(result); + completeLatch.countDown(); + } + }); try (Socket socket = server.accept()) { consumeRequestHeaders(socket); OutputStream output = socket.getOutputStream(); - String headers = "" + - "HTTP/1.1 200 OK\r\n" + + String headers = + "HTTP/1.1 200 OK\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n"; output.write(headers.getBytes(StandardCharsets.UTF_8)); @@ -100,8 +99,8 @@ public class HttpClientChunkedContentTest Thread.sleep(1000); - String terminal = "" + - "0\r\n" + + String terminal = + "0\r\n" + "\r\n"; output.write(terminal.getBytes(StandardCharsets.UTF_8)); output.flush(); @@ -129,35 +128,35 @@ public class HttpClientChunkedContentTest final AtomicReference resultRef = new AtomicReference<>(); final CountDownLatch completeLatch = new CountDownLatch(1); client.newRequest("localhost", server.getLocalPort()) - .onResponseContentAsync(new Response.AsyncContentListener() + .onResponseContentAsync(new Response.AsyncContentListener() + { + @Override + public void onContent(Response response, ByteBuffer content, Callback callback) { - @Override - public void onContent(Response response, ByteBuffer content, Callback callback) - { - if (callbackRef.compareAndSet(null, callback)) - firstContentLatch.countDown(); - else - callback.succeeded(); - } - }) - .timeout(5, TimeUnit.SECONDS) - .send(new Response.CompleteListener() + if (callbackRef.compareAndSet(null, callback)) + firstContentLatch.countDown(); + else + callback.succeeded(); + } + }) + .timeout(5, TimeUnit.SECONDS) + .send(new Response.CompleteListener() + { + @Override + public void onComplete(Result result) { - @Override - public void onComplete(Result result) - { - resultRef.set(result); - completeLatch.countDown(); - } - }); + resultRef.set(result); + completeLatch.countDown(); + } + }); try (Socket socket = server.accept()) { consumeRequestHeaders(socket); OutputStream output = socket.getOutputStream(); - String response = "" + - "HTTP/1.1 200 OK\r\n" + + String response = + "HTTP/1.1 200 OK\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "8\r\n" + @@ -182,7 +181,7 @@ public class HttpClientChunkedContentTest // Issue another request to be sure the connection is sane. Request request = client.newRequest("localhost", server.getLocalPort()) - .timeout(5, TimeUnit.SECONDS); + .timeout(5, TimeUnit.SECONDS); FutureResponseListener listener = new FutureResponseListener(request); request.send(listener); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientCorrelationDataTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientCorrelationDataTest.java new file mode 100644 index 00000000000..ac7e58d6eb6 --- /dev/null +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientCorrelationDataTest.java @@ -0,0 +1,70 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.client; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.client.api.Request; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ArgumentsSource; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class HttpClientCorrelationDataTest extends AbstractHttpClientServerTest +{ + @ParameterizedTest + @ArgumentsSource(ScenarioProvider.class) + public void testCorrelationData(Scenario scenario) throws Exception + { + String correlationName = "X-Correlation-Data"; + String correlationData = "123456"; + ThreadLocal correlation = new ThreadLocal<>(); + + start(scenario, new EmptyServerHandler() + { + @Override + protected void service(String target, org.eclipse.jetty.server.Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + assertEquals(correlationData, request.getHeader(correlationName)); + } + }); + client.getRequestListeners().add(new Request.Listener.Adapter() + { + @Override + public void onQueued(Request request) + { + request.header(correlationName, correlation.get()); + } + }); + + correlation.set(correlationData); + + ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) + .scheme(scenario.getScheme()) + .timeout(5, TimeUnit.SECONDS) + .send(); + + assertEquals(200, response.getStatus()); + } +} diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientCustomProxyTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientCustomProxyTest.java index 5380befd7c6..ea4d68982ab 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientCustomProxyTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientCustomProxyTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,15 +18,11 @@ package org.eclipse.jetty.client; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; - import java.io.IOException; import java.nio.ByteBuffer; import java.util.Map; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -49,9 +45,11 @@ import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.junit.jupiter.api.AfterEach; - import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class HttpClientCustomProxyTest { public static final byte[] CAFE_BABE = new byte[]{(byte)0xCA, (byte)0xFE, (byte)0xBA, (byte)0xBE}; @@ -108,8 +106,8 @@ public class HttpClientCustomProxyTest client.getProxyConfiguration().getProxies().add(new CAFEBABEProxy(new Origin.Address("localhost", proxyPort), false)); ContentResponse response = client.newRequest(serverHost, serverPort) - .timeout(5, TimeUnit.SECONDS) - .send(); + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(status, response.getStatus()); } diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientExplicitConnectionTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientExplicitConnectionTest.java index fe70713c688..0891b2b4382 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientExplicitConnectionTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientExplicitConnectionTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,11 +18,6 @@ package org.eclipse.jetty.client; -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.assertTrue; - import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -38,6 +33,11 @@ import org.eclipse.jetty.util.FuturePromise; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsSource; +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.assertTrue; + public class HttpClientExplicitConnectionTest extends AbstractHttpClientServerTest { @ParameterizedTest @@ -112,8 +112,8 @@ public class HttpClientExplicitConnectionTest extends AbstractHttpClientServerTe Connection connection = futureConnection.get(5, TimeUnit.SECONDS); CountDownLatch responseLatch = new CountDownLatch(1); Request request = client.newRequest(destination.getHost(), destination.getPort()) - .scheme(scenario.getScheme()) - .onResponseSuccess(response -> responseLatch.countDown()); + .scheme(scenario.getScheme()) + .onResponseSuccess(response -> responseLatch.countDown()); FutureResponseListener listener = new FutureResponseListener(request); connection.send(request, listener); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientFailureTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientFailureTest.java index cc92cff52fd..1ded467459b 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientFailureTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientFailureTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,10 +18,6 @@ package org.eclipse.jetty.client; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.nio.ByteBuffer; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; @@ -40,9 +36,12 @@ import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.junit.jupiter.api.AfterEach; - import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class HttpClientFailureTest { private Server server; @@ -87,11 +86,12 @@ public class HttpClientFailureTest }, null); client.start(); - assertThrows(ExecutionException.class, ()->{ + assertThrows(ExecutionException.class, () -> + { client.newRequest("localhost", connector.getLocalPort()) - .onRequestHeaders(request -> connectionRef.get().getEndPoint().close()) - .timeout(5, TimeUnit.SECONDS) - .send(); + .onRequestHeaders(request -> connectionRef.get().getEndPoint().close()) + .timeout(5, TimeUnit.SECONDS) + .send(); }); DuplexConnectionPool connectionPool = (DuplexConnectionPool)connectionRef.get().getHttpDestination().getConnectionPool(); @@ -122,18 +122,18 @@ public class HttpClientFailureTest final CountDownLatch completeLatch = new CountDownLatch(1); DeferredContentProvider content = new DeferredContentProvider(); client.newRequest("localhost", connector.getLocalPort()) - .onRequestCommit(request -> - { - connectionRef.get().getEndPoint().close(); - commitLatch.countDown(); - }) - .content(content) - .idleTimeout(2, TimeUnit.SECONDS) - .send(result -> - { - if (result.isFailed()) - completeLatch.countDown(); - }); + .onRequestCommit(request -> + { + connectionRef.get().getEndPoint().close(); + commitLatch.countDown(); + }) + .content(content) + .idleTimeout(2, TimeUnit.SECONDS) + .send(result -> + { + if (result.isFailed()) + completeLatch.countDown(); + }); assertTrue(commitLatch.await(5, TimeUnit.SECONDS)); final CountDownLatch contentLatch = new CountDownLatch(1); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientGZIPTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientGZIPTest.java index 0c4d5b1f5f4..6ec23d1c966 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientGZIPTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientGZIPTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,29 +18,35 @@ package org.eclipse.jetty.client; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InterruptedIOException; +import java.nio.charset.StandardCharsets; import java.util.Arrays; +import java.util.Random; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.zip.GZIPOutputStream; - -import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.io.MappedByteBufferPool; import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.handler.AbstractHandler; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsSource; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.lessThan; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assumptions.assumeTrue; + public class HttpClientGZIPTest extends AbstractHttpClientServerTest { @ParameterizedTest @@ -48,12 +54,11 @@ public class HttpClientGZIPTest extends AbstractHttpClientServerTest public void testGZIPContentEncoding(Scenario scenario) throws Exception { final byte[] data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - start(scenario, new AbstractHandler() + start(scenario, new EmptyServerHandler() { @Override - public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + protected void service(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException { - baseRequest.setHandled(true); response.setHeader("Content-Encoding", "gzip"); GZIPOutputStream gzipOutput = new GZIPOutputStream(response.getOutputStream()); gzipOutput.write(data); @@ -62,9 +67,9 @@ public class HttpClientGZIPTest extends AbstractHttpClientServerTest }); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(200, response.getStatus()); assertArrayEquals(data, response.getContent()); @@ -75,12 +80,11 @@ public class HttpClientGZIPTest extends AbstractHttpClientServerTest public void testGZIPContentOneByteAtATime(Scenario scenario) throws Exception { final byte[] data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - start(scenario, new AbstractHandler() + start(scenario, new EmptyServerHandler() { @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + protected void service(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException { - baseRequest.setHandled(true); response.setHeader("Content-Encoding", "gzip"); ByteArrayOutputStream gzipData = new ByteArrayOutputStream(); @@ -100,8 +104,8 @@ public class HttpClientGZIPTest extends AbstractHttpClientServerTest }); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .send(); + .scheme(scenario.getScheme()) + .send(); assertEquals(200, response.getStatus()); assertArrayEquals(data, response.getContent()); @@ -112,12 +116,11 @@ public class HttpClientGZIPTest extends AbstractHttpClientServerTest public void testGZIPContentSentTwiceInOneWrite(Scenario scenario) throws Exception { final byte[] data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - start(scenario, new AbstractHandler() + start(scenario, new EmptyServerHandler() { @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + protected void service(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException { - baseRequest.setHandled(true); response.setHeader("Content-Encoding", "gzip"); ByteArrayOutputStream gzipData = new ByteArrayOutputStream(); @@ -135,8 +138,8 @@ public class HttpClientGZIPTest extends AbstractHttpClientServerTest }); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .send(); + .scheme(scenario.getScheme()) + .send(); assertEquals(200, response.getStatus()); @@ -164,12 +167,11 @@ public class HttpClientGZIPTest extends AbstractHttpClientServerTest private void testGZIPContentFragmented(Scenario scenario, final int fragment) throws Exception { final byte[] data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - start(scenario, new AbstractHandler() + start(scenario, new EmptyServerHandler() { @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + protected void service(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException { - baseRequest.setHandled(true); response.setHeader("Content-Encoding", "gzip"); ByteArrayOutputStream gzipData = new ByteArrayOutputStream(); @@ -193,8 +195,8 @@ public class HttpClientGZIPTest extends AbstractHttpClientServerTest }); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .send(); + .scheme(scenario.getScheme()) + .send(); assertEquals(200, response.getStatus()); assertArrayEquals(data, response.getContent()); @@ -204,12 +206,11 @@ public class HttpClientGZIPTest extends AbstractHttpClientServerTest @ArgumentsSource(ScenarioProvider.class) public void testGZIPContentCorrupted(Scenario scenario) throws Exception { - start(scenario, new AbstractHandler() + start(scenario, new EmptyServerHandler() { @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + protected void service(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException { - baseRequest.setHandled(true); response.setHeader("Content-Encoding", "gzip"); // Not gzipped, will cause the client to blow up. response.getOutputStream().print("0123456789"); @@ -218,16 +219,58 @@ public class HttpClientGZIPTest extends AbstractHttpClientServerTest final CountDownLatch latch = new CountDownLatch(1); client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .send(result -> - { - if (result.isFailed()) - latch.countDown(); - }); + .scheme(scenario.getScheme()) + .send(result -> + { + if (result.isFailed()) + latch.countDown(); + }); assertTrue(latch.await(5, TimeUnit.SECONDS)); } + @ParameterizedTest + @ArgumentsSource(ScenarioProvider.class) + public void testLargeGZIPContentDoesNotPolluteByteBufferPool(Scenario scenario) throws Exception + { + String digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + Random random = new Random(); + byte[] content = new byte[1024 * 1024]; + for (int i = 0; i < content.length; ++i) + { + content[i] = (byte)digits.charAt(random.nextInt(digits.length())); + } + start(scenario, new EmptyServerHandler() + { + @Override + protected void service(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException + { + response.setContentType("text/plain;charset=" + StandardCharsets.US_ASCII.name()); + response.setHeader(HttpHeader.CONTENT_ENCODING.asString(), "gzip"); + GZIPOutputStream gzip = new GZIPOutputStream(response.getOutputStream()); + gzip.write(content); + gzip.finish(); + } + }); + + ByteBufferPool pool = client.getByteBufferPool(); + assumeTrue(pool instanceof MappedByteBufferPool); + MappedByteBufferPool bufferPool = (MappedByteBufferPool)pool; + + ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) + .scheme(scenario.getScheme()) + .timeout(5, TimeUnit.SECONDS) + .send(); + + assertEquals(HttpStatus.OK_200, response.getStatus()); + assertArrayEquals(content, response.getContent()); + + long directMemory = bufferPool.getMemory(true); + assertThat(directMemory, lessThan((long)content.length)); + long heapMemory = bufferPool.getMemory(false); + assertThat(heapMemory, lessThan((long)content.length)); + } + private static void sleep(long ms) throws IOException { try diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientProxyTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientProxyTest.java index 042ead500a9..605c4b7795e 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientProxyTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientProxyTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,14 +18,12 @@ package org.eclipse.jetty.client; -import static org.junit.jupiter.api.Assertions.assertEquals; - import java.io.IOException; import java.net.URI; import java.nio.charset.StandardCharsets; +import java.util.Base64; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -37,10 +35,11 @@ import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.server.handler.AbstractHandler; -import org.eclipse.jetty.util.B64Code; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsSource; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class HttpClientProxyTest extends AbstractHttpClientServerTest { @ParameterizedTest @@ -69,9 +68,9 @@ public class HttpClientProxyTest extends AbstractHttpClientServerTest client.getProxyConfiguration().getProxies().add(new HttpProxy("localhost", proxyPort)); ContentResponse response = client.newRequest(serverHost, serverPort) - .scheme(scenario.getScheme()) - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(status, response.getStatus()); } @@ -82,7 +81,7 @@ public class HttpClientProxyTest extends AbstractHttpClientServerTest { final String user = "foo"; final String password = "bar"; - final String credentials = B64Code.encode(user + ":" + password, StandardCharsets.ISO_8859_1); + final String credentials = Base64.getEncoder().encodeToString((user + ":" + password).getBytes(StandardCharsets.ISO_8859_1)); final String serverHost = "server"; final String realm = "test_realm"; final int status = HttpStatus.NO_CONTENT_204; @@ -117,9 +116,9 @@ public class HttpClientProxyTest extends AbstractHttpClientServerTest client.getProxyConfiguration().getProxies().add(new HttpProxy(proxyHost, proxyPort)); ContentResponse response1 = client.newRequest(serverHost, serverPort) - .scheme(scenario.getScheme()) - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .timeout(5, TimeUnit.SECONDS) + .send(); // No Authentication available => 407 assertEquals(HttpStatus.PROXY_AUTHENTICATION_REQUIRED_407, response1.getStatus()); @@ -138,9 +137,9 @@ public class HttpClientProxyTest extends AbstractHttpClientServerTest }); // ...and perform the request again => 407 + 204 ContentResponse response2 = client.newRequest(serverHost, serverPort) - .scheme(scenario.getScheme()) - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(status, response2.getStatus()); assertEquals(2, requests.get()); @@ -148,9 +147,9 @@ public class HttpClientProxyTest extends AbstractHttpClientServerTest // Now the authentication result is cached => 204 requests.set(0); ContentResponse response3 = client.newRequest(serverHost, serverPort) - .scheme(scenario.getScheme()) - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(status, response3.getStatus()); assertEquals(1, requests.get()); @@ -162,7 +161,7 @@ public class HttpClientProxyTest extends AbstractHttpClientServerTest { String user = "foo"; String password = "bar"; - String credentials = B64Code.encode(user + ":" + password, StandardCharsets.ISO_8859_1); + String credentials = Base64.getEncoder().encodeToString((user + ":" + password).getBytes(StandardCharsets.ISO_8859_1)); String proxyHost = "localhost"; String serverHost = "server"; int serverPort = HttpScheme.HTTP.is(scenario.getScheme()) ? 80 : 443; @@ -211,10 +210,10 @@ public class HttpClientProxyTest extends AbstractHttpClientServerTest client.getProxyConfiguration().getProxies().add(new HttpProxy(proxyHost, proxyPort)); ContentResponse response1 = client.newRequest(serverHost, serverPort) - .scheme(scenario.getScheme()) - .path("/proxy") - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .path("/proxy") + .timeout(5, TimeUnit.SECONDS) + .send(); // No Authentication available => 407. assertEquals(HttpStatus.PROXY_AUTHENTICATION_REQUIRED_407, response1.getStatus()); @@ -233,10 +232,10 @@ public class HttpClientProxyTest extends AbstractHttpClientServerTest }); // ...and perform the request again => 407 + 302 + 204. ContentResponse response2 = client.newRequest(serverHost, serverPort) - .scheme(scenario.getScheme()) - .path("/proxy") - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .path("/proxy") + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(status, response2.getStatus()); assertEquals(3, requests.get()); @@ -244,10 +243,10 @@ public class HttpClientProxyTest extends AbstractHttpClientServerTest // Now the authentication result is cached => 204. requests.set(0); ContentResponse response3 = client.newRequest(serverHost, serverPort) - .scheme(scenario.getScheme()) - .path("/server") - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .path("/server") + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(status, response3.getStatus()); assertEquals(1, requests.get()); @@ -308,22 +307,22 @@ public class HttpClientProxyTest extends AbstractHttpClientServerTest }); // Make a request, expect 407 + 401 + 204. ContentResponse response1 = client.newRequest(serverHost, serverPort) - .scheme(scenario.getScheme()) - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(status, response1.getStatus()); assertEquals(3, requests.get()); - // Make again the request, authentication is cached, expect 204. + // Make again the request, only the server authentication is cached, expect 407 + 204. requests.set(0); ContentResponse response2 = client.newRequest(serverHost, serverPort) - .scheme(scenario.getScheme()) - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(status, response2.getStatus()); - assertEquals(1, requests.get()); + assertEquals(2, requests.get()); } @ParameterizedTest @@ -379,10 +378,10 @@ public class HttpClientProxyTest extends AbstractHttpClientServerTest }); // Make a request, expect 407 + 204. ContentResponse response1 = client.newRequest(serverHost, serverPort) - .scheme(scenario.getScheme()) - .header(HttpHeader.AUTHORIZATION, "Basic foobar") - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .header(HttpHeader.AUTHORIZATION, "Basic foobar") + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(status, response1.getStatus()); assertEquals(2, requests.get()); @@ -390,10 +389,10 @@ public class HttpClientProxyTest extends AbstractHttpClientServerTest // Make again the request, authentication is cached, expect 204. requests.set(0); ContentResponse response2 = client.newRequest(serverHost, serverPort) - .scheme(scenario.getScheme()) - .header(HttpHeader.AUTHORIZATION, "Basic foobar") - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .header(HttpHeader.AUTHORIZATION, "Basic foobar") + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(status, response2.getStatus()); assertEquals(1, requests.get()); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientRedirectTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientRedirectTest.java index fbcac8d2d3a..6a6999d1282 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientRedirectTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientRedirectTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,14 +18,6 @@ package org.eclipse.jetty.client; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -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.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.IOException; import java.net.URLDecoder; import java.nio.ByteBuffer; @@ -34,8 +26,9 @@ import java.nio.charset.StandardCharsets; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; - +import java.util.concurrent.atomic.AtomicLong; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -48,13 +41,20 @@ import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.toolchain.test.IO; import org.hamcrest.Matchers; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsSource; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +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.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class HttpClientRedirectTest extends AbstractHttpClientServerTest { @ParameterizedTest @@ -64,10 +64,10 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest start(scenario, new RedirectHandler()); Response response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path("/303/localhost/done") - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .path("/303/localhost/done") + .timeout(5, TimeUnit.SECONDS) + .send(); assertNotNull(response); assertEquals(200, response.getStatus()); assertFalse(response.getHeaders().containsKey(HttpHeader.LOCATION.asString())); @@ -80,10 +80,10 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest start(scenario, new RedirectHandler()); Response response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path("/303/localhost/302/localhost/done") - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .path("/303/localhost/302/localhost/done") + .timeout(5, TimeUnit.SECONDS) + .send(); assertNotNull(response); assertEquals(200, response.getStatus()); assertFalse(response.getHeaders().containsKey(HttpHeader.LOCATION.asString())); @@ -96,10 +96,10 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest start(scenario, new RedirectHandler()); Response response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path("/303/127.0.0.1/302/localhost/done") - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .path("/303/127.0.0.1/302/localhost/done") + .timeout(5, TimeUnit.SECONDS) + .send(); assertNotNull(response); assertEquals(200, response.getStatus()); assertFalse(response.getHeaders().containsKey(HttpHeader.LOCATION.asString())); @@ -112,11 +112,11 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest start(scenario, new RedirectHandler()); Response response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .method(HttpMethod.HEAD) - .path("/301/localhost/done") - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .method(HttpMethod.HEAD) + .path("/301/localhost/done") + .timeout(5, TimeUnit.SECONDS) + .send(); assertNotNull(response); assertEquals(200, response.getStatus()); assertFalse(response.getHeaders().containsKey(HttpHeader.LOCATION.asString())); @@ -128,14 +128,13 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest { start(scenario, new RedirectHandler()); - ExecutionException x = assertThrows(ExecutionException.class, ()->{ + ExecutionException x = assertThrows(ExecutionException.class, () -> client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .method(HttpMethod.DELETE) - .path("/301/localhost/done") - .timeout(5, TimeUnit.SECONDS) - .send(); - }); + .scheme(scenario.getScheme()) + .method(HttpMethod.DELETE) + .path("/301/localhost/done") + .timeout(5, TimeUnit.SECONDS) + .send()); HttpResponseException xx = (HttpResponseException)x.getCause(); Response response = xx.getResponse(); assertNotNull(response); @@ -151,12 +150,12 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest byte[] data = new byte[]{0, 1, 2, 3, 4, 5, 6, 7}; ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .method(HttpMethod.POST) - .path("/307/localhost/done") - .content(new ByteBufferContentProvider(ByteBuffer.wrap(data))) - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .method(HttpMethod.POST) + .path("/307/localhost/done") + .content(new ByteBufferContentProvider(ByteBuffer.wrap(data))) + .timeout(5, TimeUnit.SECONDS) + .send(); assertNotNull(response); assertEquals(200, response.getStatus()); assertFalse(response.getHeaders().containsKey(HttpHeader.LOCATION.asString())); @@ -170,13 +169,12 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest start(scenario, new RedirectHandler()); client.setMaxRedirects(1); - ExecutionException x = assertThrows(ExecutionException.class, ()->{ + ExecutionException x = assertThrows(ExecutionException.class, () -> client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path("/303/localhost/302/localhost/done") - .timeout(5, TimeUnit.SECONDS) - .send(); - }); + .scheme(scenario.getScheme()) + .path("/303/localhost/302/localhost/done") + .timeout(5, TimeUnit.SECONDS) + .send()); HttpResponseException xx = (HttpResponseException)x.getCause(); Response response = xx.getResponse(); assertNotNull(response); @@ -191,10 +189,10 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest start(scenario, new RedirectHandler()); Response response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path("/303/localhost/done?close=true") - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .path("/303/localhost/done?close=true") + .timeout(5, TimeUnit.SECONDS) + .send(); assertNotNull(response); assertEquals(200, response.getStatus()); assertFalse(response.getHeaders().containsKey(HttpHeader.LOCATION.asString())); @@ -207,11 +205,11 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest start(scenario, new RedirectHandler()); Response response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .followRedirects(false) - .path("/303/localhost/done?close=true") - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .followRedirects(false) + .path("/303/localhost/done?close=true") + .timeout(5, TimeUnit.SECONDS) + .send(); assertNotNull(response); assertEquals(303, response.getStatus()); assertTrue(response.getHeaders().containsKey(HttpHeader.LOCATION.asString())); @@ -224,10 +222,10 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest start(scenario, new RedirectHandler()); Response response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path("/303/localhost/done?relative=true") - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .path("/303/localhost/done?relative=true") + .timeout(5, TimeUnit.SECONDS) + .send(); assertNotNull(response); assertEquals(200, response.getStatus()); assertFalse(response.getHeaders().containsKey(HttpHeader.LOCATION.asString())); @@ -240,10 +238,10 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest start(scenario, new RedirectHandler()); Response response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path("/303/localhost/a+space?decode=true") - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .path("/303/localhost/a+space?decode=true") + .timeout(5, TimeUnit.SECONDS) + .send(); assertNotNull(response); assertEquals(200, response.getStatus()); assertFalse(response.getHeaders().containsKey(HttpHeader.LOCATION.asString())); @@ -256,10 +254,10 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest start(scenario, new RedirectHandler()); Response response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path("/303/localhost/a+space?relative=true&decode=true") - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .path("/303/localhost/a+space?relative=true&decode=true") + .timeout(5, TimeUnit.SECONDS) + .send(); assertNotNull(response); assertEquals(200, response.getStatus()); assertFalse(response.getHeaders().containsKey(HttpHeader.LOCATION.asString())); @@ -269,12 +267,11 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest @ArgumentsSource(ScenarioProvider.class) public void testRedirectWithWrongScheme(Scenario scenario) throws Exception { - start(scenario, new AbstractHandler() + start(scenario, new EmptyServerHandler() { @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + protected void service(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) { - baseRequest.setHandled(true); response.setStatus(303); response.setHeader("Location", "ssh://localhost:" + connector.getLocalPort() + "/path"); } @@ -282,14 +279,14 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest final CountDownLatch latch = new CountDownLatch(1); client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path("/path") - .timeout(5, TimeUnit.SECONDS) - .send(result -> - { - assertTrue(result.isFailed()); - latch.countDown(); - }); + .scheme(scenario.getScheme()) + .path("/path") + .timeout(5, TimeUnit.SECONDS) + .send(result -> + { + assertTrue(result.isFailed()); + latch.countDown(); + }); assertTrue(latch.await(5, TimeUnit.SECONDS)); } @@ -304,10 +301,10 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest try { client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path("/303/doesNotExist/done") - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .path("/303/doesNotExist/done") + .timeout(5, TimeUnit.SECONDS) + .send(); } catch (ExecutionException x) { @@ -407,10 +404,10 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest final HttpRedirector redirector = new HttpRedirector(client); org.eclipse.jetty.client.api.Request request1 = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path("/303/localhost/302/localhost/done") - .timeout(5, TimeUnit.SECONDS) - .followRedirects(false); + .scheme(scenario.getScheme()) + .path("/303/localhost/302/localhost/done") + .timeout(5, TimeUnit.SECONDS) + .followRedirects(false); ContentResponse response1 = request1.send(); assertEquals(303, response1.getStatus()); @@ -439,12 +436,11 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest public void testRedirectWithCorruptedBody(Scenario scenario) throws Exception { byte[] bytes = "ok".getBytes(StandardCharsets.UTF_8); - start(scenario, new AbstractHandler() + start(scenario, new EmptyServerHandler() { @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + protected void service(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException { - baseRequest.setHandled(true); if (target.startsWith("/redirect")) { response.setStatus(HttpStatus.SEE_OTHER_303); @@ -462,15 +458,69 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest }); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path("/redirect") - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .path("/redirect") + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(200, response.getStatus()); assertArrayEquals(bytes, response.getContent()); } + @ParameterizedTest + @ArgumentsSource(ScenarioProvider.class) + public void testRedirectToSameURL(Scenario scenario) throws Exception + { + start(scenario, new EmptyServerHandler() + { + @Override + protected void service(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) + { + response.setStatus(HttpStatus.SEE_OTHER_303); + response.setHeader(HttpHeader.LOCATION.asString(), request.getRequestURI()); + } + }); + + ExecutionException x = assertThrows(ExecutionException.class, () -> + client.newRequest("localhost", connector.getLocalPort()) + .scheme(scenario.getScheme()) + .send()); + assertThat(x.getCause(), Matchers.instanceOf(HttpResponseException.class)); + } + + @ParameterizedTest + @ArgumentsSource(ScenarioProvider.class) + public void testInfiniteRedirectLoopMustTimeout(Scenario scenario) throws Exception + { + AtomicLong counter = new AtomicLong(); + start(scenario, new EmptyServerHandler() + { + @Override + protected void service(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) + { + try + { + Thread.sleep(200); + response.setStatus(HttpStatus.SEE_OTHER_303); + response.setHeader(HttpHeader.LOCATION.asString(), "/" + counter.getAndIncrement()); + } + catch (InterruptedException x) + { + throw new RuntimeException(x); + } + } + }); + + assertThrows(TimeoutException.class, () -> + { + client.setMaxRedirects(-1); + client.newRequest("localhost", connector.getLocalPort()) + .scheme(scenario.getScheme()) + .timeout(1, TimeUnit.SECONDS) + .send(); + }); + } + private void testSameMethodRedirect(final Scenario scenario, final HttpMethod method, int redirectCode) throws Exception { testMethodRedirect(scenario, method, method, redirectCode); @@ -510,19 +560,19 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest }); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .method(requestMethod) - .path("/" + redirectCode + "/localhost/done") - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .method(requestMethod) + .path("/" + redirectCode + "/localhost/done") + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(200, response.getStatus()); } - private class RedirectHandler extends AbstractHandler + private class RedirectHandler extends EmptyServerHandler { @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + protected void service(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { try { @@ -551,10 +601,6 @@ public class HttpClientRedirectTest extends AbstractHttpClientServerTest // Echo content back IO.copy(request.getInputStream(), response.getOutputStream()); } - finally - { - baseRequest.setHandled(true); - } } } } diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientSynchronizationTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientSynchronizationTest.java index 2aafbe1b783..a0d8d24f267 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientSynchronizationTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientSynchronizationTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,10 +18,6 @@ package org.eclipse.jetty.client; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.net.ConnectException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -33,6 +29,10 @@ import org.hamcrest.Matchers; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsSource; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + /** * Verifies that synchronization performed from outside HttpClient does not cause deadlocks */ @@ -51,7 +51,7 @@ public class HttpClientSynchronizationTest extends AbstractHttpClientServerTest for (int i = 0; i < count; ++i) { Request request = client.newRequest("localhost", port) - .scheme(scenario.getScheme()); + .scheme(scenario.getScheme()); synchronized (this) { @@ -84,7 +84,7 @@ public class HttpClientSynchronizationTest extends AbstractHttpClientServerTest for (int i = 0; i < count; ++i) { Request request = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()); + .scheme(scenario.getScheme()); synchronized (this) { diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTLSTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTLSTest.java index 076d923a816..b256901e143 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTLSTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTLSTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,15 +18,6 @@ package org.eclipse.jetty.client; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.instanceOf; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assumptions.assumeTrue; - import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.OutputStream; @@ -39,8 +30,8 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; - import javax.net.ssl.SSLException; +import javax.net.ssl.SSLPeerUnverifiedException; import javax.net.ssl.SSLSocket; import org.eclipse.jetty.client.api.ContentResponse; @@ -53,23 +44,31 @@ import org.eclipse.jetty.io.ssl.SslHandshakeListener; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.util.JavaVersion; +import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.thread.ExecutorThreadPool; import org.eclipse.jetty.util.thread.QueuedThreadPool; -import org.hamcrest.Matchers; import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.DisabledOnJre; +import org.junit.jupiter.api.condition.EnabledOnJre; import org.junit.jupiter.api.condition.JRE; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.instanceOf; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class HttpClientTLSTest { private Server server; private ServerConnector connector; private HttpClient client; + private SSLSocket sslSocket; + private void startServer(SslContextFactory sslContextFactory, Handler handler) throws Exception { ExecutorThreadPool serverThreads = new ExecutorThreadPool(); @@ -92,13 +91,25 @@ public class HttpClientTLSTest client.start(); } - private SslContextFactory createSslContextFactory() + private SslContextFactory.Server createServerSslContextFactory() + { + SslContextFactory.Server sslContextFactory = new SslContextFactory.Server(); + configureSslContextFactory(sslContextFactory); + return sslContextFactory; + } + + private SslContextFactory.Client createClientSslContextFactory() + { + SslContextFactory.Client sslContextFactory = new SslContextFactory.Client(); + configureSslContextFactory(sslContextFactory); + sslContextFactory.setEndpointIdentificationAlgorithm(null); + return sslContextFactory; + } + + private void configureSslContextFactory(SslContextFactory sslContextFactory) { - SslContextFactory sslContextFactory = new SslContextFactory(); - sslContextFactory.setEndpointIdentificationAlgorithm(""); sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks"); sslContextFactory.setKeyStorePassword("storepwd"); - return sslContextFactory; } @AfterEach @@ -113,8 +124,8 @@ public class HttpClientTLSTest @Test public void testNoCommonTLSProtocol() throws Exception { - SslContextFactory serverTLSFactory = createSslContextFactory(); - serverTLSFactory.setIncludeProtocols("TLSv1.2"); + SslContextFactory serverTLSFactory = createServerSslContextFactory(); + serverTLSFactory.setIncludeProtocols("TLSv1.3"); startServer(serverTLSFactory, new EmptyServerHandler()); CountDownLatch serverLatch = new CountDownLatch(1); @@ -127,8 +138,8 @@ public class HttpClientTLSTest } }); - SslContextFactory clientTLSFactory = createSslContextFactory(); - clientTLSFactory.setIncludeProtocols("TLSv1.1"); + SslContextFactory clientTLSFactory = createClientSslContextFactory(); + clientTLSFactory.setIncludeProtocols("TLSv1.2"); startClient(clientTLSFactory); CountDownLatch clientLatch = new CountDownLatch(1); @@ -141,12 +152,11 @@ public class HttpClientTLSTest } }); - assertThrows(ExecutionException.class, ()->{ + assertThrows(ExecutionException.class, () -> client.newRequest("localhost", connector.getLocalPort()) - .scheme(HttpScheme.HTTPS.asString()) - .timeout(5, TimeUnit.SECONDS) - .send(); - }); + .scheme(HttpScheme.HTTPS.asString()) + .timeout(5, TimeUnit.SECONDS) + .send()); assertTrue(serverLatch.await(1, TimeUnit.SECONDS)); assertTrue(clientLatch.await(1, TimeUnit.SECONDS)); @@ -155,7 +165,7 @@ public class HttpClientTLSTest @Test public void testNoCommonTLSCiphers() throws Exception { - SslContextFactory serverTLSFactory = createSslContextFactory(); + SslContextFactory serverTLSFactory = createServerSslContextFactory(); serverTLSFactory.setIncludeCipherSuites("TLS_RSA_WITH_AES_128_CBC_SHA"); startServer(serverTLSFactory, new EmptyServerHandler()); @@ -169,7 +179,7 @@ public class HttpClientTLSTest } }); - SslContextFactory clientTLSFactory = createSslContextFactory(); + SslContextFactory clientTLSFactory = createClientSslContextFactory(); clientTLSFactory.setExcludeCipherSuites(".*_SHA$"); startClient(clientTLSFactory); @@ -183,12 +193,11 @@ public class HttpClientTLSTest } }); - assertThrows(ExecutionException.class, ()->{ + assertThrows(ExecutionException.class, () -> client.newRequest("localhost", connector.getLocalPort()) - .scheme(HttpScheme.HTTPS.asString()) - .timeout(5, TimeUnit.SECONDS) - .send(); - }); + .scheme(HttpScheme.HTTPS.asString()) + .timeout(5, TimeUnit.SECONDS) + .send()); assertTrue(serverLatch.await(1, TimeUnit.SECONDS)); assertTrue(clientLatch.await(1, TimeUnit.SECONDS)); @@ -197,7 +206,7 @@ public class HttpClientTLSTest @Test public void testMismatchBetweenTLSProtocolAndTLSCiphersOnServer() throws Exception { - SslContextFactory serverTLSFactory = createSslContextFactory(); + SslContextFactory serverTLSFactory = createServerSslContextFactory(); // TLS 1.1 protocol, but only TLS 1.2 ciphers. serverTLSFactory.setIncludeProtocols("TLSv1.1"); serverTLSFactory.setIncludeCipherSuites("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"); @@ -213,7 +222,7 @@ public class HttpClientTLSTest } }); - SslContextFactory clientTLSFactory = createSslContextFactory(); + SslContextFactory clientTLSFactory = createClientSslContextFactory(); startClient(clientTLSFactory); CountDownLatch clientLatch = new CountDownLatch(1); @@ -226,25 +235,23 @@ public class HttpClientTLSTest } }); - assertThrows(ExecutionException.class, ()->{ + assertThrows(ExecutionException.class, () -> client.newRequest("localhost", connector.getLocalPort()) - .scheme(HttpScheme.HTTPS.asString()) - .timeout(5, TimeUnit.SECONDS) - .send(); - }); + .scheme(HttpScheme.HTTPS.asString()) + .timeout(5, TimeUnit.SECONDS) + .send()); assertTrue(serverLatch.await(1, TimeUnit.SECONDS)); assertTrue(clientLatch.await(1, TimeUnit.SECONDS)); } - // In JDK 11, a mismatch on the client does not generate any bytes towards - // the server, while in TLS 1.2 the client sends to the server the close_notify. - @DisabledOnJre( JRE.JAVA_11 ) + // In JDK 11+, a mismatch on the client does not generate any bytes towards + // the server, while in previous JDKs the client sends to the server the close_notify. + @EnabledOnJre({JRE.JAVA_8, JRE.JAVA_9, JRE.JAVA_10}) @Test public void testMismatchBetweenTLSProtocolAndTLSCiphersOnClient() throws Exception { - - SslContextFactory serverTLSFactory = createSslContextFactory(); + SslContextFactory serverTLSFactory = createServerSslContextFactory(); startServer(serverTLSFactory, new EmptyServerHandler()); CountDownLatch serverLatch = new CountDownLatch(1); @@ -257,7 +264,7 @@ public class HttpClientTLSTest } }); - SslContextFactory clientTLSFactory = createSslContextFactory(); + SslContextFactory clientTLSFactory = createClientSslContextFactory(); // TLS 1.1 protocol, but only TLS 1.2 ciphers. clientTLSFactory.setIncludeProtocols("TLSv1.1"); clientTLSFactory.setIncludeCipherSuites("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"); @@ -273,12 +280,11 @@ public class HttpClientTLSTest } }); - assertThrows(ExecutionException.class, ()->{ + assertThrows(ExecutionException.class, () -> client.newRequest("localhost", connector.getLocalPort()) - .scheme(HttpScheme.HTTPS.asString()) - .timeout(5, TimeUnit.SECONDS) - .send(); - }); + .scheme(HttpScheme.HTTPS.asString()) + .timeout(5, TimeUnit.SECONDS) + .send()); assertTrue(serverLatch.await(1, TimeUnit.SECONDS)); assertTrue(clientLatch.await(1, TimeUnit.SECONDS)); @@ -287,7 +293,7 @@ public class HttpClientTLSTest @Test public void testHandshakeSucceeded() throws Exception { - SslContextFactory serverTLSFactory = createSslContextFactory(); + SslContextFactory serverTLSFactory = createServerSslContextFactory(); startServer(serverTLSFactory, new EmptyServerHandler()); CountDownLatch serverLatch = new CountDownLatch(1); @@ -300,7 +306,7 @@ public class HttpClientTLSTest } }); - SslContextFactory clientTLSFactory = createSslContextFactory(); + SslContextFactory clientTLSFactory = createClientSslContextFactory(); startClient(clientTLSFactory); CountDownLatch clientLatch = new CountDownLatch(1); @@ -320,13 +326,13 @@ public class HttpClientTLSTest assertTrue(clientLatch.await(1, TimeUnit.SECONDS)); } - // Excluded because of a bug in JDK 11+27 where session resumption does not work. - @DisabledOnJre( JRE.JAVA_11 ) + // Excluded in JDK 11+ because resumed sessions cannot be compared + // using their session IDs even though they are resumed correctly. + @EnabledOnJre({JRE.JAVA_8, JRE.JAVA_9, JRE.JAVA_10}) @Test public void testHandshakeSucceededWithSessionResumption() throws Exception { - - SslContextFactory serverTLSFactory = createSslContextFactory(); + SslContextFactory serverTLSFactory = createServerSslContextFactory(); startServer(serverTLSFactory, new EmptyServerHandler()); AtomicReference serverSession = new AtomicReference<>(); @@ -339,7 +345,7 @@ public class HttpClientTLSTest } }); - SslContextFactory clientTLSFactory = createSslContextFactory(); + SslContextFactory clientTLSFactory = createClientSslContextFactory(); startClient(clientTLSFactory); AtomicReference clientSession = new AtomicReference<>(); @@ -354,10 +360,10 @@ public class HttpClientTLSTest // First request primes the TLS session. ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(HttpScheme.HTTPS.asString()) - .header(HttpHeader.CONNECTION, "close") - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(HttpScheme.HTTPS.asString()) + .header(HttpHeader.CONNECTION, "close") + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(HttpStatus.OK_200, response.getStatus()); assertNotNull(serverSession.get()); @@ -390,32 +396,32 @@ public class HttpClientTLSTest // Second request should have the same session ID. response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(HttpScheme.HTTPS.asString()) - .header(HttpHeader.CONNECTION, "close") - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(HttpScheme.HTTPS.asString()) + .header(HttpHeader.CONNECTION, "close") + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(HttpStatus.OK_200, response.getStatus()); assertTrue(serverLatch.await(1, TimeUnit.SECONDS)); assertTrue(clientLatch.await(1, TimeUnit.SECONDS)); } - // Excluded because of a bug in JDK 11+27 where session resumption does not work. - @DisabledOnJre( JRE.JAVA_11 ) + // Excluded in JDK 11+ because resumed sessions cannot be compared + // using their session IDs even though they are resumed correctly. + @EnabledOnJre({JRE.JAVA_8, JRE.JAVA_9, JRE.JAVA_10}) @Test public void testClientRawCloseDoesNotInvalidateSession() throws Exception { - - SslContextFactory serverTLSFactory = createSslContextFactory(); + SslContextFactory serverTLSFactory = createServerSslContextFactory(); startServer(serverTLSFactory, new EmptyServerHandler()); - SslContextFactory clientTLSFactory = createSslContextFactory(); + SslContextFactory clientTLSFactory = createClientSslContextFactory(); clientTLSFactory.start(); String host = "localhost"; int port = connector.getLocalPort(); Socket socket = new Socket(host, port); - SSLSocket sslSocket = (SSLSocket)clientTLSFactory.getSslContext().getSocketFactory().createSocket(socket, host, port, true); + sslSocket = (SSLSocket)clientTLSFactory.getSslContext().getSocketFactory().createSocket(socket, host, port, true); CountDownLatch handshakeLatch1 = new CountDownLatch(1); AtomicReference session1 = new AtomicReference<>(); sslSocket.addHandshakeCompletedListener(event -> @@ -428,14 +434,12 @@ public class HttpClientTLSTest // In TLS 1.3 the server sends a NewSessionTicket post-handshake message // to enable session resumption and without a read, the message is not processed. - try + + assertThrows(SocketTimeoutException.class, () -> { sslSocket.setSoTimeout(1000); sslSocket.getInputStream().read(); - } - catch (SocketTimeoutException expected) - { - } + }); // The client closes abruptly. socket.close(); @@ -461,13 +465,13 @@ public class HttpClientTLSTest @Test public void testServerRawCloseDetectedByClient() throws Exception { - SslContextFactory serverTLSFactory = createSslContextFactory(); + SslContextFactory serverTLSFactory = createServerSslContextFactory(); serverTLSFactory.start(); try (ServerSocket server = new ServerSocket(0)) { QueuedThreadPool clientThreads = new QueuedThreadPool(); clientThreads.setName("client"); - client = new HttpClient(createSslContextFactory()) + client = new HttpClient(createClientSslContextFactory()) { @Override protected ClientConnectionFactory newSslClientConnectionFactory(ClientConnectionFactory connectionFactory) @@ -482,12 +486,12 @@ public class HttpClientTLSTest CountDownLatch latch = new CountDownLatch(1); client.newRequest("localhost", server.getLocalPort()) - .scheme(HttpScheme.HTTPS.asString()) - .send(result -> - { - assertThat(result.getResponseFailure(), instanceOf(SSLException.class)); - latch.countDown(); - }); + .scheme(HttpScheme.HTTPS.asString()) + .send(result -> + { + assertThat(result.getResponseFailure(), instanceOf(SSLException.class)); + latch.countDown(); + }); try (Socket socket = server.accept()) { @@ -497,7 +501,7 @@ public class HttpClientTLSTest while (true) { String line = reader.readLine(); - if (line == null || line.isEmpty()) + if (StringUtil.isEmpty(line)) break; } @@ -514,8 +518,8 @@ public class HttpClientTLSTest byte[] half = new byte[8]; String response = "HTTP/1.1 200 OK\r\n" + // "Content-Length: " + (half.length * 2) + "\r\n" + - "Connection: close\r\n" + - "\r\n"; + "Connection: close\r\n" + + "\r\n"; OutputStream output = sslSocket.getOutputStream(); output.write(response.getBytes(StandardCharsets.UTF_8)); output.write(half); @@ -527,4 +531,30 @@ public class HttpClientTLSTest assertTrue(latch.await(5, TimeUnit.SECONDS)); } } + + @Test + public void testHostNameVerificationFailure() throws Exception + { + SslContextFactory serverTLSFactory = createServerSslContextFactory(); + startServer(serverTLSFactory, new EmptyServerHandler()); + + SslContextFactory clientTLSFactory = createClientSslContextFactory(); + // Make sure the host name is not verified at the TLS level. + clientTLSFactory.setEndpointIdentificationAlgorithm(null); + // Add host name verification after the TLS handshake. + clientTLSFactory.setHostnameVerifier((host, session) -> false); + startClient(clientTLSFactory); + + CountDownLatch latch = new CountDownLatch(1); + client.newRequest("localhost", connector.getLocalPort()) + .scheme(HttpScheme.HTTPS.asString()) + .send(result -> + { + Throwable failure = result.getFailure(); + if (failure instanceof SSLPeerUnverifiedException) + latch.countDown(); + }); + + assertTrue(latch.await(5, TimeUnit.SECONDS)); + } } diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java index 9afbf8c32fa..a8d9fa48409 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,16 +18,6 @@ package org.eclipse.jetty.client; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.instanceOf; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -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.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -60,7 +50,6 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; - import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; @@ -91,6 +80,7 @@ import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.io.AbstractConnection; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.toolchain.test.Net; import org.eclipse.jetty.toolchain.test.jupiter.WorkDir; import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension; import org.eclipse.jetty.util.Callback; @@ -106,6 +96,16 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsSource; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.instanceOf; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +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.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + @ExtendWith(WorkDirExtension.class) public class HttpClientTest extends AbstractHttpClientServerTest { @@ -250,7 +250,9 @@ public class HttpClientTest extends AbstractHttpClientServerTest ServletOutputStream output = response.getOutputStream(); String[] paramValues1 = request.getParameterValues(paramName1); for (String paramValue : paramValues1) + { output.write(paramValue.getBytes(StandardCharsets.UTF_8)); + } String paramValue2 = request.getParameter(paramName2); output.write(paramValue2.getBytes(StandardCharsets.UTF_8)); baseRequest.setHandled(true); @@ -295,9 +297,9 @@ public class HttpClientTest extends AbstractHttpClientServerTest }); ContentResponse response = client.POST(scenario.getScheme() + "://localhost:" + connector.getLocalPort()) - .param(paramName, paramValue) - .timeout(5, TimeUnit.SECONDS) - .send(); + .param(paramName, paramValue) + .timeout(5, TimeUnit.SECONDS) + .send(); assertNotNull(response); assertEquals(200, response.getStatus()); @@ -329,9 +331,9 @@ public class HttpClientTest extends AbstractHttpClientServerTest URI uri = URI.create(scenario.getScheme() + "://localhost:" + connector.getLocalPort() + "/path?" + paramName + "=" + encodedParamValue); ContentResponse response = client.newRequest(uri) - .method(HttpMethod.PUT) - .timeout(5, TimeUnit.SECONDS) - .send(); + .method(HttpMethod.PUT) + .timeout(5, TimeUnit.SECONDS) + .send(); assertNotNull(response); assertEquals(200, response.getStatus()); @@ -363,10 +365,10 @@ public class HttpClientTest extends AbstractHttpClientServerTest }); ContentResponse response = client.POST(scenario.getScheme() + "://localhost:" + connector.getLocalPort() + "/?b=1") - .param(paramName, paramValue) - .content(new BytesContentProvider(content)) - .timeout(5, TimeUnit.SECONDS) - .send(); + .param(paramName, paramValue) + .content(new BytesContentProvider(content)) + .timeout(5, TimeUnit.SECONDS) + .send(); assertNotNull(response); assertEquals(200, response.getStatus()); @@ -389,16 +391,16 @@ public class HttpClientTest extends AbstractHttpClientServerTest final byte[] content = {0, 1, 2, 3}; ContentResponse response = client.POST(scenario.getScheme() + "://localhost:" + connector.getLocalPort()) - .onRequestContent((request, buffer) -> - { - byte[] bytes = new byte[buffer.remaining()]; - buffer.get(bytes); - if (!Arrays.equals(content, bytes)) - request.abort(new Exception()); - }) - .content(new BytesContentProvider(content)) - .timeout(5, TimeUnit.SECONDS) - .send(); + .onRequestContent((request, buffer) -> + { + byte[] bytes = new byte[buffer.remaining()]; + buffer.get(bytes); + if (!Arrays.equals(content, bytes)) + request.abort(new Exception()); + }) + .content(new BytesContentProvider(content)) + .timeout(5, TimeUnit.SECONDS) + .send(); assertNotNull(response); assertEquals(200, response.getStatus()); @@ -420,16 +422,18 @@ public class HttpClientTest extends AbstractHttpClientServerTest final AtomicInteger progress = new AtomicInteger(); ContentResponse response = client.POST(scenario.getScheme() + "://localhost:" + connector.getLocalPort()) - .onRequestContent((request, buffer) -> - { - byte[] bytes = new byte[buffer.remaining()]; - assertEquals(1, bytes.length); - buffer.get(bytes); - assertEquals(bytes[0], progress.getAndIncrement()); - }) - .content(new BytesContentProvider(new byte[]{0}, new byte[]{1}, new byte[]{2}, new byte[]{3}, new byte[]{4})) - .timeout(5, TimeUnit.SECONDS) - .send(); + .onRequestContent((request, buffer) -> + { + byte[] bytes = new byte[buffer.remaining()]; + assertEquals(1, bytes.length); + buffer.get(bytes); + assertEquals(bytes[0], progress.getAndIncrement()); + }) + .content(new BytesContentProvider(new byte[]{0}, new byte[]{1}, new byte[]{ + 2 + }, new byte[]{3}, new byte[]{4})) + .timeout(5, TimeUnit.SECONDS) + .send(); assertNotNull(response); assertEquals(200, response.getStatus()); @@ -447,40 +451,40 @@ public class HttpClientTest extends AbstractHttpClientServerTest final CountDownLatch latch = new CountDownLatch(1); final CountDownLatch successLatch = new CountDownLatch(2); client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .onRequestBegin(request -> + .scheme(scenario.getScheme()) + .onRequestBegin(request -> + { + try { - try - { - latch.await(); - } - catch (InterruptedException x) - { - x.printStackTrace(); - } - }) - .send(new Response.Listener.Adapter() + latch.await(); + } + catch (InterruptedException x) { - @Override - public void onSuccess(Response response) - { - assertEquals(200, response.getStatus()); - successLatch.countDown(); - } - }); + x.printStackTrace(); + } + }) + .send(new Response.Listener.Adapter() + { + @Override + public void onSuccess(Response response) + { + assertEquals(200, response.getStatus()); + successLatch.countDown(); + } + }); client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .onRequestQueued(request -> latch.countDown()) - .send(new Response.Listener.Adapter() + .scheme(scenario.getScheme()) + .onRequestQueued(request -> latch.countDown()) + .send(new Response.Listener.Adapter() + { + @Override + public void onSuccess(Response response) { - @Override - public void onSuccess(Response response) - { - assertEquals(200, response.getStatus()); - successLatch.countDown(); - } - }); + assertEquals(200, response.getStatus()); + successLatch.countDown(); + } + }); assertTrue(successLatch.await(5, TimeUnit.SECONDS)); } @@ -507,20 +511,20 @@ public class HttpClientTest extends AbstractHttpClientServerTest { final CountDownLatch latch = new CountDownLatch(2); client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path("/one") - .onResponseFailure((response, failure) -> latch.countDown()) - .send(null); + .scheme(scenario.getScheme()) + .path("/one") + .onResponseFailure((response, failure) -> latch.countDown()) + .send(null); client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path("/two") - .onResponseSuccess(response -> - { - assertEquals(200, response.getStatus()); - latch.countDown(); - }) - .send(null); + .scheme(scenario.getScheme()) + .path("/two") + .onResponseSuccess(response -> + { + assertEquals(200, response.getStatus()); + latch.countDown(); + }) + .send(null); assertTrue(latch.await(5, TimeUnit.SECONDS)); } @@ -530,7 +534,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest @ArgumentsSource(ScenarioProvider.class) public void test_ExchangeIsComplete_OnlyWhenBothRequestAndResponseAreComplete(Scenario scenario) throws Exception { - start(scenario,new AbstractHandler.ErrorDispatchHandler() + start(scenario, new AbstractHandler.ErrorDispatchHandler() { @Override protected void doNonErrorHandle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException @@ -542,7 +546,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest byte[] buffer = new byte[1024]; InputStream in = request.getInputStream(); - while(true) + while (true) { int read = in.read(buffer); if (read < 0) @@ -559,7 +563,9 @@ public class HttpClientTest extends AbstractHttpClientServerTest { byte[] kb = new byte[1024]; for (int i = 0; i < 10 * 1024; ++i) + { output.write(kb); + } } final CountDownLatch latch = new CountDownLatch(3); @@ -570,10 +576,10 @@ public class HttpClientTest extends AbstractHttpClientServerTest .scheme(scenario.getScheme()) .file(file) .onRequestSuccess(request -> - { - requestTime.set(System.nanoTime()); - latch.countDown(); - }) + { + requestTime.set(System.nanoTime()); + latch.countDown(); + }) .send(new Response.Listener.Adapter() { @Override @@ -603,7 +609,6 @@ public class HttpClientTest extends AbstractHttpClientServerTest Files.delete(file); } - @ParameterizedTest @ArgumentsSource(ScenarioProvider.class) public void test_ExchangeIsComplete_WhenRequestFailsMidway_WithResponse(Scenario scenario) throws Exception @@ -620,49 +625,49 @@ public class HttpClientTest extends AbstractHttpClientServerTest final CountDownLatch latch = new CountDownLatch(1); client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - // The second ByteBuffer set to null will throw an exception - .content(new ContentProvider() + .scheme(scenario.getScheme()) + // The second ByteBuffer set to null will throw an exception + .content(new ContentProvider() + { + @Override + public long getLength() { - @Override - public long getLength() - { - return -1; - } + return -1; + } - @Override - public Iterator iterator() + @Override + public Iterator iterator() + { + return new Iterator() { - return new Iterator() + @Override + public boolean hasNext() { - @Override - public boolean hasNext() - { - return true; - } + return true; + } - @Override - public ByteBuffer next() - { - throw new NoSuchElementException("explicitly_thrown_by_test"); - } + @Override + public ByteBuffer next() + { + throw new NoSuchElementException("explicitly_thrown_by_test"); + } - @Override - public void remove() - { - throw new UnsupportedOperationException(); - } - }; - } - }) - .send(new Response.Listener.Adapter() + @Override + public void remove() + { + throw new UnsupportedOperationException(); + } + }; + } + }) + .send(new Response.Listener.Adapter() + { + @Override + public void onComplete(Result result) { - @Override - public void onComplete(Result result) - { - latch.countDown(); - } - }); + latch.countDown(); + } + }); assertTrue(latch.await(5, TimeUnit.SECONDS)); } @@ -677,21 +682,21 @@ public class HttpClientTest extends AbstractHttpClientServerTest final String host = "localhost"; final int port = connector.getLocalPort(); client.newRequest(host, port) - .scheme(scenario.getScheme()) - .onRequestBegin(request -> + .scheme(scenario.getScheme()) + .onRequestBegin(request -> + { + HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scenario.getScheme(), host, port); + DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool(); + connectionPool.getActiveConnections().iterator().next().close(); + }) + .send(new Response.Listener.Adapter() + { + @Override + public void onComplete(Result result) { - HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scenario.getScheme(), host, port); - DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool(); - connectionPool.getActiveConnections().iterator().next().close(); - }) - .send(new Response.Listener.Adapter() - { - @Override - public void onComplete(Result result) - { - latch.countDown(); - } - }); + latch.countDown(); + } + }); assertTrue(latch.await(5, TimeUnit.SECONDS)); } @@ -721,19 +726,20 @@ public class HttpClientTest extends AbstractHttpClientServerTest final String host = "localhost"; final int port = connector.getLocalPort(); - assertThrows(TimeoutException.class, ()->{ + assertThrows(TimeoutException.class, () -> + { client.newRequest(host, port) - .scheme(scenario.getScheme()) - .idleTimeout(idleTimeout, TimeUnit.MILLISECONDS) - .timeout(3 * idleTimeout, TimeUnit.MILLISECONDS) - .send(); + .scheme(scenario.getScheme()) + .idleTimeout(idleTimeout, TimeUnit.MILLISECONDS) + .timeout(3 * idleTimeout, TimeUnit.MILLISECONDS) + .send(); }); // Make another request without specifying the idle timeout, should not fail ContentResponse response = client.newRequest(host, port) - .scheme(scenario.getScheme()) - .timeout(3 * idleTimeout, TimeUnit.MILLISECONDS) - .send(); + .scheme(scenario.getScheme()) + .timeout(3 * idleTimeout, TimeUnit.MILLISECONDS) + .send(); assertNotNull(response); assertEquals(200, response.getStatus()); @@ -743,12 +749,13 @@ public class HttpClientTest extends AbstractHttpClientServerTest @ArgumentsSource(ScenarioProvider.class) public void testSendToIPv6Address(Scenario scenario) throws Exception { + Assumptions.assumeTrue(Net.isIpv6InterfaceAvailable()); start(scenario, new EmptyServerHandler()); ContentResponse response = client.newRequest("[::1]", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .timeout(5, TimeUnit.SECONDS) + .send(); assertNotNull(response); assertEquals(200, response.getStatus()); @@ -770,10 +777,10 @@ public class HttpClientTest extends AbstractHttpClientServerTest }); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .onResponseHeader((response1, field) -> !field.getName().equals(headerName)) - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .onResponseHeader((response1, field) -> !field.getName().equals(headerName)) + .timeout(5, TimeUnit.SECONDS) + .send(); assertNotNull(response); assertEquals(200, response.getStatus()); @@ -791,22 +798,22 @@ public class HttpClientTest extends AbstractHttpClientServerTest for (int i = 0; i < count; ++i) { client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .send(new Response.Listener.Adapter() + .scheme(scenario.getScheme()) + .send(new Response.Listener.Adapter() + { + @Override + public boolean onHeader(Response response, HttpField field) { - @Override - public boolean onHeader(Response response, HttpField field) - { - return false; - } + return false; + } - @Override - public void onComplete(Result result) - { - if (result.isSucceeded()) - latch.countDown(); - } - }); + @Override + public void onComplete(Result result) + { + if (result.isSucceeded()) + latch.countDown(); + } + }); } assertTrue(latch.await(10, TimeUnit.SECONDS)); @@ -830,10 +837,10 @@ public class HttpClientTest extends AbstractHttpClientServerTest // HEAD requests receive a Content-Length header, but do not // receive the content so they must handle this case properly ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .method(HttpMethod.HEAD) - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .method(HttpMethod.HEAD) + .timeout(5, TimeUnit.SECONDS) + .send(); assertNotNull(response); assertEquals(200, response.getStatus()); @@ -841,9 +848,9 @@ public class HttpClientTest extends AbstractHttpClientServerTest // Perform a normal GET request to be sure the content is now read response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .timeout(5, TimeUnit.SECONDS) + .send(); assertNotNull(response); assertEquals(200, response.getStatus()); @@ -857,7 +864,8 @@ public class HttpClientTest extends AbstractHttpClientServerTest String host = "idontexist"; int port = 80; - assertThrows(IOException.class, ()->{ + assertThrows(IOException.class, () -> + { Socket socket = new Socket(); socket.connect(new InetSocketAddress(host, port), 1000); }, "Host must not be resolvable"); @@ -866,13 +874,13 @@ public class HttpClientTest extends AbstractHttpClientServerTest final CountDownLatch latch = new CountDownLatch(1); client.newRequest(host, port) - .send(result -> - { - assertTrue(result.isFailed()); - Throwable failure = result.getFailure(); - assertTrue(failure instanceof UnknownHostException); - latch.countDown(); - }); + .send(result -> + { + assertTrue(result.isFailed()); + Throwable failure = result.getFailure(); + assertTrue(failure instanceof UnknownHostException); + latch.countDown(); + }); assertTrue(latch.await(10, TimeUnit.SECONDS)); } @@ -880,38 +888,40 @@ public class HttpClientTest extends AbstractHttpClientServerTest @ArgumentsSource(ScenarioProvider.class) public void testConnectHostWithMultipleAddresses(Scenario scenario) throws Exception { - start(scenario, new EmptyServerHandler()); - - client.setSocketAddressResolver(new SocketAddressResolver.Async(client.getExecutor(), client.getScheduler(), client.getConnectTimeout()) + startServer(scenario, new EmptyServerHandler()); + startClient(scenario, null, client -> { - @Override - public void resolve(String host, int port, Promise> promise) + client.setSocketAddressResolver(new SocketAddressResolver.Async(client.getExecutor(), client.getScheduler(), 5000) { - super.resolve(host, port, new Promise>() + @Override + public void resolve(String host, int port, Promise> promise) { - @Override - public void succeeded(List result) + super.resolve(host, port, new Promise>() { - // Add as first address an invalid address so that we test - // that the connect operation iterates over the addresses. - result.add(0, new InetSocketAddress("idontexist", port)); - promise.succeeded(result); - } + @Override + public void succeeded(List result) + { + // Add as first address an invalid address so that we test + // that the connect operation iterates over the addresses. + result.add(0, new InetSocketAddress("idontexist", port)); + promise.succeeded(result); + } - @Override - public void failed(Throwable x) - { - promise.failed(x); - } - }); - } + @Override + public void failed(Throwable x) + { + promise.failed(x); + } + }); + } + }); }); // If no exceptions the test passes. client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .header(HttpHeader.CONNECTION, "close") - .send(); + .scheme(scenario.getScheme()) + .header(HttpHeader.CONNECTION, "close") + .send(); } @ParameterizedTest @@ -932,19 +942,19 @@ public class HttpClientTest extends AbstractHttpClientServerTest }); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .agent(userAgent) - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .agent(userAgent) + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(200, response.getStatus()); response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .header(HttpHeader.USER_AGENT, null) - .header(HttpHeader.USER_AGENT, userAgent) - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .header(HttpHeader.USER_AGENT, null) + .header(HttpHeader.USER_AGENT, userAgent) + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(200, response.getStatus()); } @@ -969,28 +979,28 @@ public class HttpClientTest extends AbstractHttpClientServerTest // User agent not specified, use default. ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path("/ua") - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .path("/ua") + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(200, response.getStatus()); // User agent explicitly removed. response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .agent(null) - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .agent(null) + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(200, response.getStatus()); // User agent explicitly removed. response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .header(HttpHeader.USER_AGENT, null) - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .header(HttpHeader.USER_AGENT, null) + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(200, response.getStatus()); } @@ -1049,16 +1059,16 @@ public class HttpClientTest extends AbstractHttpClientServerTest } }; ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .onRequestQueued(listener) - .onRequestBegin(listener) - .onRequestHeaders(listener) - .onRequestCommit(listener) - .onRequestContent(listener) - .onRequestSuccess(listener) - .onRequestFailure(listener) - .listener(listener) - .send(); + .scheme(scenario.getScheme()) + .onRequestQueued(listener) + .onRequestBegin(listener) + .onRequestHeaders(listener) + .onRequestCommit(listener) + .onRequestContent(listener) + .onRequestSuccess(listener) + .onRequestFailure(listener) + .listener(listener) + .send(); assertEquals(200, response.getStatus()); int expectedEventsTriggeredByOnRequestXXXListeners = 5; @@ -1132,15 +1142,15 @@ public class HttpClientTest extends AbstractHttpClientServerTest } }; client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .onResponseBegin(listener) - .onResponseHeader(listener) - .onResponseHeaders(listener) - .onResponseContent(listener) - .onResponseContentAsync(listener) - .onResponseSuccess(listener) - .onResponseFailure(listener) - .send(listener); + .scheme(scenario.getScheme()) + .onResponseBegin(listener) + .onResponseHeader(listener) + .onResponseHeaders(listener) + .onResponseContent(listener) + .onResponseContentAsync(listener) + .onResponseSuccess(listener) + .onResponseFailure(listener) + .send(listener); assertTrue(latch.await(5, TimeUnit.SECONDS)); int expectedEventsTriggeredByOnResponseXXXListeners = 3; @@ -1182,16 +1192,14 @@ public class HttpClientTest extends AbstractHttpClientServerTest } }; - client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .send(listener); + .scheme(scenario.getScheme()) + .send(listener); Response response = ex.exchange(null); assertEquals(200, response.getStatus()); assertArrayEquals(content, listener.getContent()); - } @ParameterizedTest @@ -1210,9 +1218,9 @@ public class HttpClientTest extends AbstractHttpClientServerTest }); ContentResponse response = client.newRequest("http://127.0.0.1:" + connector.getLocalPort() + "/path") - .scheme(scenario.getScheme()) - .header(HttpHeader.HOST, host) - .send(); + .scheme(scenario.getScheme()) + .header(HttpHeader.HOST, host) + .send(); assertEquals(200, response.getStatus()); } @@ -1235,11 +1243,11 @@ public class HttpClientTest extends AbstractHttpClientServerTest }); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .version(HttpVersion.HTTP_1_0) - .header(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE.asString()) - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .version(HttpVersion.HTTP_1_0) + .header(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE.asString()) + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(200, response.getStatus()); assertTrue(response.getHeaders().contains(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE.asString())); @@ -1267,10 +1275,10 @@ public class HttpClientTest extends AbstractHttpClientServerTest { long timeout = 5000; Request request = client.newRequest(destination.getHost(), destination.getPort()) - .scheme(destination.getScheme()) - .version(HttpVersion.HTTP_1_0) - .header(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE.asString()) - .timeout(timeout, TimeUnit.MILLISECONDS); + .scheme(destination.getScheme()) + .version(HttpVersion.HTTP_1_0) + .header(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE.asString()) + .timeout(timeout, TimeUnit.MILLISECONDS); FutureResponseListener listener = new FutureResponseListener(request); connection.send(request, listener); @@ -1292,11 +1300,11 @@ public class HttpClientTest extends AbstractHttpClientServerTest start(scenario, new EmptyServerHandler()); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .version(HttpVersion.HTTP_1_0) - .header(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE.asString()) - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .version(HttpVersion.HTTP_1_0) + .header(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE.asString()) + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(200, response.getStatus()); assertTrue(response.getHeaders().contains(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE.asString())); @@ -1320,12 +1328,12 @@ public class HttpClientTest extends AbstractHttpClientServerTest final CountDownLatch completeLatch = new CountDownLatch(1); client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .send(result -> - { - if (result.isFailed()) - completeLatch.countDown(); - }); + .scheme(scenario.getScheme()) + .send(result -> + { + if (result.isFailed()) + completeLatch.countDown(); + }); assertTrue(latch.await(5, TimeUnit.SECONDS)); @@ -1341,7 +1349,8 @@ public class HttpClientTest extends AbstractHttpClientServerTest { Assumptions.assumeTrue(HttpScheme.HTTP.is(scenario.getScheme())); - ExecutionException e = assertThrows(ExecutionException.class, ()->{ + ExecutionException e = assertThrows(ExecutionException.class, () -> + { testContentDelimitedByEOFWithSlowRequest(scenario, HttpVersion.HTTP_1_0, 1024); }); @@ -1353,7 +1362,8 @@ public class HttpClientTest extends AbstractHttpClientServerTest @ArgumentsSource(NonSslScenarioProvider.class) public void testBigContentDelimitedByEOFWithSlowRequestHTTP10(Scenario scenario) throws Exception { - ExecutionException e = assertThrows(ExecutionException.class, ()->{ + ExecutionException e = assertThrows(ExecutionException.class, () -> + { testContentDelimitedByEOFWithSlowRequest(scenario, HttpVersion.HTTP_1_0, 128 * 1024); }); @@ -1401,9 +1411,9 @@ public class HttpClientTest extends AbstractHttpClientServerTest DeferredContentProvider content = new DeferredContentProvider(ByteBuffer.wrap(new byte[]{0})); Request request = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .version(version) - .content(content); + .scheme(scenario.getScheme()) + .version(version) + .content(content); FutureResponseListener listener = new FutureResponseListener(request); request.send(listener); // Wait some time to simulate a slow request. @@ -1466,24 +1476,24 @@ public class HttpClientTest extends AbstractHttpClientServerTest final CountDownLatch contentLatch = new CountDownLatch(1); final CountDownLatch completeLatch = new CountDownLatch(1); client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .send(new Response.Listener.Adapter() + .scheme(scenario.getScheme()) + .send(new Response.Listener.Adapter() + { + @Override + public void onContent(Response response, ByteBuffer content, Callback callback) { - @Override - public void onContent(Response response, ByteBuffer content, Callback callback) - { - // Do not notify the callback yet. - callbackRef.set(callback); - contentLatch.countDown(); - } + // Do not notify the callback yet. + callbackRef.set(callback); + contentLatch.countDown(); + } - @Override - public void onComplete(Result result) - { - if (result.isSucceeded()) - completeLatch.countDown(); - } - }); + @Override + public void onComplete(Result result) + { + if (result.isSucceeded()) + completeLatch.countDown(); + } + }); assertTrue(contentLatch.await(5, TimeUnit.SECONDS)); @@ -1526,22 +1536,22 @@ public class HttpClientTest extends AbstractHttpClientServerTest } }; } - }, scenario.newSslContextFactory()); + }, scenario.newClientSslContextFactory()); client.start(); final CountDownLatch latch = new CountDownLatch(2); client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .onRequestBegin(request -> - { - assertTrue(open.get()); + .scheme(scenario.getScheme()) + .onRequestBegin(request -> + { + assertTrue(open.get()); + latch.countDown(); + }) + .send(result -> + { + if (result.isSucceeded()) latch.countDown(); - }) - .send(result -> - { - if (result.isSucceeded()) - latch.countDown(); - }); + }); assertTrue(latch.await(5, TimeUnit.SECONDS)); } @@ -1558,8 +1568,8 @@ public class HttpClientTest extends AbstractHttpClientServerTest int port = server.getLocalPort(); Request request = client.newRequest(host, port) - .method(HttpMethod.CONNECT) - .version(HttpVersion.HTTP_1_0); + .method(HttpMethod.CONNECT) + .version(HttpVersion.HTTP_1_0); FuturePromise promise = new FuturePromise<>(); client.getDestination("http", host, port).newConnection(promise); Connection connection = promise.get(5, TimeUnit.SECONDS); @@ -1572,8 +1582,8 @@ public class HttpClientTest extends AbstractHttpClientServerTest consume(input, false); // HTTP/1.0 response, the client must not close the connection. - String httpResponse = "" + - "HTTP/1.0 200 OK\r\n" + + String httpResponse = + "HTTP/1.0 200 OK\r\n" + "\r\n"; OutputStream output = socket.getOutputStream(); output.write(httpResponse.getBytes(StandardCharsets.UTF_8)); @@ -1594,8 +1604,8 @@ public class HttpClientTest extends AbstractHttpClientServerTest consume(input, false); - httpResponse = "" + - "HTTP/1.1 200 OK\r\n" + + httpResponse = + "HTTP/1.1 200 OK\r\n" + "Content-Length: 0\r\n" + "\r\n"; output.write(httpResponse.getBytes(StandardCharsets.UTF_8)); @@ -1610,6 +1620,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest @ArgumentsSource(ScenarioProvider.class) public void test_IPv6_Host(Scenario scenario) throws Exception { + Assumptions.assumeTrue(Net.isIpv6InterfaceAvailable()); start(scenario, new AbstractHandler() { @Override @@ -1629,7 +1640,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest assertNotNull(response); assertEquals(200, response.getStatus()); - assertThat(new String(response.getContent(), StandardCharsets.ISO_8859_1),Matchers.startsWith("[::1]:")); + assertThat(new String(response.getContent(), StandardCharsets.ISO_8859_1), Matchers.startsWith("[::1]:")); } @ParameterizedTest @@ -1639,46 +1650,46 @@ public class HttpClientTest extends AbstractHttpClientServerTest startClient(scenario); assertCopyRequest(client.newRequest("http://example.com/some/url") - .method(HttpMethod.HEAD) - .version(HttpVersion.HTTP_2) - .content(new StringContentProvider("some string")) - .timeout(321, TimeUnit.SECONDS) - .idleTimeout(2221, TimeUnit.SECONDS) - .followRedirects(true) - .header(HttpHeader.CONTENT_TYPE, "application/json") - .header("X-Some-Custom-Header", "some-value")); + .method(HttpMethod.HEAD) + .version(HttpVersion.HTTP_2) + .content(new StringContentProvider("some string")) + .timeout(321, TimeUnit.SECONDS) + .idleTimeout(2221, TimeUnit.SECONDS) + .followRedirects(true) + .header(HttpHeader.CONTENT_TYPE, "application/json") + .header("X-Some-Custom-Header", "some-value")); assertCopyRequest(client.newRequest("https://example.com") - .method(HttpMethod.POST) - .version(HttpVersion.HTTP_1_0) - .content(new StringContentProvider("some other string")) - .timeout(123231, TimeUnit.SECONDS) - .idleTimeout(232342, TimeUnit.SECONDS) - .followRedirects(false) - .header(HttpHeader.ACCEPT, "application/json") - .header("X-Some-Other-Custom-Header", "some-other-value")); + .method(HttpMethod.POST) + .version(HttpVersion.HTTP_1_0) + .content(new StringContentProvider("some other string")) + .timeout(123231, TimeUnit.SECONDS) + .idleTimeout(232342, TimeUnit.SECONDS) + .followRedirects(false) + .header(HttpHeader.ACCEPT, "application/json") + .header("X-Some-Other-Custom-Header", "some-other-value")); assertCopyRequest(client.newRequest("https://example.com") - .header(HttpHeader.ACCEPT, "application/json") - .header(HttpHeader.ACCEPT, "application/xml") - .header("x-same-name", "value1") - .header("x-same-name", "value2")); + .header(HttpHeader.ACCEPT, "application/json") + .header(HttpHeader.ACCEPT, "application/xml") + .header("x-same-name", "value1") + .header("x-same-name", "value2")); assertCopyRequest(client.newRequest("https://example.com") - .header(HttpHeader.ACCEPT, "application/json") - .header(HttpHeader.CONTENT_TYPE, "application/json")); + .header(HttpHeader.ACCEPT, "application/json") + .header(HttpHeader.CONTENT_TYPE, "application/json")); assertCopyRequest(client.newRequest("https://example.com") - .header("Accept", "application/json") - .header("Content-Type", "application/json")); + .header("Accept", "application/json") + .header("Content-Type", "application/json")); assertCopyRequest(client.newRequest("https://example.com") - .header("X-Custom-Header-1", "value1") - .header("X-Custom-Header-2", "value2")); + .header("X-Custom-Header-1", "value1") + .header("X-Custom-Header-2", "value2")); assertCopyRequest(client.newRequest("https://example.com") - .header("X-Custom-Header-1", "value") - .header("X-Custom-Header-2", "value")); + .header("X-Custom-Header-1", "value") + .header("X-Custom-Header-2", "value")); } @ParameterizedTest @@ -1696,10 +1707,10 @@ public class HttpClientTest extends AbstractHttpClientServerTest }); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .version(HttpVersion.HTTP_1_0) - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .version(HttpVersion.HTTP_1_0) + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(200, response.getStatus()); } @@ -1719,8 +1730,8 @@ public class HttpClientTest extends AbstractHttpClientServerTest client.setIdleTimeout(idleTimeout); Request request = client.newRequest("localhost", server.getLocalPort()) - .scheme(scenario.getScheme()) - .timeout(5, TimeUnit.SECONDS); + .scheme(scenario.getScheme()) + .timeout(5, TimeUnit.SECONDS); FutureResponseListener listener = new FutureResponseListener(request); request.send(listener); @@ -1732,8 +1743,8 @@ public class HttpClientTest extends AbstractHttpClientServerTest consume(input, false); // Send a bad response. - String httpResponse = "" + - "HTTP/1.1 204 No Content\r\n" + + String httpResponse = + "HTTP/1.1 204 No Content\r\n" + "\r\n" + "No Content"; OutputStream output = socket.getOutputStream(); @@ -1749,15 +1760,15 @@ public class HttpClientTest extends AbstractHttpClientServerTest // Send another request to verify we have handled the wrong response correctly. request = client.newRequest("localhost", server.getLocalPort()) - .scheme(scenario.getScheme()) - .timeout(5, TimeUnit.SECONDS); + .scheme(scenario.getScheme()) + .timeout(5, TimeUnit.SECONDS); listener = new FutureResponseListener(request); request.send(listener); consume(input, false); - httpResponse = "" + - "HTTP/1.1 200 OK\r\n" + + httpResponse = + "HTTP/1.1 200 OK\r\n" + "Content-Length: 0\r\n" + "\r\n"; output.write(httpResponse.getBytes(StandardCharsets.UTF_8)); @@ -1771,7 +1782,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest private void assertCopyRequest(Request original) { - Request copy = client.copyRequest((HttpRequest) original, original.getURI()); + Request copy = client.copyRequest((HttpRequest)original, original.getURI()); assertEquals(original.getURI(), copy.getURI()); assertEquals(original.getMethod(), copy.getMethod()); assertEquals(original.getVersion(), copy.getVersion()); @@ -1799,7 +1810,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest } } - public static abstract class RetryListener implements Response.CompleteListener + public abstract static class RetryListener implements Response.CompleteListener { private final HttpClient client; private final String scheme; @@ -1837,11 +1848,11 @@ public class HttpClientTest extends AbstractHttpClientServerTest public void perform() { client.newRequest(host, port) - .scheme(scheme) - .method("POST") - .param("attempt", String.valueOf(retries)) - .content(new StringContentProvider("0123456789ABCDEF")) - .send(this); + .scheme(scheme) + .method("POST") + .param("attempt", String.valueOf(retries)) + .content(new StringContentProvider("0123456789ABCDEF")) + .send(this); } } } diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientURITest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientURITest.java index bd4a567381c..15d62f1b6bb 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientURITest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientURITest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,13 +18,6 @@ package org.eclipse.jetty.client; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.instanceOf; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; @@ -38,7 +31,6 @@ import java.nio.charset.StandardCharsets; import java.util.Locale; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -50,23 +42,34 @@ import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.toolchain.test.Net; import org.eclipse.jetty.util.Fields; +import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.URIUtil; +import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsSource; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.instanceOf; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class HttpClientURITest extends AbstractHttpClientServerTest { @ParameterizedTest @ArgumentsSource(ScenarioProvider.class) public void testIPv6Host(Scenario scenario) throws Exception { + Assumptions.assumeTrue(Net.isIpv6InterfaceAvailable()); start(scenario, new EmptyServerHandler()); String host = "::1"; Request request = client.newRequest(host, connector.getLocalPort()) - .scheme(scenario.getScheme()) - .timeout(5, TimeUnit.SECONDS); + .scheme(scenario.getScheme()) + .timeout(5, TimeUnit.SECONDS); assertEquals(host, request.getHost()); StringBuilder uri = new StringBuilder(); @@ -81,7 +84,8 @@ public class HttpClientURITest extends AbstractHttpClientServerTest public void testIDNHost(Scenario scenario) throws Exception { startClient(scenario); - assertThrows(IllegalArgumentException.class, ()-> { + assertThrows(IllegalArgumentException.class, () -> + { client.newRequest(scenario.getScheme() + "://пример.рф"); // example.com-like host in IDN domain }); } @@ -104,18 +108,19 @@ public class HttpClientURITest extends AbstractHttpClientServerTest startClient(scenario); ContentResponse response = client.newRequest("localhost", server.getLocalPort()) - .timeout(5, TimeUnit.SECONDS) - .followRedirects(false) - .send(); + .timeout(5, TimeUnit.SECONDS) + .followRedirects(false) + .send(); HttpField location = response.getHeaders().getField(HttpHeader.LOCATION); assertEquals(incorrectlyDecoded, location.getValue()); - ExecutionException x = assertThrows(ExecutionException.class, ()-> { + ExecutionException x = assertThrows(ExecutionException.class, () -> + { client.newRequest("localhost", server.getLocalPort()) - .timeout(5, TimeUnit.SECONDS) - .followRedirects(true) - .send(); + .timeout(5, TimeUnit.SECONDS) + .followRedirects(true) + .send(); }); assertThat(x.getCause(), instanceOf(IllegalArgumentException.class)); } @@ -141,9 +146,9 @@ public class HttpClientURITest extends AbstractHttpClientServerTest }); Request request = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .timeout(5, TimeUnit.SECONDS) - .path(path); + .scheme(scenario.getScheme()) + .timeout(5, TimeUnit.SECONDS) + .path(path); assertEquals(path, request.getPath()); assertNull(request.getQuery()); @@ -177,9 +182,9 @@ public class HttpClientURITest extends AbstractHttpClientServerTest String pathQuery = path + "?" + query; Request request = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .timeout(5, TimeUnit.SECONDS) - .path(pathQuery); + .scheme(scenario.getScheme()) + .timeout(5, TimeUnit.SECONDS) + .path(pathQuery); assertEquals(path, request.getPath()); assertEquals(query, request.getQuery()); @@ -214,10 +219,10 @@ public class HttpClientURITest extends AbstractHttpClientServerTest }); Request request = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .timeout(5, TimeUnit.SECONDS) - .path(path) - .param(name, value); + .scheme(scenario.getScheme()) + .timeout(5, TimeUnit.SECONDS) + .path(path) + .param(name, value); assertEquals(path, request.getPath()); assertEquals(query, request.getQuery()); @@ -254,10 +259,10 @@ public class HttpClientURITest extends AbstractHttpClientServerTest }); Request request = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .timeout(5, TimeUnit.SECONDS) - .path(path + "?" + name1 + "=" + value1) - .param(name2, value2); + .scheme(scenario.getScheme()) + .timeout(5, TimeUnit.SECONDS) + .path(path + "?" + name1 + "=" + value1) + .param(name2, value2); assertEquals(path, request.getPath()); assertEquals(query, request.getQuery()); @@ -299,10 +304,10 @@ public class HttpClientURITest extends AbstractHttpClientServerTest }); Request request = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .timeout(5, TimeUnit.SECONDS) - .path(path + "?" + name1 + "=" + encodedValue1) - .param(name2, value2); + .scheme(scenario.getScheme()) + .timeout(5, TimeUnit.SECONDS) + .path(path + "?" + name1 + "=" + encodedValue1) + .param(name2, value2); assertEquals(path, request.getPath()); assertEquals(query, request.getQuery()); @@ -336,9 +341,9 @@ public class HttpClientURITest extends AbstractHttpClientServerTest }); Request request = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .timeout(5, TimeUnit.SECONDS) - .path(pathQuery); + .scheme(scenario.getScheme()) + .timeout(5, TimeUnit.SECONDS) + .path(pathQuery); assertEquals(path, request.getPath()); assertEquals(query, request.getQuery()); @@ -370,9 +375,9 @@ public class HttpClientURITest extends AbstractHttpClientServerTest }); Request request = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .timeout(5, TimeUnit.SECONDS) - .path(pathQuery); + .scheme(scenario.getScheme()) + .timeout(5, TimeUnit.SECONDS) + .path(pathQuery); assertEquals(path, request.getPath()); assertEquals(query, request.getQuery()); @@ -403,11 +408,11 @@ public class HttpClientURITest extends AbstractHttpClientServerTest }); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path("/path?" + name1 + "=" + name1) - .param(name2, name2) - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .path("/path?" + name1 + "=" + name1) + .param(name2, name2) + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(HttpStatus.OK_200, response.getStatus()); } @@ -433,7 +438,7 @@ public class HttpClientURITest extends AbstractHttpClientServerTest String uri = scenario.getScheme() + "://localhost:" + connector.getLocalPort() + "/path?" + rawQuery; Request request = client.newRequest(uri) - .timeout(5, TimeUnit.SECONDS); + .timeout(5, TimeUnit.SECONDS); assertEquals(rawQuery, request.getQuery()); ContentResponse response = request.send(); @@ -461,9 +466,9 @@ public class HttpClientURITest extends AbstractHttpClientServerTest }); Request request = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path("/path?" + rawQuery) - .timeout(5, TimeUnit.SECONDS); + .scheme(scenario.getScheme()) + .path("/path?" + rawQuery) + .timeout(5, TimeUnit.SECONDS); assertEquals(rawQuery, request.getQuery()); ContentResponse response = request.send(); @@ -496,10 +501,10 @@ public class HttpClientURITest extends AbstractHttpClientServerTest }); Request request = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path("/path?" + rawQuery1) - .param(name2, value2) - .timeout(5, TimeUnit.SECONDS); + .scheme(scenario.getScheme()) + .path("/path?" + rawQuery1) + .param(name2, value2) + .timeout(5, TimeUnit.SECONDS); assertEquals(query, request.getQuery()); ContentResponse response = request.send(); @@ -521,9 +526,9 @@ public class HttpClientURITest extends AbstractHttpClientServerTest }); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme().toUpperCase(Locale.ENGLISH)) - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme().toUpperCase(Locale.ENGLISH)) + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(HttpStatus.OK_200, response.getStatus()); } @@ -542,9 +547,9 @@ public class HttpClientURITest extends AbstractHttpClientServerTest }); ContentResponse response = client.newRequest("LOCALHOST", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(HttpStatus.OK_200, response.getStatus()); } @@ -565,10 +570,10 @@ public class HttpClientURITest extends AbstractHttpClientServerTest }); Request request = client.newRequest("localhost", connector.getLocalPort()) - .method(HttpMethod.OPTIONS) - .scheme(scenario.getScheme()) - .path("*") - .timeout(5, TimeUnit.SECONDS); + .method(HttpMethod.OPTIONS) + .scheme(scenario.getScheme()) + .path("*") + .timeout(5, TimeUnit.SECONDS); assertEquals("*", request.getPath()); assertNull(request.getQuery()); @@ -607,15 +612,15 @@ public class HttpClientURITest extends AbstractHttpClientServerTest while (true) { String line = reader.readLine(); - if (line == null || line.isEmpty()) + if (StringUtil.isEmpty(line)) break; } writer.append("HTTP/1.1 302 Found\r\n") - .append("Location: ").append(location).append("\r\n") - .append("Content-Length: 0\r\n") - .append("Connection: close\r\n") - .append("\r\n"); + .append("Location: ").append(location).append("\r\n") + .append("Content-Length: 0\r\n") + .append("Connection: close\r\n") + .append("\r\n"); writer.flush(); } } diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientUploadDuringServerShutdown.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientUploadDuringServerShutdown.java index 73804840b3e..ce760f61dee 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientUploadDuringServerShutdown.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientUploadDuringServerShutdown.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,9 +18,6 @@ package org.eclipse.jetty.client; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.IOException; import java.io.InputStream; import java.util.Random; @@ -28,7 +25,6 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -46,9 +42,11 @@ import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.thread.QueuedThreadPool; - import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class HttpClientUploadDuringServerShutdown { /** @@ -121,8 +119,8 @@ public class HttpClientUploadDuringServerShutdown { int length = 16 * 1024 * 1024 + random.nextInt(16 * 1024 * 1024); client.newRequest("localhost", 8888) - .content(new BytesContentProvider(new byte[length])) - .send(result -> latch.countDown()); + .content(new BytesContentProvider(new byte[length])) + .send(result -> latch.countDown()); long sleep = 1 + random.nextInt(10); TimeUnit.MILLISECONDS.sleep(sleep); } @@ -235,20 +233,20 @@ public class HttpClientUploadDuringServerShutdown final CountDownLatch completeLatch = new CountDownLatch(1); client.newRequest("localhost", connector.getLocalPort()) - .timeout(10, TimeUnit.SECONDS) - .onRequestBegin(request -> + .timeout(10, TimeUnit.SECONDS) + .onRequestBegin(request -> + { + try { - try - { - beginLatch.countDown(); - completeLatch.await(5, TimeUnit.SECONDS); - } - catch (InterruptedException x) - { - x.printStackTrace(); - } - }) - .send(result -> completeLatch.countDown()); + beginLatch.countDown(); + completeLatch.await(5, TimeUnit.SECONDS); + } + catch (InterruptedException x) + { + x.printStackTrace(); + } + }) + .send(result -> completeLatch.countDown()); assertTrue(completeLatch.await(5, TimeUnit.SECONDS)); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpConnectionLifecycleTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpConnectionLifecycleTest.java index 243303f5345..3c4b362a324 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpConnectionLifecycleTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpConnectionLifecycleTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,10 +18,6 @@ package org.eclipse.jetty.client; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.IOException; import java.nio.ByteBuffer; import java.util.Arrays; @@ -29,7 +25,6 @@ import java.util.Collection; import java.util.Queue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -43,7 +38,6 @@ import org.eclipse.jetty.client.http.HttpDestinationOverHTTP; import org.eclipse.jetty.client.util.ByteBufferContentProvider; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpVersion; -import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.StacklessLogging; @@ -52,13 +46,18 @@ import org.junit.jupiter.api.condition.DisabledIfSystemProperty; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsSource; +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 HttpConnectionLifecycleTest extends AbstractHttpClientServerTest { @Override - public void start(Scenario scenario, Handler handler) throws Exception + public HttpClient newHttpClient(Scenario scenario, HttpClientTransport transport) { - super.start(scenario, handler); + HttpClient client = super.newHttpClient(scenario, transport); client.setStrictEventOrdering(false); + return client; } @ParameterizedTest @@ -81,29 +80,29 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest final CountDownLatch headersLatch = new CountDownLatch(1); final CountDownLatch successLatch = new CountDownLatch(3); client.newRequest(host, port) - .scheme(scenario.getScheme()) - .onRequestSuccess(request -> successLatch.countDown()) - .onResponseHeaders(response -> + .scheme(scenario.getScheme()) + .onRequestSuccess(request -> successLatch.countDown()) + .onResponseHeaders(response -> + { + assertEquals(0, idleConnections.size()); + assertEquals(1, activeConnections.size()); + headersLatch.countDown(); + }) + .send(new Response.Listener.Adapter() + { + @Override + public void onSuccess(Response response) { - assertEquals(0, idleConnections.size()); - assertEquals(1, activeConnections.size()); - headersLatch.countDown(); - }) - .send(new Response.Listener.Adapter() - { - @Override - public void onSuccess(Response response) - { - successLatch.countDown(); - } + successLatch.countDown(); + } - @Override - public void onComplete(Result result) - { - assertFalse(result.isFailed()); - successLatch.countDown(); - } - }); + @Override + public void onComplete(Result result) + { + assertFalse(result.isFailed()); + successLatch.countDown(); + } + }); assertTrue(headersLatch.await(30, TimeUnit.SECONDS)); assertTrue(successLatch.await(30, TimeUnit.SECONDS)); @@ -183,40 +182,40 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest final CountDownLatch successLatch = new CountDownLatch(3); client.newRequest(host, port) - .scheme(scenario.getScheme()) - .listener(new Request.Listener.Adapter() + .scheme(scenario.getScheme()) + .listener(new Request.Listener.Adapter() + { + @Override + public void onBegin(Request request) { - @Override - public void onBegin(Request request) - { - // Remove the host header, this will make the request invalid - request.header(HttpHeader.HOST, null); - } + // Remove the host header, this will make the request invalid + request.header(HttpHeader.HOST, null); + } - @Override - public void onSuccess(Request request) - { - successLatch.countDown(); - } - }) - .send(new Response.Listener.Adapter() + @Override + public void onSuccess(Request request) { - @Override - public void onSuccess(Response response) - { - assertEquals(400, response.getStatus()); - // 400 response also come with a Connection: close, - // so the connection is closed and removed - successLatch.countDown(); - } + successLatch.countDown(); + } + }) + .send(new Response.Listener.Adapter() + { + @Override + public void onSuccess(Response response) + { + assertEquals(400, response.getStatus()); + // 400 response also come with a Connection: close, + // so the connection is closed and removed + successLatch.countDown(); + } - @Override - public void onComplete(Result result) - { - assertFalse(result.isFailed()); - successLatch.countDown(); - } - }); + @Override + public void onComplete(Result result) + { + assertFalse(result.isFailed()); + successLatch.countDown(); + } + }); assertTrue(successLatch.await(30, TimeUnit.SECONDS)); @@ -246,53 +245,53 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest final long delay = 1000; final CountDownLatch successLatch = new CountDownLatch(3); client.newRequest(host, port) - .scheme(scenario.getScheme()) - .listener(new Request.Listener.Adapter() + .scheme(scenario.getScheme()) + .listener(new Request.Listener.Adapter() + { + @Override + public void onBegin(Request request) { - @Override - public void onBegin(Request request) - { - // Remove the host header, this will make the request invalid - request.header(HttpHeader.HOST, null); - } + // Remove the host header, this will make the request invalid + request.header(HttpHeader.HOST, null); + } - @Override - public void onHeaders(Request request) - { - try - { - TimeUnit.MILLISECONDS.sleep(delay); - } - catch (InterruptedException e) - { - e.printStackTrace(); - } - } - - @Override - public void onSuccess(Request request) - { - successLatch.countDown(); - } - }) - .send(new Response.Listener.Adapter() + @Override + public void onHeaders(Request request) { - @Override - public void onSuccess(Response response) + try { - assertEquals(400, response.getStatus()); - // 400 response also come with a Connection: close, - // so the connection is closed and removed - successLatch.countDown(); + TimeUnit.MILLISECONDS.sleep(delay); } + catch (InterruptedException e) + { + e.printStackTrace(); + } + } - @Override - public void onComplete(Result result) - { - assertFalse(result.isFailed()); - successLatch.countDown(); - } - }); + @Override + public void onSuccess(Request request) + { + successLatch.countDown(); + } + }) + .send(new Response.Listener.Adapter() + { + @Override + public void onSuccess(Response response) + { + assertEquals(400, response.getStatus()); + // 400 response also come with a Connection: close, + // so the connection is closed and removed + successLatch.countDown(); + } + + @Override + public void onComplete(Result result) + { + assertFalse(result.isFailed()); + successLatch.countDown(); + } + }); assertTrue(successLatch.await(delay * 30, TimeUnit.MILLISECONDS)); @@ -321,13 +320,13 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest final CountDownLatch failureLatch = new CountDownLatch(2); client.newRequest(host, port) - .scheme(scenario.getScheme()) - .onRequestFailure((request, failure) -> failureLatch.countDown()) - .send(result -> - { - assertTrue(result.isFailed()); - failureLatch.countDown(); - }); + .scheme(scenario.getScheme()) + .onRequestFailure((request, failure) -> failureLatch.countDown()) + .send(result -> + { + assertTrue(result.isFailed()); + failureLatch.countDown(); + }); assertTrue(failureLatch.await(30, TimeUnit.SECONDS)); @@ -362,18 +361,18 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest final CountDownLatch latch = new CountDownLatch(1); client.newRequest(host, port) - .scheme(scenario.getScheme()) - .send(new Response.Listener.Adapter() + .scheme(scenario.getScheme()) + .send(new Response.Listener.Adapter() + { + @Override + public void onComplete(Result result) { - @Override - public void onComplete(Result result) - { - assertFalse(result.isFailed()); - assertEquals(0, idleConnections.size()); - assertEquals(0, activeConnections.size()); - latch.countDown(); - } - }); + assertFalse(result.isFailed()); + assertEquals(0, idleConnections.size()); + assertEquals(0, activeConnections.size()); + latch.countDown(); + } + }); assertTrue(latch.await(30, TimeUnit.SECONDS)); @@ -413,21 +412,21 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest final CountDownLatch latch = new CountDownLatch(1); ByteBuffer buffer = ByteBuffer.allocate(16 * 1024 * 1024); - Arrays.fill(buffer.array(),(byte)'x'); + Arrays.fill(buffer.array(), (byte)'x'); client.newRequest(host, port) - .scheme(scenario.getScheme()) - .content(new ByteBufferContentProvider(buffer)) - .send(new Response.Listener.Adapter() + .scheme(scenario.getScheme()) + .content(new ByteBufferContentProvider(buffer)) + .send(new Response.Listener.Adapter() + { + @Override + public void onComplete(Result result) { - @Override - public void onComplete(Result result) - { - assertEquals(1, latch.getCount()); - assertEquals(0, idleConnections.size()); - assertEquals(0, activeConnections.size()); - latch.countDown(); - } - }); + assertEquals(1, latch.getCount()); + assertEquals(0, idleConnections.size()); + assertEquals(0, activeConnections.size()); + latch.countDown(); + } + }); assertTrue(latch.await(30, TimeUnit.SECONDS)); @@ -458,9 +457,9 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest assertEquals(0, activeConnections.size()); ContentResponse response = client.newRequest(host, port) - .scheme(scenario.getScheme()) - .timeout(30, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .timeout(30, TimeUnit.SECONDS) + .send(); assertEquals(200, response.getStatus()); @@ -492,13 +491,13 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest client.setStrictEventOrdering(false); ContentResponse response = client.newRequest(host, port) - .scheme(scenario.getScheme()) - .onResponseBegin(response1 -> - { - // Simulate a HTTP 1.0 response has been received. - ((HttpResponse)response1).version(HttpVersion.HTTP_1_0); - }) - .send(); + .scheme(scenario.getScheme()) + .onResponseBegin(response1 -> + { + // Simulate an HTTP 1.0 response has been received. + ((HttpResponse)response1).version(HttpVersion.HTTP_1_0); + }) + .send(); assertEquals(200, response.getStatus()); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpCookieTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpCookieTest.java index d61b159d9f8..c90c821a70e 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpCookieTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpCookieTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,13 +18,6 @@ package org.eclipse.jetty.client; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - import java.io.IOException; import java.net.HttpCookie; import java.net.URI; @@ -34,7 +27,6 @@ import java.util.List; import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeUnit; - import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; @@ -47,6 +39,13 @@ import org.eclipse.jetty.server.Request; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsSource; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + public class HttpCookieTest extends AbstractHttpClientServerTest { private static final Cookie[] EMPTY_COOKIES = new Cookie[0]; @@ -126,8 +125,8 @@ public class HttpCookieTest extends AbstractHttpClientServerTest }); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .send(); + .scheme(scenario.getScheme()) + .send(); assertEquals(200, response.getStatus()); assertTrue(client.getCookieStore().getCookies().isEmpty()); } @@ -153,10 +152,10 @@ public class HttpCookieTest extends AbstractHttpClientServerTest }); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .cookie(new HttpCookie(name, value)) - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .cookie(new HttpCookie(name, value)) + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(200, response.getStatus()); } @@ -199,19 +198,19 @@ public class HttpCookieTest extends AbstractHttpClientServerTest }); ContentResponse response = send(client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path("/foo") - .header(headerName, "0") - .timeout(5, TimeUnit.SECONDS)); + .scheme(scenario.getScheme()) + .path("/foo") + .header(headerName, "0") + .timeout(5, TimeUnit.SECONDS)); assertEquals(HttpStatus.OK_200, response.getStatus()); Arrays.asList("/", "/foo", "/foo/bar").forEach(path -> { ContentResponse r = send(client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path(path) - .header(headerName, "1") - .timeout(5, TimeUnit.SECONDS)); + .scheme(scenario.getScheme()) + .path(path) + .header(headerName, "1") + .timeout(5, TimeUnit.SECONDS)); assertEquals(HttpStatus.OK_200, r.getStatus()); }); } @@ -260,19 +259,19 @@ public class HttpCookieTest extends AbstractHttpClientServerTest }); ContentResponse response = send(client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path("/foo/bar") - .header(headerName, "0") - .timeout(5, TimeUnit.SECONDS)); + .scheme(scenario.getScheme()) + .path("/foo/bar") + .header(headerName, "0") + .timeout(5, TimeUnit.SECONDS)); assertEquals(HttpStatus.OK_200, response.getStatus()); Arrays.asList("/", "/foo", "/foo/", "/foobar", "/foo/bar", "/foo/bar/baz").forEach(path -> { ContentResponse r = send(client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path(path) - .header(headerName, "1") - .timeout(5, TimeUnit.SECONDS)); + .scheme(scenario.getScheme()) + .path(path) + .header(headerName, "1") + .timeout(5, TimeUnit.SECONDS)); assertEquals(HttpStatus.OK_200, r.getStatus()); }); } @@ -321,19 +320,19 @@ public class HttpCookieTest extends AbstractHttpClientServerTest }); ContentResponse response = send(client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path("/foo") - .header(headerName, "0") - .timeout(5, TimeUnit.SECONDS)); + .scheme(scenario.getScheme()) + .path("/foo") + .header(headerName, "0") + .timeout(5, TimeUnit.SECONDS)); assertEquals(HttpStatus.OK_200, response.getStatus()); Arrays.asList("/", "/foo", "/foo/bar", "/foo/bar/", "/foo/barbaz").forEach(path -> { ContentResponse r = send(client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path(path) - .header(headerName, "1") - .timeout(5, TimeUnit.SECONDS)); + .scheme(scenario.getScheme()) + .path(path) + .header(headerName, "1") + .timeout(5, TimeUnit.SECONDS)); assertEquals(HttpStatus.OK_200, r.getStatus()); }); } @@ -382,19 +381,19 @@ public class HttpCookieTest extends AbstractHttpClientServerTest }); ContentResponse response = send(client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path("/foo/bar") - .header(headerName, "0") - .timeout(5, TimeUnit.SECONDS)); + .scheme(scenario.getScheme()) + .path("/foo/bar") + .header(headerName, "0") + .timeout(5, TimeUnit.SECONDS)); assertEquals(HttpStatus.OK_200, response.getStatus()); Arrays.asList("/", "/foo", "/foo/", "/foobar", "/foo/bar").forEach(path -> { ContentResponse r = send(client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path(path) - .header(headerName, "1") - .timeout(5, TimeUnit.SECONDS)); + .scheme(scenario.getScheme()) + .path(path) + .header(headerName, "1") + .timeout(5, TimeUnit.SECONDS)); assertEquals(HttpStatus.OK_200, r.getStatus()); }); } @@ -445,19 +444,19 @@ public class HttpCookieTest extends AbstractHttpClientServerTest }); ContentResponse response = send(client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path("/foo") - .header(headerName, "0") - .timeout(5, TimeUnit.SECONDS)); + .scheme(scenario.getScheme()) + .path("/foo") + .header(headerName, "0") + .timeout(5, TimeUnit.SECONDS)); assertEquals(HttpStatus.OK_200, response.getStatus()); Arrays.asList("/", "/foo", "/foo/bar").forEach(path -> { ContentResponse r = send(client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path(path) - .header(headerName, "1") - .timeout(5, TimeUnit.SECONDS)); + .scheme(scenario.getScheme()) + .path(path) + .header(headerName, "1") + .timeout(5, TimeUnit.SECONDS)); assertEquals(HttpStatus.OK_200, r.getStatus()); }); } @@ -515,19 +514,19 @@ public class HttpCookieTest extends AbstractHttpClientServerTest }); ContentResponse response = send(client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path("/foo") - .header(headerName, "0") - .timeout(5, TimeUnit.SECONDS)); + .scheme(scenario.getScheme()) + .path("/foo") + .header(headerName, "0") + .timeout(5, TimeUnit.SECONDS)); assertEquals(HttpStatus.OK_200, response.getStatus()); Arrays.asList("/", "/foo", "/foo/bar", "/bar", "/bar/foo").forEach(path -> { ContentResponse r = send(client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path(path) - .header(headerName, "1") - .timeout(5, TimeUnit.SECONDS)); + .scheme(scenario.getScheme()) + .path(path) + .header(headerName, "1") + .timeout(5, TimeUnit.SECONDS)); assertEquals(HttpStatus.OK_200, r.getStatus()); }); } @@ -588,19 +587,19 @@ public class HttpCookieTest extends AbstractHttpClientServerTest }); ContentResponse response = send(client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path("/foo") - .header(headerName, "0") - .timeout(5, TimeUnit.SECONDS)); + .scheme(scenario.getScheme()) + .path("/foo") + .header(headerName, "0") + .timeout(5, TimeUnit.SECONDS)); assertEquals(HttpStatus.OK_200, response.getStatus()); Arrays.asList("/", "/foo", "/foo/bar").forEach(path -> { ContentResponse r = send(client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path(path) - .header(headerName, "1") - .timeout(5, TimeUnit.SECONDS)); + .scheme(scenario.getScheme()) + .path(path) + .header(headerName, "1") + .timeout(5, TimeUnit.SECONDS)); assertEquals(HttpStatus.OK_200, r.getStatus()); }); } @@ -649,19 +648,19 @@ public class HttpCookieTest extends AbstractHttpClientServerTest }); ContentResponse response = send(client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path("/foo/bar") - .header(headerName, "0") - .timeout(5, TimeUnit.SECONDS)); + .scheme(scenario.getScheme()) + .path("/foo/bar") + .header(headerName, "0") + .timeout(5, TimeUnit.SECONDS)); assertEquals(HttpStatus.OK_200, response.getStatus()); Arrays.asList("/", "/foo", "/foo/", "/foobar", "/foo/bar").forEach(path -> { ContentResponse r = send(client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path(path) - .header(headerName, "1") - .timeout(5, TimeUnit.SECONDS)); + .scheme(scenario.getScheme()) + .path(path) + .header(headerName, "1") + .timeout(5, TimeUnit.SECONDS)); assertEquals(HttpStatus.OK_200, r.getStatus()); }); } diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpRequestAbortTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpRequestAbortTest.java index 4a63f1089d5..3a2d7d6304a 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpRequestAbortTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpRequestAbortTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,12 +18,6 @@ package org.eclipse.jetty.client; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertSame; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.IOException; import java.nio.ByteBuffer; import java.util.concurrent.CountDownLatch; @@ -31,7 +25,6 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; - import javax.servlet.DispatcherType; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -47,6 +40,12 @@ import org.eclipse.jetty.util.log.StacklessLogging; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsSource; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class HttpRequestAbortTest extends AbstractHttpClientServerTest { @ParameterizedTest @@ -57,10 +56,11 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest Exception failure = new Exception("oops"); - ExecutionException x = assertThrows(ExecutionException.class, ()->{ + ExecutionException x = assertThrows(ExecutionException.class, () -> + { Request request = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .timeout(5, TimeUnit.SECONDS); + .scheme(scenario.getScheme()) + .timeout(5, TimeUnit.SECONDS); request.abort(failure); request.send(); }); @@ -85,26 +85,27 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest final CountDownLatch latch = new CountDownLatch(1); final AtomicBoolean begin = new AtomicBoolean(); - ExecutionException x = assertThrows(ExecutionException.class, ()->{ + ExecutionException x = assertThrows(ExecutionException.class, () -> + { client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .listener(new Request.Listener.Adapter() + .scheme(scenario.getScheme()) + .listener(new Request.Listener.Adapter() + { + @Override + public void onQueued(Request request) { - @Override - public void onQueued(Request request) - { - aborted.set(request.abort(cause)); - latch.countDown(); - } + aborted.set(request.abort(cause)); + latch.countDown(); + } - @Override - public void onBegin(Request request) - { - begin.set(true); - } - }) - .timeout(5, TimeUnit.SECONDS) - .send(); + @Override + public void onBegin(Request request) + { + begin.set(true); + } + }) + .timeout(5, TimeUnit.SECONDS) + .send(); }); assertTrue(latch.await(5, TimeUnit.SECONDS)); @@ -130,26 +131,27 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest final CountDownLatch latch = new CountDownLatch(1); final CountDownLatch committed = new CountDownLatch(1); - ExecutionException x = assertThrows(ExecutionException.class, ()->{ + ExecutionException x = assertThrows(ExecutionException.class, () -> + { client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .listener(new Request.Listener.Adapter() + .scheme(scenario.getScheme()) + .listener(new Request.Listener.Adapter() + { + @Override + public void onBegin(Request request) { - @Override - public void onBegin(Request request) - { - aborted.set(request.abort(cause)); - latch.countDown(); - } + aborted.set(request.abort(cause)); + latch.countDown(); + } - @Override - public void onCommit(Request request) - { - committed.countDown(); - } - }) - .timeout(5, TimeUnit.SECONDS) - .send(); + @Override + public void onCommit(Request request) + { + committed.countDown(); + } + }) + .timeout(5, TimeUnit.SECONDS) + .send(); }); assertTrue(latch.await(5, TimeUnit.SECONDS)); if (aborted.get()) @@ -174,26 +176,27 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest final CountDownLatch latch = new CountDownLatch(1); final CountDownLatch committed = new CountDownLatch(1); - ExecutionException x = assertThrows(ExecutionException.class, ()->{ + ExecutionException x = assertThrows(ExecutionException.class, () -> + { client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .listener(new Request.Listener.Adapter() + .scheme(scenario.getScheme()) + .listener(new Request.Listener.Adapter() + { + @Override + public void onHeaders(Request request) { - @Override - public void onHeaders(Request request) - { - aborted.set(request.abort(cause)); - latch.countDown(); - } + aborted.set(request.abort(cause)); + latch.countDown(); + } - @Override - public void onCommit(Request request) - { - committed.countDown(); - } - }) - .timeout(5, TimeUnit.SECONDS) - .send(); + @Override + public void onCommit(Request request) + { + committed.countDown(); + } + }) + .timeout(5, TimeUnit.SECONDS) + .send(); }); assertTrue(latch.await(5, TimeUnit.SECONDS)); if (aborted.get()) @@ -220,16 +223,17 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest final Throwable cause = new Exception(); final AtomicBoolean aborted = new AtomicBoolean(); final CountDownLatch latch = new CountDownLatch(1); - ExecutionException x = assertThrows(ExecutionException.class, ()->{ + ExecutionException x = assertThrows(ExecutionException.class, () -> + { client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .onRequestCommit(request -> - { - aborted.set(request.abort(cause)); - latch.countDown(); - }) - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .onRequestCommit(request -> + { + aborted.set(request.abort(cause)); + latch.countDown(); + }) + .timeout(5, TimeUnit.SECONDS) + .send(); }); assertTrue(latch.await(5, TimeUnit.SECONDS)); if (aborted.get()) @@ -270,24 +274,25 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest final AtomicBoolean aborted = new AtomicBoolean(); final CountDownLatch latch = new CountDownLatch(1); - ExecutionException x = assertThrows(ExecutionException.class, ()->{ + ExecutionException x = assertThrows(ExecutionException.class, () -> + { client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .onRequestCommit(request -> - { - aborted.set(request.abort(cause)); - latch.countDown(); - }) - .content(new ByteBufferContentProvider(ByteBuffer.wrap(new byte[]{0}), ByteBuffer.wrap(new byte[]{1})) - { - @Override - public long getLength() + .scheme(scenario.getScheme()) + .onRequestCommit(request -> { - return -1; - } - }) - .timeout(5, TimeUnit.SECONDS) - .send(); + aborted.set(request.abort(cause)); + latch.countDown(); + }) + .content(new ByteBufferContentProvider(ByteBuffer.wrap(new byte[]{0}), ByteBuffer.wrap(new byte[]{1})) + { + @Override + public long getLength() + { + return -1; + } + }) + .timeout(5, TimeUnit.SECONDS) + .send(); }); assertTrue(latch.await(5, TimeUnit.SECONDS)); if (aborted.get()) @@ -298,7 +303,6 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest assertEquals(0, connectionPool.getConnectionCount()); assertEquals(0, connectionPool.getActiveConnections().size()); assertEquals(0, connectionPool.getIdleConnections().size()); - } @ParameterizedTest @@ -328,24 +332,25 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest final Throwable cause = new Exception(); final AtomicBoolean aborted = new AtomicBoolean(); final CountDownLatch latch = new CountDownLatch(1); - ExecutionException x = assertThrows(ExecutionException.class, ()->{ + ExecutionException x = assertThrows(ExecutionException.class, () -> + { client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .onRequestContent((request, content) -> + .scheme(scenario.getScheme()) + .onRequestContent((request, content) -> + { + aborted.set(request.abort(cause)); + latch.countDown(); + }) + .content(new ByteBufferContentProvider(ByteBuffer.wrap(new byte[]{0}), ByteBuffer.wrap(new byte[]{1})) + { + @Override + public long getLength() { - aborted.set(request.abort(cause)); - latch.countDown(); - }) - .content(new ByteBufferContentProvider(ByteBuffer.wrap(new byte[]{0}), ByteBuffer.wrap(new byte[]{1})) - { - @Override - public long getLength() - { - return -1; - } - }) - .timeout(5, TimeUnit.SECONDS) - .send(); + return -1; + } + }) + .timeout(5, TimeUnit.SECONDS) + .send(); }); assertTrue(latch.await(5, TimeUnit.SECONDS)); if (aborted.get()) @@ -385,8 +390,8 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest }); Request request = client.newRequest("localhost", connector.getLocalPort()) - .timeout(3 * delay, TimeUnit.MILLISECONDS) - .scheme(scenario.getScheme()); + .timeout(3 * delay, TimeUnit.MILLISECONDS) + .scheme(scenario.getScheme()); final Thread thread = Thread.currentThread(); new Thread(() -> @@ -402,7 +407,7 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest } }).start(); - assertThrows(InterruptedException.class, ()->request.send()); + assertThrows(InterruptedException.class, () -> request.send()); } @ParameterizedTest @@ -429,8 +434,8 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest }); final Request request = client.newRequest("localhost", connector.getLocalPort()) - .timeout(3 * delay, TimeUnit.MILLISECONDS) - .scheme(scenario.getScheme()); + .timeout(3 * delay, TimeUnit.MILLISECONDS) + .scheme(scenario.getScheme()); final Throwable cause = new Exception(); final AtomicBoolean aborted = new AtomicBoolean(); @@ -493,8 +498,8 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest final Throwable cause = new Exception(); final CountDownLatch latch = new CountDownLatch(1); Request request = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .timeout(3 * delay, TimeUnit.MILLISECONDS); + .scheme(scenario.getScheme()) + .timeout(3 * delay, TimeUnit.MILLISECONDS); request.send(result -> { assertTrue(result.isFailed()); @@ -548,12 +553,13 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest } }); - ExecutionException e = assertThrows(ExecutionException.class,()->{ + ExecutionException e = assertThrows(ExecutionException.class, () -> + { client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path("/redirect") - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scenario.getScheme()) + .path("/redirect") + .timeout(5, TimeUnit.SECONDS) + .send(); }); assertTrue(latch.await(5, TimeUnit.SECONDS)); if (aborted.get()) diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpResponseAbortTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpResponseAbortTest.java index 2f13fb4f776..9689576f38c 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpResponseAbortTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpResponseAbortTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,16 +18,12 @@ package org.eclipse.jetty.client; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.IOException; import java.io.OutputStream; import java.nio.ByteBuffer; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -38,6 +34,9 @@ import org.eclipse.jetty.server.handler.AbstractHandler; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsSource; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class HttpResponseAbortTest extends AbstractHttpClientServerTest { @ParameterizedTest @@ -48,13 +47,13 @@ public class HttpResponseAbortTest extends AbstractHttpClientServerTest final CountDownLatch latch = new CountDownLatch(1); client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .onResponseBegin(response -> response.abort(new Exception())) - .send(result -> - { - assertTrue(result.isFailed()); - latch.countDown(); - }); + .scheme(scenario.getScheme()) + .onResponseBegin(response -> response.abort(new Exception())) + .send(result -> + { + assertTrue(result.isFailed()); + latch.countDown(); + }); assertTrue(latch.await(5, TimeUnit.SECONDS)); } @@ -66,17 +65,17 @@ public class HttpResponseAbortTest extends AbstractHttpClientServerTest final CountDownLatch latch = new CountDownLatch(1); client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .onResponseHeader((response, field) -> - { - response.abort(new Exception()); - return true; - }) - .send(result -> - { - assertTrue(result.isFailed()); - latch.countDown(); - }); + .scheme(scenario.getScheme()) + .onResponseHeader((response, field) -> + { + response.abort(new Exception()); + return true; + }) + .send(result -> + { + assertTrue(result.isFailed()); + latch.countDown(); + }); assertTrue(latch.await(5, TimeUnit.SECONDS)); } @@ -88,13 +87,13 @@ public class HttpResponseAbortTest extends AbstractHttpClientServerTest final CountDownLatch latch = new CountDownLatch(1); client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .onResponseHeaders(response -> response.abort(new Exception())) - .send(result -> - { - assertTrue(result.isFailed()); - latch.countDown(); - }); + .scheme(scenario.getScheme()) + .onResponseHeaders(response -> response.abort(new Exception())) + .send(result -> + { + assertTrue(result.isFailed()); + latch.countDown(); + }); assertTrue(latch.await(5, TimeUnit.SECONDS)); } @@ -125,13 +124,13 @@ public class HttpResponseAbortTest extends AbstractHttpClientServerTest final CountDownLatch latch = new CountDownLatch(1); client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .onResponseContent((response, content) -> response.abort(new Exception())) - .send(result -> - { - assertTrue(result.isFailed()); - latch.countDown(); - }); + .scheme(scenario.getScheme()) + .onResponseContent((response, content) -> response.abort(new Exception())) + .send(result -> + { + assertTrue(result.isFailed()); + latch.countDown(); + }); assertTrue(latch.await(5, TimeUnit.SECONDS)); } @@ -164,28 +163,28 @@ public class HttpResponseAbortTest extends AbstractHttpClientServerTest final AtomicInteger completes = new AtomicInteger(); final CountDownLatch completeLatch = new CountDownLatch(1); client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .content(contentProvider) - .onResponseContent((response, content) -> + .scheme(scenario.getScheme()) + .content(contentProvider) + .onResponseContent((response, content) -> + { + try { - try - { - response.abort(new Exception()); - contentProvider.close(); - // Delay to let the request side to finish its processing. - Thread.sleep(1000); - } - catch (InterruptedException x) - { - x.printStackTrace(); - } - }) - .send(result -> + response.abort(new Exception()); + contentProvider.close(); + // Delay to let the request side to finish its processing. + Thread.sleep(1000); + } + catch (InterruptedException x) { - completes.incrementAndGet(); - assertTrue(result.isFailed()); - completeLatch.countDown(); - }); + x.printStackTrace(); + } + }) + .send(result -> + { + completes.incrementAndGet(); + assertTrue(result.isFailed()); + completeLatch.countDown(); + }); assertTrue(completeLatch.await(5, TimeUnit.SECONDS)); // Wait to be sure that the complete event is only notified once. diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpResponseConcurrentAbortTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpResponseConcurrentAbortTest.java index f03e8a3f8e7..d74f919ae83 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpResponseConcurrentAbortTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpResponseConcurrentAbortTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,15 +18,12 @@ package org.eclipse.jetty.client; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.IOException; import java.io.OutputStream; import java.nio.ByteBuffer; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -39,6 +36,8 @@ import org.eclipse.jetty.server.handler.AbstractHandler; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsSource; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class HttpResponseConcurrentAbortTest extends AbstractHttpClientServerTest { private final CountDownLatch callbackLatch = new CountDownLatch(1); @@ -54,16 +53,16 @@ public class HttpResponseConcurrentAbortTest extends AbstractHttpClientServerTes start(scenario, new EmptyServerHandler()); client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .onResponseBegin(new Response.BeginListener() + .scheme(scenario.getScheme()) + .onResponseBegin(new Response.BeginListener() + { + @Override + public void onBegin(Response response) { - @Override - public void onBegin(Response response) - { - abort(response); - } - }) - .send(new TestResponseListener()); + abort(response); + } + }) + .send(new TestResponseListener()); assertTrue(callbackLatch.await(5, TimeUnit.SECONDS)); assertTrue(completeLatch.await(5, TimeUnit.SECONDS)); assertTrue(failureWasAsync.get()); @@ -77,17 +76,17 @@ public class HttpResponseConcurrentAbortTest extends AbstractHttpClientServerTes start(scenario, new EmptyServerHandler()); client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .onResponseHeader(new Response.HeaderListener() + .scheme(scenario.getScheme()) + .onResponseHeader(new Response.HeaderListener() + { + @Override + public boolean onHeader(Response response, HttpField field) { - @Override - public boolean onHeader(Response response, HttpField field) - { - abort(response); - return true; - } - }) - .send(new TestResponseListener()); + abort(response); + return true; + } + }) + .send(new TestResponseListener()); assertTrue(callbackLatch.await(5, TimeUnit.SECONDS)); assertTrue(completeLatch.await(5, TimeUnit.SECONDS)); assertTrue(failureWasAsync.get()); @@ -101,16 +100,16 @@ public class HttpResponseConcurrentAbortTest extends AbstractHttpClientServerTes start(scenario, new EmptyServerHandler()); client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .onResponseHeaders(new Response.HeadersListener() + .scheme(scenario.getScheme()) + .onResponseHeaders(new Response.HeadersListener() + { + @Override + public void onHeaders(Response response) { - @Override - public void onHeaders(Response response) - { - abort(response); - } - }) - .send(new TestResponseListener()); + abort(response); + } + }) + .send(new TestResponseListener()); assertTrue(callbackLatch.await(5, TimeUnit.SECONDS)); assertTrue(completeLatch.await(5, TimeUnit.SECONDS)); assertTrue(failureWasAsync.get()); @@ -134,16 +133,16 @@ public class HttpResponseConcurrentAbortTest extends AbstractHttpClientServerTes }); client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .onResponseContent(new Response.ContentListener() + .scheme(scenario.getScheme()) + .onResponseContent(new Response.ContentListener() + { + @Override + public void onContent(Response response, ByteBuffer content) { - @Override - public void onContent(Response response, ByteBuffer content) - { - abort(response); - } - }) - .send(new TestResponseListener()); + abort(response); + } + }) + .send(new TestResponseListener()); assertTrue(callbackLatch.await(5, TimeUnit.SECONDS)); assertTrue(completeLatch.await(5, TimeUnit.SECONDS)); assertTrue(failureWasAsync.get()); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/InsufficientThreadsDetectionTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/InsufficientThreadsDetectionTest.java index 4b0ec5fbbe5..f5ed30976b6 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/InsufficientThreadsDetectionTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/InsufficientThreadsDetectionTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,13 +18,12 @@ package org.eclipse.jetty.client; -import static org.junit.jupiter.api.Assertions.assertThrows; - import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP; import org.eclipse.jetty.util.thread.QueuedThreadPool; - import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertThrows; + public class InsufficientThreadsDetectionTest { @Test @@ -33,7 +32,8 @@ public class InsufficientThreadsDetectionTest QueuedThreadPool clientThreads = new QueuedThreadPool(1); HttpClient httpClient = new HttpClient(new HttpClientTransportOverHTTP(1), null); httpClient.setExecutor(clientThreads); - assertThrows(IllegalStateException.class, ()->{ + assertThrows(IllegalStateException.class, () -> + { httpClient.start(); }); } @@ -46,7 +46,8 @@ public class InsufficientThreadsDetectionTest httpClient1.setExecutor(clientThreads); httpClient1.start(); - assertThrows(IllegalStateException.class, ()->{ + assertThrows(IllegalStateException.class, () -> + { // Share the same thread pool with another instance. HttpClient httpClient2 = new HttpClient(new HttpClientTransportOverHTTP(1), null); httpClient2.setExecutor(clientThreads); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/LivelockTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/LivelockTest.java index c32c9396d20..d232ea3b945 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/LivelockTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/LivelockTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,8 +18,6 @@ package org.eclipse.jetty.client; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.nio.channels.Selector; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -42,6 +40,8 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class LivelockTest { public static Stream modes() @@ -71,7 +71,7 @@ public class LivelockTest server.setHandler(handler); server.start(); } - + @AfterEach public void after() throws Exception { @@ -90,7 +90,7 @@ public class LivelockTest // NonBlocking actions are submitted to both the client and server // ManagedSelectors that submit themselves in an attempt to cause a live lock // as there will always be an action available to run. - + int count = 5; HttpClientTransport transport = new HttpClientTransportOverHTTP(1); client = new HttpClient(transport, null); @@ -103,7 +103,7 @@ public class LivelockTest clientThreads.setName("client"); client.setExecutor(clientThreads); client.start(); - + AtomicBoolean busy = new AtomicBoolean(true); if (clientLiveLock) @@ -125,19 +125,19 @@ public class LivelockTest for (int i = 0; i < count; ++i) { client.newRequest("localhost", connector.getLocalPort()) - .path("/" + i) - .send(result -> + .path("/" + i) + .send(result -> + { + if (result.isSucceeded() && result.getResponse().getStatus() == HttpStatus.OK_200) + latch.countDown(); + else { - if (result.isSucceeded() && result.getResponse().getStatus() == HttpStatus.OK_200) - latch.countDown(); - else - { - if(result.getRequestFailure() != null) - clientLog.warn(result.getRequestFailure()); - if(result.getResponseFailure() != null) - clientLog.warn(result.getResponseFailure()); - } - }); + if (result.getRequestFailure() != null) + clientLog.warn(result.getRequestFailure()); + if (result.getResponseFailure() != null) + clientLog.warn(result.getResponseFailure()); + } + }); sleep(pause); } assertTrue(latch.await(2 * pause * count, TimeUnit.MILLISECONDS)); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ProxyConfigurationTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ProxyConfigurationTest.java index fb773855878..87632761d7b 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/ProxyConfigurationTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ProxyConfigurationTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,12 +18,13 @@ package org.eclipse.jetty.client; +import org.eclipse.jetty.toolchain.test.Net; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -import org.junit.jupiter.api.Test; - public class ProxyConfigurationTest { @Test @@ -70,6 +71,7 @@ public class ProxyConfigurationTest @Test public void testProxyMatchesWithIncludesAndExcludesIPv6() throws Exception { + Assumptions.assumeTrue(Net.isIpv6InterfaceAvailable()); HttpProxy proxy = new HttpProxy("host", 0); proxy.getIncludedAddresses().add("[1::2:3:4]"); proxy.getExcludedAddresses().add("[1::2:3:4]:5"); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ServerConnectionCloseTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ServerConnectionCloseTest.java index 118ecd3af36..f28ba6d07d8 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/ServerConnectionCloseTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ServerConnectionCloseTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,8 +18,6 @@ package org.eclipse.jetty.client; -import static org.junit.jupiter.api.Assertions.assertEquals; - import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -35,9 +33,10 @@ import org.eclipse.jetty.client.util.FutureResponseListener; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.junit.jupiter.api.AfterEach; - import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class ServerConnectionCloseTest { private HttpClient client; @@ -112,22 +111,22 @@ public class ServerConnectionCloseTest consumeRequest(input); OutputStream output = socket.getOutputStream(); - String serverResponse = "" + - "HTTP/1.1 200 OK\r\n" + + String serverResponse = + "HTTP/1.1 200 OK\r\n" + "Connection: close\r\n"; if (chunked) { - serverResponse += "" + - "Transfer-Encoding: chunked\r\n" + + serverResponse += + "Transfer-Encoding: chunked\r\n" + "\r\n"; for (int i = 0; i < 2; ++i) { serverResponse += - Integer.toHexString(content.length()) + "\r\n" + - content + "\r\n"; + Integer.toHexString(content.length()) + "\r\n" + + content + "\r\n"; } - serverResponse += "" + - "0\r\n" + + serverResponse += + "0\r\n" + "\r\n"; } else diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/Socks4ProxyTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/Socks4ProxyTest.java index 41243ec8cec..df56547514c 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/Socks4ProxyTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/Socks4ProxyTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,9 +18,6 @@ package org.eclipse.jetty.client; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.ServerSocketChannel; @@ -30,10 +27,12 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import org.junit.jupiter.api.AfterEach; - import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class Socks4ProxyTest { private ServerSocketChannel server; @@ -73,14 +72,14 @@ public class Socks4ProxyTest String method = "GET"; String path = "/path"; client.newRequest(serverHost, serverPort) - .method(method) - .path(path) - .timeout(5, TimeUnit.SECONDS) - .send(result -> - { - if (result.isSucceeded()) - latch.countDown(); - }); + .method(method) + .path(path) + .timeout(5, TimeUnit.SECONDS) + .send(result -> + { + if (result.isSucceeded()) + latch.countDown(); + }); try (SocketChannel channel = server.accept()) { @@ -107,8 +106,8 @@ public class Socks4ProxyTest assertEquals(method + " " + path, StandardCharsets.UTF_8.decode(buffer).toString()); // Response - String response = "" + - "HTTP/1.1 200 OK\r\n" + + String response = + "HTTP/1.1 200 OK\r\n" + "Content-Length: 0\r\n" + "Connection: close\r\n" + "\r\n"; @@ -130,16 +129,16 @@ public class Socks4ProxyTest int serverPort = proxyPort + 1; // Any port will do String method = "GET"; client.newRequest(serverHost, serverPort) - .method(method) - .path("/path") - .timeout(5, TimeUnit.SECONDS) - .send(result -> - { - if (result.isSucceeded()) - latch.countDown(); - else - result.getFailure().printStackTrace(); - }); + .method(method) + .path("/path") + .timeout(5, TimeUnit.SECONDS) + .send(result -> + { + if (result.isSucceeded()) + latch.countDown(); + else + result.getFailure().printStackTrace(); + }); try (SocketChannel channel = server.accept()) { @@ -165,8 +164,8 @@ public class Socks4ProxyTest assertEquals(method, StandardCharsets.UTF_8.decode(buffer).toString()); // Response - String response = "" + - "HTTP/1.1 200 OK\r\n" + + String response = + "HTTP/1.1 200 OK\r\n" + "Content-Length: 0\r\n" + "Connection: close\r\n" + "\r\n"; diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/TLSServerConnectionCloseTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/TLSServerConnectionCloseTest.java index 8575d5563bd..d1855b3f8f4 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/TLSServerConnectionCloseTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/TLSServerConnectionCloseTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,15 +18,12 @@ package org.eclipse.jetty.client; -import static org.junit.jupiter.api.Assertions.assertEquals; - import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.TimeUnit; - import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocket; @@ -42,14 +39,16 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.EnumSource; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class TLSServerConnectionCloseTest { private HttpClient client; private void startClient() throws Exception { - SslContextFactory sslContextFactory = new SslContextFactory(); - sslContextFactory.setEndpointIdentificationAlgorithm(""); + SslContextFactory sslContextFactory = new SslContextFactory.Client(); + sslContextFactory.setEndpointIdentificationAlgorithm(null); sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks"); sslContextFactory.setKeyStorePassword("storepwd"); @@ -111,22 +110,22 @@ public class TLSServerConnectionCloseTest consumeRequest(input); OutputStream output = sslSocket.getOutputStream(); - String serverResponse = "" + - "HTTP/1.1 200 OK\r\n" + + String serverResponse = + "HTTP/1.1 200 OK\r\n" + "Connection: close\r\n"; if (chunked) { - serverResponse += "" + - "Transfer-Encoding: chunked\r\n" + + serverResponse += + "Transfer-Encoding: chunked\r\n" + "\r\n"; for (int i = 0; i < 2; ++i) { serverResponse += - Integer.toHexString(content.length()) + "\r\n" + - content + "\r\n"; + Integer.toHexString(content.length()) + "\r\n" + + content + "\r\n"; } - serverResponse += "" + - "0\r\n" + + serverResponse += + "0\r\n" + "\r\n"; } else diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ValidatingConnectionPoolTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ValidatingConnectionPoolTest.java index aa9a8381e1c..e9ad7464846 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/ValidatingConnectionPoolTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ValidatingConnectionPoolTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,19 +18,15 @@ package org.eclipse.jetty.client; -import static org.junit.jupiter.api.Assertions.assertEquals; - import java.io.IOException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.client.api.ContentResponse; import org.eclipse.jetty.client.api.Request; -import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP; import org.eclipse.jetty.client.util.FutureResponseListener; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeaderValue; @@ -40,16 +36,18 @@ import org.eclipse.jetty.server.handler.AbstractHandler; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsSource; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class ValidatingConnectionPoolTest extends AbstractHttpClientServerTest { @Override - protected void startClient(final Scenario scenario) throws Exception + public HttpClient newHttpClient(Scenario scenario, HttpClientTransport transport) { long timeout = 1000; - HttpClientTransportOverHTTP transport = new HttpClientTransportOverHTTP(1); transport.setConnectionPoolFactory(destination -> - new ValidatingConnectionPool(destination, destination.getHttpClient().getMaxConnectionsPerDestination(), destination, destination.getHttpClient().getScheduler(), timeout)); - startClient(scenario, transport); + new ValidatingConnectionPool(destination, destination.getHttpClient().getMaxConnectionsPerDestination(), destination, destination.getHttpClient().getScheduler(), timeout)); + + return super.newHttpClient(scenario, transport); } @ParameterizedTest @@ -61,14 +59,14 @@ public class ValidatingConnectionPoolTest extends AbstractHttpClientServerTest client.setMaxConnectionsPerDestination(1); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .send(); + .scheme(scenario.getScheme()) + .send(); assertEquals(200, response.getStatus()); // The second request should be sent after the validating timeout. response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .send(); + .scheme(scenario.getScheme()) + .send(); assertEquals(200, response.getStatus()); } @@ -100,9 +98,9 @@ public class ValidatingConnectionPoolTest extends AbstractHttpClientServerTest }); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path("/redirect") - .send(); + .scheme(scenario.getScheme()) + .path("/redirect") + .send(); assertEquals(200, response.getStatus()); } @@ -148,25 +146,25 @@ public class ValidatingConnectionPoolTest extends AbstractHttpClientServerTest final CountDownLatch latch = new CountDownLatch(1); Request request1 = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path("/one") - .onRequestBegin(r -> + .scheme(scenario.getScheme()) + .path("/one") + .onRequestBegin(r -> + { + try { - try - { - latch.await(); - } - catch (InterruptedException x) - { - r.abort(x); - } - }); + latch.await(); + } + catch (InterruptedException x) + { + r.abort(x); + } + }); FutureResponseListener listener1 = new FutureResponseListener(request1); request1.send(listener1); Request request2 = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .path("/two"); + .scheme(scenario.getScheme()) + .path("/two"); FutureResponseListener listener2 = new FutureResponseListener(request2); request2.send(listener2); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/api/Usage.java b/jetty-client/src/test/java/org/eclipse/jetty/client/api/Usage.java index 8d2d53530f0..30030887a32 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/api/Usage.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/api/Usage.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,10 +18,6 @@ package org.eclipse.jetty.client.api; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.OutputStream; @@ -45,10 +41,13 @@ import org.eclipse.jetty.client.util.OutputStreamContentProvider; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.util.FuturePromise; - import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + @Disabled public class Usage { @@ -76,15 +75,15 @@ public class Usage // Address must be provided, it's the only thing non defaultable Request request = client.newRequest("localhost", 8080) - .scheme("https") - .method(HttpMethod.GET) - .path("/uri") - .version(HttpVersion.HTTP_1_1) - .param("a", "b") - .header("X-Header", "Y-value") - .agent("Jetty HTTP Client") - .idleTimeout(5000, TimeUnit.MILLISECONDS) - .timeout(20, TimeUnit.SECONDS); + .scheme("https") + .method(HttpMethod.GET) + .path("/uri") + .version(HttpVersion.HTTP_1_1) + .param("a", "b") + .header("X-Header", "Y-value") + .agent("Jetty HTTP Client") + .idleTimeout(5000, TimeUnit.MILLISECONDS) + .timeout(20, TimeUnit.SECONDS); ContentResponse response = request.send(); assertEquals(200, response.getStatus()); @@ -100,19 +99,19 @@ public class Usage final CountDownLatch latch = new CountDownLatch(1); client.newRequest("localhost", 8080) - // Send asynchronously - .send(new Response.CompleteListener() - { - @Override - public void onComplete(Result result) + // Send asynchronously + .send(new Response.CompleteListener() { - if (result.isSucceeded()) + @Override + public void onComplete(Result result) { - responseRef.set(result.getResponse()); - latch.countDown(); + if (result.isSucceeded()) + { + responseRef.set(result.getResponse()); + latch.countDown(); + } } - } - }); + }); assertTrue(latch.await(5, TimeUnit.SECONDS)); Response response = responseRef.get(); @@ -137,14 +136,14 @@ public class Usage client.start(); Response response = client.newRequest("localhost", 8080) - // Add a request listener - .listener(new Request.Listener.Adapter() + // Add a request listener + .listener(new Request.Listener.Adapter() + { + @Override + public void onSuccess(Request request) { - @Override - public void onSuccess(Request request) - { - } - }).send(); + } + }).send(); assertEquals(200, response.getStatus()); } @@ -226,10 +225,10 @@ public class Usage client.setFollowRedirects(false); ContentResponse response = client.newRequest("localhost", 8080) - // Follow redirects for this request only - .followRedirects(true) - .timeout(5, TimeUnit.SECONDS) - .send(); + // Follow redirects for this request only + .followRedirects(true) + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(200, response.getStatus()); } @@ -277,9 +276,9 @@ public class Usage InputStream input = new ByteArrayInputStream("content".getBytes(StandardCharsets.UTF_8)); ContentResponse response = client.newRequest("localhost", 8080) - // Provide the content as InputStream - .content(new InputStreamContentProvider(input)) - .send(); + // Provide the content as InputStream + .content(new InputStreamContentProvider(input)) + .send(); assertEquals(200, response.getStatus()); } @@ -294,15 +293,15 @@ public class Usage try (OutputStream output = content.getOutputStream()) { client.newRequest("localhost", 8080) - .content(content) - .send(new Response.CompleteListener() + .content(content) + .send(new Response.CompleteListener() + { + @Override + public void onComplete(Result result) { - @Override - public void onComplete(Result result) - { - assertEquals(200, result.getResponse().getStatus()); - } - }); + assertEquals(200, result.getResponse().getStatus()); + } + }); output.write(new byte[1024]); output.write(new byte[512]); @@ -323,16 +322,16 @@ public class Usage final AtomicBoolean sendContent = new AtomicBoolean(true); DeferredContentProvider async = new DeferredContentProvider(ByteBuffer.wrap(new byte[]{0, 1, 2})); client.newRequest("localhost", 8080) - .content(async) - .send(new Response.Listener.Adapter() + .content(async) + .send(new Response.Listener.Adapter() + { + @Override + public void onBegin(Response response) { - @Override - public void onBegin(Response response) - { - if (response.getStatus() == 404) - sendContent.set(false); - } - }); + if (response.getStatus() == 404) + sendContent.set(false); + } + }); Thread.sleep(100); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/http/HttpDestinationOverHTTPTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/http/HttpDestinationOverHTTPTest.java index 74790daf37f..83d58760876 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/http/HttpDestinationOverHTTPTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/http/HttpDestinationOverHTTPTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,9 +18,6 @@ package org.eclipse.jetty.client.http; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.*; - import java.util.concurrent.CountDownLatch; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeUnit; @@ -39,10 +36,18 @@ import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeaderValue; import org.hamcrest.Matchers; -import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsSource; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class HttpDestinationOverHTTPTest extends AbstractHttpClientServerTest { @ParameterizedTest @@ -51,7 +56,7 @@ public class HttpDestinationOverHTTPTest extends AbstractHttpClientServerTest { start(scenario, new EmptyServerHandler()); - try(HttpDestinationOverHTTP destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", connector.getLocalPort()))) + try (HttpDestinationOverHTTP destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", connector.getLocalPort()))) { destination.start(); DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool(); @@ -71,7 +76,7 @@ public class HttpDestinationOverHTTPTest extends AbstractHttpClientServerTest { start(scenario, new EmptyServerHandler()); - try(HttpDestinationOverHTTP destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", connector.getLocalPort()))) + try (HttpDestinationOverHTTP destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", connector.getLocalPort()))) { destination.start(); @@ -153,7 +158,7 @@ public class HttpDestinationOverHTTPTest extends AbstractHttpClientServerTest { start(scenario, new EmptyServerHandler()); - try(HttpDestinationOverHTTP destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", connector.getLocalPort()))) + try (HttpDestinationOverHTTP destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", connector.getLocalPort()))) { destination.start(); DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool(); @@ -163,14 +168,14 @@ public class HttpDestinationOverHTTPTest extends AbstractHttpClientServerTest connection1 = peekIdleConnection(connectionPool, 5, TimeUnit.SECONDS); assertNotNull(connection1); // Acquire the connection to make it active. - assertSame(connection1, connectionPool.acquire(),"From idle"); + assertSame(connection1, connectionPool.acquire(), "From idle"); } destination.process(connection1); destination.release(connection1); Connection connection2 = connectionPool.acquire(); - assertSame(connection1, connection2,"After release"); + assertSame(connection1, connection2, "After release"); } } @@ -214,34 +219,34 @@ public class HttpDestinationOverHTTPTest extends AbstractHttpClientServerTest // Make one request to open the connection and be sure everything is setup properly ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scheme) - .send(); + .scheme(scheme) + .send(); assertEquals(200, response.getStatus()); // Send another request that is sent immediately CountDownLatch successLatch = new CountDownLatch(1); CountDownLatch failureLatch = new CountDownLatch(1); client.newRequest("localhost", connector.getLocalPort()) - .scheme(scheme) - .path("/one") - .onRequestQueued(request -> - { - // This request exceeds the maximum queued, should fail - client.newRequest("localhost", connector.getLocalPort()) - .scheme(scheme) - .path("/two") - .send(result -> - { - assertTrue(result.isFailed()); - assertThat(result.getRequestFailure(), Matchers.instanceOf(RejectedExecutionException.class)); - failureLatch.countDown(); - }); - }) - .send(result -> - { - if (result.isSucceeded()) - successLatch.countDown(); - }); + .scheme(scheme) + .path("/one") + .onRequestQueued(request -> + { + // This request exceeds the maximum queued, should fail + client.newRequest("localhost", connector.getLocalPort()) + .scheme(scheme) + .path("/two") + .send(result -> + { + assertTrue(result.isFailed()); + assertThat(result.getRequestFailure(), Matchers.instanceOf(RejectedExecutionException.class)); + failureLatch.countDown(); + }); + }) + .send(result -> + { + if (result.isSucceeded()) + successLatch.countDown(); + }); assertTrue(failureLatch.await(5, TimeUnit.SECONDS)); assertTrue(successLatch.await(5, TimeUnit.SECONDS)); @@ -258,9 +263,9 @@ public class HttpDestinationOverHTTPTest extends AbstractHttpClientServerTest Destination destinationBefore = client.getDestination(scenario.getScheme(), host, port); ContentResponse response = client.newRequest(host, port) - .scheme(scenario.getScheme()) - .header(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString()) - .send(); + .scheme(scenario.getScheme()) + .header(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString()) + .send(); assertEquals(200, response.getStatus()); @@ -270,9 +275,9 @@ public class HttpDestinationOverHTTPTest extends AbstractHttpClientServerTest client.setRemoveIdleDestinations(true); response = client.newRequest(host, port) - .scheme(scenario.getScheme()) - .header(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString()) - .send(); + .scheme(scenario.getScheme()) + .header(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString()) + .send(); assertEquals(200, response.getStatus()); @@ -293,14 +298,7 @@ public class HttpDestinationOverHTTPTest extends AbstractHttpClientServerTest server.stop(); Request request = client.newRequest(host, port).scheme(scenario.getScheme()); - try - { - request.send(); - fail("Request to a closed port must fail"); - } - catch (Exception expected) - { - } + assertThrows(Exception.class, () -> request.send()); long deadline = System.nanoTime() + TimeUnit.SECONDS.toNanos(1); while (!client.getDestinations().isEmpty() && System.nanoTime() < deadline) diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTPTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTPTest.java index 3c66cbfea36..a31d2639f0a 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTPTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTPTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,15 +18,6 @@ package org.eclipse.jetty.client.http; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.instanceOf; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertSame; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.EOFException; import java.nio.charset.StandardCharsets; import java.util.Collections; @@ -42,6 +33,7 @@ import org.eclipse.jetty.client.HttpResponseException; import org.eclipse.jetty.client.Origin; import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.util.FutureResponseListener; +import org.eclipse.jetty.http.BadMessageException; import org.eclipse.jetty.http.HttpCompliance; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeader; @@ -53,13 +45,22 @@ 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.instanceOf; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class HttpReceiverOverHTTPTest -{ +{ private HttpClient client; private HttpDestinationOverHTTP destination; private ByteArrayEndPoint endPoint; private HttpConnectionOverHTTP connection; - + public static Stream complianceModes() throws Exception { return Stream.of( @@ -68,7 +69,7 @@ public class HttpReceiverOverHTTPTest HttpCompliance.RFC7230_LEGACY ).map(Arguments::of); } - + public void init(HttpCompliance compliance) throws Exception { client = new HttpClient(); @@ -104,8 +105,8 @@ public class HttpReceiverOverHTTPTest public void test_Receive_NoResponseContent(HttpCompliance compliance) throws Exception { init(compliance); - endPoint.addInput("" + - "HTTP/1.1 200 OK\r\n" + + endPoint.addInput( + "HTTP/1.1 200 OK\r\n" + "Content-length: 0\r\n" + "\r\n"); HttpExchange exchange = newExchange(); @@ -129,8 +130,8 @@ public class HttpReceiverOverHTTPTest { init(compliance); String content = "0123456789ABCDEF"; - endPoint.addInput("" + - "HTTP/1.1 200 OK\r\n" + + endPoint.addInput( + "HTTP/1.1 200 OK\r\n" + "Content-length: " + content.length() + "\r\n" + "\r\n" + content); @@ -158,8 +159,8 @@ public class HttpReceiverOverHTTPTest init(compliance); String content1 = "0123456789"; String content2 = "ABCDEF"; - endPoint.addInput("" + - "HTTP/1.1 200 OK\r\n" + + endPoint.addInput( + "HTTP/1.1 200 OK\r\n" + "Content-length: " + (content1.length() + content2.length()) + "\r\n" + "\r\n" + content1); @@ -169,7 +170,7 @@ public class HttpReceiverOverHTTPTest endPoint.addInputEOF(); connection.getHttpChannel().receive(); - ExecutionException e = assertThrows(ExecutionException.class, ()->listener.get(5, TimeUnit.SECONDS)); + ExecutionException e = assertThrows(ExecutionException.class, () -> listener.get(5, TimeUnit.SECONDS)); assertThat(e.getCause(), instanceOf(EOFException.class)); } @@ -178,8 +179,8 @@ public class HttpReceiverOverHTTPTest public void test_Receive_ResponseContent_IdleTimeout(HttpCompliance compliance) throws Exception { init(compliance); - endPoint.addInput("" + - "HTTP/1.1 200 OK\r\n" + + endPoint.addInput( + "HTTP/1.1 200 OK\r\n" + "Content-length: 1\r\n" + "\r\n"); HttpExchange exchange = newExchange(); @@ -190,7 +191,7 @@ public class HttpReceiverOverHTTPTest Thread.sleep(100); connection.onIdleExpired(); - ExecutionException e = assertThrows(ExecutionException.class, ()->listener.get(5, TimeUnit.SECONDS)); + ExecutionException e = assertThrows(ExecutionException.class, () -> listener.get(5, TimeUnit.SECONDS)); assertThat(e.getCause(), instanceOf(TimeoutException.class)); } @@ -199,16 +200,18 @@ public class HttpReceiverOverHTTPTest public void test_Receive_BadResponse(HttpCompliance compliance) throws Exception { init(compliance); - endPoint.addInput("" + - "HTTP/1.1 200 OK\r\n" + + endPoint.addInput( + "HTTP/1.1 200 OK\r\n" + "Content-length: A\r\n" + "\r\n"); HttpExchange exchange = newExchange(); FutureResponseListener listener = (FutureResponseListener)exchange.getResponseListeners().get(0); connection.getHttpChannel().receive(); - ExecutionException e = assertThrows(ExecutionException.class, ()->listener.get(5, TimeUnit.SECONDS)); + ExecutionException e = assertThrows(ExecutionException.class, () -> listener.get(5, TimeUnit.SECONDS)); assertThat(e.getCause(), instanceOf(HttpResponseException.class)); + assertThat(e.getCause().getCause(), instanceOf(BadMessageException.class)); + assertThat(e.getCause().getCause().getCause(), instanceOf(NumberFormatException.class)); } @ParameterizedTest @@ -244,10 +247,10 @@ public class HttpReceiverOverHTTPTest } }; endPoint.setConnection(connection); - + // Partial response to trigger the call to fillInterested(). - endPoint.addInput("" + - "HTTP/1.1 200 OK\r\n" + + endPoint.addInput( + "HTTP/1.1 200 OK\r\n" + "Content-Length: 1\r\n" + "\r\n"); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/http/HttpSenderOverHTTPTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/http/HttpSenderOverHTTPTest.java index 7abe61bbfe6..59e1936c664 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/http/HttpSenderOverHTTPTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/http/HttpSenderOverHTTPTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,9 +18,6 @@ package org.eclipse.jetty.client.http; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.net.URI; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; @@ -39,11 +36,13 @@ import org.eclipse.jetty.io.ByteArrayEndPoint; import org.eclipse.jetty.util.Promise; import org.hamcrest.Matchers; import org.junit.jupiter.api.AfterEach; - import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledIfSystemProperty; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class HttpSenderOverHTTPTest { private HttpClient client; @@ -257,7 +256,7 @@ public class HttpSenderOverHTTPTest String requestString = endPoint.takeOutputString(); assertTrue(requestString.startsWith("GET ")); - assertThat(requestString,Matchers.endsWith("\r\n\r\n" + content1 + content2)); + assertThat(requestString, Matchers.endsWith("\r\n\r\n" + content1 + content2)); assertTrue(headersLatch.await(5, TimeUnit.SECONDS)); assertTrue(successLatch.await(5, TimeUnit.SECONDS)); } diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/jmx/HttpClientJMXTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/jmx/HttpClientJMXTest.java index e03afecd792..c5d254cc3c3 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/jmx/HttpClientJMXTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/jmx/HttpClientJMXTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,21 +18,19 @@ package org.eclipse.jetty.client.jmx; -import static org.junit.jupiter.api.Assertions.assertEquals; - import java.lang.management.ManagementFactory; import java.util.Locale; import java.util.Set; - import javax.management.MBeanServer; import javax.management.ObjectName; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.io.SelectorManager; import org.eclipse.jetty.jmx.MBeanContainer; - import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class HttpClientJMXTest { @Test @@ -62,7 +60,9 @@ public class HttpClientJMXTest pattern = new ObjectName(domain + ":*"); objectNames = mbeanServer.queryNames(pattern, null); for (ObjectName oName : objectNames) + { assertEquals(name, oName.getKeyProperty("context")); + } } finally { diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/NeedWantClientAuthTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/NeedWantClientAuthTest.java index 12aca96fec7..5e68a8e365f 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/NeedWantClientAuthTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/NeedWantClientAuthTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,15 +18,9 @@ package org.eclipse.jetty.client.ssl; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.security.cert.Certificate; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; - import javax.net.ssl.SSLException; import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.SSLSession; @@ -43,9 +37,13 @@ import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.hamcrest.Matchers; import org.junit.jupiter.api.AfterEach; - import org.junit.jupiter.api.Test; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + /** * In order to work, client authentication needs a certificate * signed by a CA that also signed the server certificate. @@ -81,10 +79,9 @@ public class NeedWantClientAuthTest client.start(); } - private SslContextFactory createSslContextFactory() + private SslContextFactory.Server createServerSslContextFactory() { - SslContextFactory sslContextFactory = new SslContextFactory(); - sslContextFactory.setEndpointIdentificationAlgorithm(""); + SslContextFactory.Server sslContextFactory = new SslContextFactory.Server(); sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks"); sslContextFactory.setKeyStorePassword("storepwd"); return sslContextFactory; @@ -102,16 +99,16 @@ public class NeedWantClientAuthTest @Test public void testWantClientAuthWithoutAuth() throws Exception { - SslContextFactory serverSSL = createSslContextFactory(); + SslContextFactory.Server serverSSL = createServerSslContextFactory(); serverSSL.setWantClientAuth(true); startServer(serverSSL, new EmptyServerHandler()); - SslContextFactory clientSSL = new SslContextFactory(true); + SslContextFactory clientSSL = new SslContextFactory.Client(true); startClient(clientSSL); ContentResponse response = client.newRequest("https://localhost:" + connector.getLocalPort()) - .timeout(5, TimeUnit.SECONDS) - .send(); + .timeout(10, TimeUnit.SECONDS) + .send(); assertEquals(HttpStatus.OK_200, response.getStatus()); } @@ -119,7 +116,7 @@ public class NeedWantClientAuthTest @Test public void testWantClientAuthWithAuth() throws Exception { - SslContextFactory serverSSL = createSslContextFactory(); + SslContextFactory.Server serverSSL = createServerSslContextFactory(); serverSSL.setWantClientAuth(true); startServer(serverSSL, new EmptyServerHandler()); CountDownLatch handshakeLatch = new CountDownLatch(1); @@ -143,17 +140,17 @@ public class NeedWantClientAuthTest } }); - SslContextFactory clientSSL = new SslContextFactory(true); + SslContextFactory clientSSL = new SslContextFactory.Client(true); clientSSL.setKeyStorePath("src/test/resources/client_keystore.jks"); clientSSL.setKeyStorePassword("storepwd"); startClient(clientSSL); ContentResponse response = client.newRequest("https://localhost:" + connector.getLocalPort()) - .timeout(5, TimeUnit.SECONDS) - .send(); + .timeout(10, TimeUnit.SECONDS) + .send(); assertEquals(HttpStatus.OK_200, response.getStatus()); - assertTrue(handshakeLatch.await(5, TimeUnit.SECONDS)); + assertTrue(handshakeLatch.await(10, TimeUnit.SECONDS)); } @Test @@ -166,11 +163,11 @@ public class NeedWantClientAuthTest // The server still sends bad_certificate to the client, but the client handshake has already // completed successfully its TLS handshake. - SslContextFactory serverSSL = createSslContextFactory(); + SslContextFactory.Server serverSSL = createServerSslContextFactory(); serverSSL.setNeedClientAuth(true); startServer(serverSSL, new EmptyServerHandler()); - SslContextFactory clientSSL = new SslContextFactory(true); + SslContextFactory clientSSL = new SslContextFactory.Client(true); startClient(clientSSL); CountDownLatch handshakeLatch = new CountDownLatch(1); client.addBean(new SslHandshakeListener() @@ -192,25 +189,25 @@ public class NeedWantClientAuthTest CountDownLatch latch = new CountDownLatch(1); client.newRequest("https://localhost:" + connector.getLocalPort()) - .timeout(5, TimeUnit.SECONDS) - .send(result -> + .timeout(10, TimeUnit.SECONDS) + .send(result -> + { + if (result.isFailed()) { - if (result.isFailed()) - { - Throwable failure = result.getFailure(); - if (failure instanceof SSLException) - latch.countDown(); - } - }); + Throwable failure = result.getFailure(); + if (failure instanceof SSLException) + latch.countDown(); + } + }); - assertTrue(handshakeLatch.await(5, TimeUnit.SECONDS)); - assertTrue(latch.await(5, TimeUnit.SECONDS)); + assertTrue(handshakeLatch.await(10, TimeUnit.SECONDS)); + assertTrue(latch.await(10, TimeUnit.SECONDS)); } @Test public void testNeedClientAuthWithAuth() throws Exception { - SslContextFactory serverSSL = createSslContextFactory(); + SslContextFactory.Server serverSSL = createServerSslContextFactory(); serverSSL.setNeedClientAuth(true); startServer(serverSSL, new EmptyServerHandler()); CountDownLatch handshakeLatch = new CountDownLatch(1); @@ -234,16 +231,16 @@ public class NeedWantClientAuthTest } }); - SslContextFactory clientSSL = new SslContextFactory(true); + SslContextFactory clientSSL = new SslContextFactory.Client(true); clientSSL.setKeyStorePath("src/test/resources/client_keystore.jks"); clientSSL.setKeyStorePassword("storepwd"); startClient(clientSSL); ContentResponse response = client.newRequest("https://localhost:" + connector.getLocalPort()) - .timeout(5, TimeUnit.SECONDS) - .send(); + .timeout(10, TimeUnit.SECONDS) + .send(); assertEquals(HttpStatus.OK_200, response.getStatus()); - assertTrue(handshakeLatch.await(5, TimeUnit.SECONDS)); + assertTrue(handshakeLatch.await(10, TimeUnit.SECONDS)); } } diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesClientTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesClientTest.java index a738af91c95..75ad9abcf7f 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesClientTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesClientTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,11 +18,6 @@ package org.eclipse.jetty.client.ssl; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.BufferedReader; import java.io.File; import java.io.InputStream; @@ -35,7 +30,6 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; - import javax.net.ssl.SSLContext; import javax.net.ssl.SSLServerSocket; import javax.net.ssl.SSLSocket; @@ -54,9 +48,13 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledOnJre; import org.junit.jupiter.api.condition.JRE; -/* This whole test is very specific to how TLS < 1.3 works. - * Starting in Java 11, TLS/1.3 is now enabled by default. - */ +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +// This whole test is very specific to how TLS < 1.3 works. +// Starting in Java 11, TLS/1.3 is now enabled by default. @EnabledOnJre({JRE.JAVA_8, JRE.JAVA_9, JRE.JAVA_10}) public class SslBytesClientTest extends SslBytesTest { @@ -71,7 +69,7 @@ public class SslBytesClientTest extends SslBytesTest { threadPool = Executors.newCachedThreadPool(); - sslContextFactory = new SslContextFactory(true); + sslContextFactory = new SslContextFactory.Client(true); client = new HttpClient(sslContextFactory); client.setMaxConnectionsPerDestination(1); File keyStore = MavenTestingUtils.getTestResourceFile("keystore.jks"); @@ -164,13 +162,15 @@ public class SslBytesClientTest extends SslBytesTest String line = reader.readLine(); assertTrue(line.startsWith("GET")); while (line.length() > 0) + { line = reader.readLine(); + } // Write response OutputStream output = server.getOutputStream(); output.write(("HTTP/1.1 200 OK\r\n" + - "Content-Length: 0\r\n" + - "\r\n").getBytes(StandardCharsets.UTF_8)); + "Content-Length: 0\r\n" + + "\r\n").getBytes(StandardCharsets.UTF_8)); output.flush(); assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS)); @@ -207,7 +207,9 @@ public class SslBytesClientTest extends SslBytesTest String line = reader.readLine(); assertTrue(line.startsWith("GET")); while (line.length() > 0) + { line = reader.readLine(); + } OutputStream serverOutput = server.getOutputStream(); byte[] data1 = new byte[1024]; @@ -218,10 +220,10 @@ public class SslBytesClientTest extends SslBytesTest final String content2 = new String(data2, StandardCharsets.UTF_8); // Write first part of the response serverOutput.write(("HTTP/1.1 200 OK\r\n" + - "Content-Type: text/plain\r\n" + - "Content-Length: " + (content1.length() + content2.length()) + "\r\n" + - "\r\n" + - content1).getBytes(StandardCharsets.UTF_8)); + "Content-Type: text/plain\r\n" + + "Content-Length: " + (content1.length() + content2.length()) + "\r\n" + + "\r\n" + + content1).getBytes(StandardCharsets.UTF_8)); serverOutput.flush(); assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS)); @@ -244,7 +246,7 @@ public class SslBytesClientTest extends SslBytesTest // Trigger a read to have the server write the final renegotiation steps server.setSoTimeout(100); - assertThrows(SocketTimeoutException.class, ()->serverInput.read()); + assertThrows(SocketTimeoutException.class, () -> serverInput.read()); // Renegotiation Handshake record = proxy.readFromServer(); @@ -315,7 +317,9 @@ public class SslBytesClientTest extends SslBytesTest String line = reader.readLine(); assertTrue(line.startsWith("GET")); while (line.length() > 0) + { line = reader.readLine(); + } OutputStream serverOutput = server.getOutputStream(); byte[] data1 = new byte[1024]; @@ -326,10 +330,10 @@ public class SslBytesClientTest extends SslBytesTest final String content2 = new String(data2, StandardCharsets.UTF_8); // Write first part of the response serverOutput.write(("HTTP/1.1 200 OK\r\n" + - "Content-Type: text/plain\r\n" + - "Content-Length: " + (content1.length() + content2.length()) + "\r\n" + - "\r\n" + - content1).getBytes(StandardCharsets.UTF_8)); + "Content-Type: text/plain\r\n" + + "Content-Length: " + (content1.length() + content2.length()) + "\r\n" + + "\r\n" + + content1).getBytes(StandardCharsets.UTF_8)); serverOutput.flush(); assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS)); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesServerTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesServerTest.java index 92c3ff6ef8c..7ea3318b796 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesServerTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesServerTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,12 +18,6 @@ package org.eclipse.jetty.client.ssl; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.*; -import static org.junit.jupiter.api.Assumptions.assumeTrue; -import static org.junit.jupiter.api.condition.OS.LINUX; -import static org.junit.jupiter.api.condition.OS.WINDOWS; - import java.io.BufferedReader; import java.io.EOFException; import java.io.File; @@ -45,7 +39,6 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Matcher; import java.util.regex.Pattern; - import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLSocket; @@ -72,20 +65,31 @@ import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.SslConnectionFactory; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; -import org.eclipse.jetty.util.JavaVersion; import org.eclipse.jetty.util.component.Dumpable; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.hamcrest.Matchers; - import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.DisabledOnJre; import org.junit.jupiter.api.condition.DisabledOnOs; +import org.junit.jupiter.api.condition.EnabledOnJre; import org.junit.jupiter.api.condition.EnabledOnOs; import org.junit.jupiter.api.condition.JRE; +import static org.hamcrest.MatcherAssert.assertThat; +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; +import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.condition.OS.LINUX; +import static org.junit.jupiter.api.condition.OS.WINDOWS; + +// This whole test is very specific to how TLS < 1.3 works. +@EnabledOnJre({JRE.JAVA_8, JRE.JAVA_9, JRE.JAVA_10}) public class SslBytesServerTest extends SslBytesTest { private final AtomicInteger sslFills = new AtomicInteger(); @@ -101,8 +105,6 @@ public class SslBytesServerTest extends SslBytesTest private SimpleProxy proxy; private Runnable idleHook; - // This whole test is very specific to how TLS < 1.3 works. - @DisabledOnJre( JRE.JAVA_11 ) @BeforeEach public void init() throws Exception { @@ -114,9 +116,9 @@ public class SslBytesServerTest extends SslBytesTest sslFlushes.set(0); httpParses.set(0); serverEndPoint.set(null); - + File keyStore = MavenTestingUtils.getTestResourceFile("keystore.jks"); - sslContextFactory = new SslContextFactory(); + sslContextFactory = new SslContextFactory.Server(); sslContextFactory.setKeyStorePath(keyStore.getAbsolutePath()); sslContextFactory.setKeyStorePassword("storepwd"); @@ -125,12 +127,12 @@ public class SslBytesServerTest extends SslBytesTest @Override public Connection newConnection(Connector connector, EndPoint endPoint) { - return configure(new HttpConnection(getHttpConfiguration(), connector, endPoint,getHttpCompliance(),isRecordHttpComplianceViolations()) + return configure(new HttpConnection(getHttpConfiguration(), connector, endPoint, getHttpCompliance(), isRecordHttpComplianceViolations()) { @Override protected HttpParser newHttpParser(HttpCompliance compliance) { - return new HttpParser(newRequestHandler(), getHttpConfiguration().getRequestHeaderSize(),compliance) + return new HttpParser(newRequestHandler(), getHttpConfiguration().getRequestHeaderSize(), compliance) { @Override public boolean parseNext(ByteBuffer buffer) @@ -184,12 +186,12 @@ public class SslBytesServerTest extends SslBytesTest } }; - ServerConnector connector = new ServerConnector(server, null,null,null,1,1,sslFactory, httpFactory) + ServerConnector connector = new ServerConnector(server, null, null, null, 1, 1, sslFactory, httpFactory) { @Override protected ChannelEndPoint newEndPoint(SocketChannel channel, ManagedSelector selectSet, SelectionKey key) throws IOException { - ChannelEndPoint endp = super.newEndPoint(channel,selectSet,key); + ChannelEndPoint endp = super.newEndPoint(channel, selectSet, key); serverEndPoint.set(endp); return endp; } @@ -481,10 +483,10 @@ public class SslBytesServerTest extends SslBytesTest // Socket close record = proxy.readFromServer(); - if (record!=null) + if (record != null) { - assertEquals(record.getType(),Type.ALERT); - + assertEquals(record.getType(), Type.ALERT); + // Now should be a raw close record = proxy.readFromServer(); assertNull(record, String.valueOf(record)); @@ -579,8 +581,8 @@ public class SslBytesServerTest extends SslBytesTest threadPool.submit(() -> { OutputStream clientOutput = client.getOutputStream(); - clientOutput.write(("" + - "GET / HTTP/1.1\r\n" + + clientOutput.write(( + "GET / HTTP/1.1\r\n" + "Host: localhost\r\n" + "\r\n").getBytes(StandardCharsets.UTF_8)); clientOutput.flush(); @@ -617,8 +619,8 @@ public class SslBytesServerTest extends SslBytesTest Future request = threadPool.submit(() -> { OutputStream clientOutput = client.getOutputStream(); - clientOutput.write(("" + - "GET / HTTP/1.1\r\n" + + clientOutput.write(( + "GET / HTTP/1.1\r\n" + "Host: localhost\r\n" + "\r\n").getBytes(StandardCharsets.UTF_8)); clientOutput.flush(); @@ -668,7 +670,9 @@ public class SslBytesServerTest extends SslBytesTest // Client Hello TLSRecord record = proxy.readFromClient(); for (byte b : record.getBytes()) + { proxy.flushToServer(5, b); + } // Server Hello + Certificate + Server Done record = proxy.readFromServer(); @@ -677,17 +681,23 @@ public class SslBytesServerTest extends SslBytesTest // Client Key Exchange record = proxy.readFromClient(); for (byte b : record.getBytes()) - proxy.flushToServer(5,b); + { + proxy.flushToServer(5, b); + } // Change Cipher Spec record = proxy.readFromClient(); for (byte b : record.getBytes()) + { proxy.flushToServer(5, b); + } // Client Done record = proxy.readFromClient(); for (byte b : record.getBytes()) + { proxy.flushToServer(5, b); + } // Change Cipher Spec record = proxy.readFromServer(); @@ -702,8 +712,8 @@ public class SslBytesServerTest extends SslBytesTest Future request = threadPool.submit(() -> { OutputStream clientOutput = client.getOutputStream(); - clientOutput.write(("" + - "GET / HTTP/1.1\r\n" + + clientOutput.write(( + "GET / HTTP/1.1\r\n" + "Host: localhost\r\n" + "\r\n").getBytes(StandardCharsets.UTF_8)); clientOutput.flush(); @@ -713,7 +723,9 @@ public class SslBytesServerTest extends SslBytesTest // Application data record = proxy.readFromClient(); for (byte b : record.getBytes()) + { proxy.flushToServer(5, b); + } assertNull(request.get(1, TimeUnit.SECONDS)); // Application data @@ -744,7 +756,9 @@ public class SslBytesServerTest extends SslBytesTest // Close Alert record = proxy.readFromClient(); for (byte b : record.getBytes()) + { proxy.flushToServer(5, b); + } // Socket close record = proxy.readFromClient(); assertNull(record, String.valueOf(record)); @@ -753,10 +767,10 @@ public class SslBytesServerTest extends SslBytesTest // Socket close record = proxy.readFromServer(); // Raw close or alert - if (record!=null) + if (record != null) { - assertEquals(record.getType(),Type.ALERT); - + assertEquals(record.getType(), Type.ALERT); + // Now should be a raw close record = proxy.readFromServer(); assertNull(record, String.valueOf(record)); @@ -776,8 +790,8 @@ public class SslBytesServerTest extends SslBytesTest Future request = threadPool.submit(() -> { OutputStream clientOutput = client.getOutputStream(); - clientOutput.write(("" + - "GET / HTTP/1.1\r\n" + + clientOutput.write(( + "GET / HTTP/1.1\r\n" + "Host: localhost\r\n" + "\r\n").getBytes(StandardCharsets.UTF_8)); clientOutput.flush(); @@ -809,10 +823,10 @@ public class SslBytesServerTest extends SslBytesTest // Socket close record = proxy.readFromServer(); - if (record!=null) + if (record != null) { - assertEquals(record.getType(),Type.ALERT); - + assertEquals(record.getType(), Type.ALERT); + // Now should be a raw close record = proxy.readFromServer(); assertNull(record, String.valueOf(record)); @@ -847,8 +861,8 @@ public class SslBytesServerTest extends SslBytesTest Future request = threadPool.submit(() -> { OutputStream clientOutput = client.getOutputStream(); - clientOutput.write(("" + - "GET / HTTP/1.1\r\n" + + clientOutput.write(( + "GET / HTTP/1.1\r\n" + "Host: localhost\r\n" + "\r\n").getBytes(StandardCharsets.UTF_8)); clientOutput.flush(); @@ -880,10 +894,10 @@ public class SslBytesServerTest extends SslBytesTest // Socket close record = proxy.readFromServer(); - if (record!=null) + if (record != null) { - assertEquals(record.getType(),Type.ALERT); - + assertEquals(record.getType(), Type.ALERT); + // Now should be a raw close record = proxy.readFromServer(); assertNull(record, String.valueOf(record)); @@ -913,8 +927,8 @@ public class SslBytesServerTest extends SslBytesTest Future request = threadPool.submit(() -> { OutputStream clientOutput = client.getOutputStream(); - clientOutput.write(("" + - "GET / HTTP/1.1\r\n" + + clientOutput.write(( + "GET / HTTP/1.1\r\n" + "Host: localhost\r\n" + "\r\n").getBytes(StandardCharsets.UTF_8)); clientOutput.flush(); @@ -938,10 +952,10 @@ public class SslBytesServerTest extends SslBytesTest // Expect raw close from server OR ALERT record = proxy.readFromServer(); // TODO check that this is OK? - if (record!=null) + if (record != null) { - assertEquals(record.getType(),Type.ALERT); - + assertEquals(record.getType(), Type.ALERT); + // Now should be a raw close record = proxy.readFromServer(); assertNull(record, String.valueOf(record)); @@ -968,8 +982,8 @@ public class SslBytesServerTest extends SslBytesTest Future request = threadPool.submit(() -> { OutputStream clientOutput = client.getOutputStream(); - clientOutput.write(("" + - "GET / HTTP/1.1\r\n" + + clientOutput.write(( + "GET / HTTP/1.1\r\n" + "Host: localhost\r\n" + "\r\n").getBytes(StandardCharsets.UTF_8)); clientOutput.flush(); @@ -991,10 +1005,10 @@ public class SslBytesServerTest extends SslBytesTest // Expect raw close from server record = proxy.readFromServer(); - if (record!=null) + if (record != null) { - assertEquals(record.getType(),Type.ALERT); - + assertEquals(record.getType(), Type.ALERT); + // Now should be a raw close record = proxy.readFromServer(); assertNull(record, String.valueOf(record)); @@ -1025,8 +1039,8 @@ public class SslBytesServerTest extends SslBytesTest Future request = threadPool.submit(() -> { OutputStream clientOutput = client.getOutputStream(); - clientOutput.write(("" + - "GET /echo HTTP/1.1\r\n" + + clientOutput.write(( + "GET /echo HTTP/1.1\r\n" + "Host: localhost\r\n" + "Content-Length: " + content.length() + "\r\n" + "\r\n" + @@ -1080,8 +1094,8 @@ public class SslBytesServerTest extends SslBytesTest Future request = threadPool.submit(() -> { OutputStream clientOutput = client.getOutputStream(); - clientOutput.write(("" + - "GET /echo_suppress_exception HTTP/1.1\r\n" + + clientOutput.write(( + "GET /echo_suppress_exception HTTP/1.1\r\n" + "Host: localhost\r\n" + "Content-Length: " + content.length() + "\r\n" + "\r\n" + @@ -1137,8 +1151,8 @@ public class SslBytesServerTest extends SslBytesTest Future request = threadPool.submit(() -> { OutputStream clientOutput = client.getOutputStream(); - clientOutput.write(("" + - "GET / HTTP/1.1\r\n" + + clientOutput.write(( + "GET / HTTP/1.1\r\n" + "Host: localhost\r\n" + "\r\n").getBytes(StandardCharsets.UTF_8)); clientOutput.flush(); @@ -1179,10 +1193,10 @@ public class SslBytesServerTest extends SslBytesTest // Socket close record = proxy.readFromServer(); - if (record!=null) + if (record != null) { - assertEquals(record.getType(),Type.ALERT); - + assertEquals(record.getType(), Type.ALERT); + // Now should be a raw close record = proxy.readFromServer(); assertNull(record, String.valueOf(record)); @@ -1209,8 +1223,8 @@ public class SslBytesServerTest extends SslBytesTest Future request = threadPool.submit(() -> { OutputStream clientOutput = client.getOutputStream(); - clientOutput.write(("" + - "POST / HTTP/1.1\r\n" + + clientOutput.write(( + "POST / HTTP/1.1\r\n" + "Host: localhost\r\n" + "Content-Type: text/plain\r\n" + "Content-Length: " + content.length() + "\r\n" + @@ -1271,8 +1285,8 @@ public class SslBytesServerTest extends SslBytesTest Future request = threadPool.submit(() -> { OutputStream clientOutput = client.getOutputStream(); - clientOutput.write(("" + - "POST / HTTP/1.1\r\n" + + clientOutput.write(( + "POST / HTTP/1.1\r\n" + "Host: localhost\r\n" + "Content-Type: text/plain\r\n" + "Content-Length: " + content.length() + "\r\n" + @@ -1350,8 +1364,8 @@ public class SslBytesServerTest extends SslBytesTest // Write only part of the body automaticProxyFlow = proxy.startAutomaticFlow(); - clientOutput.write(("" + - "POST / HTTP/1.1\r\n" + + clientOutput.write(( + "POST / HTTP/1.1\r\n" + "Host: localhost\r\n" + "Content-Type: text/plain\r\n" + "Content-Length: " + (content1.length() + content2.length()) + "\r\n" + @@ -1373,15 +1387,17 @@ public class SslBytesServerTest extends SslBytesTest proxy.flushToServer(record); // Renegotiation not allowed, server has closed - loop: while(true) + loop: + while (true) { record = proxy.readFromServer(); - if (record==null) + if (record == null) break; - switch(record.getType()) + switch (record.getType()) { case APPLICATION: fail("application data not allows after renegotiate"); + return; // this is just to avoid checkstyle warning case ALERT: break loop; default: @@ -1425,8 +1441,8 @@ public class SslBytesServerTest extends SslBytesTest // Write only part of the body automaticProxyFlow = proxy.startAutomaticFlow(); - clientOutput.write(("" + - "POST / HTTP/1.1\r\n" + + clientOutput.write(( + "POST / HTTP/1.1\r\n" + "Host: localhost\r\n" + "Content-Type: text/plain\r\n" + "Content-Length: " + (content1.length() + content2.length()) + "\r\n" + @@ -1465,7 +1481,7 @@ public class SslBytesServerTest extends SslBytesTest // Trigger a read to have the client write the final renegotiation steps client.setSoTimeout(100); - assertThrows(SocketTimeoutException.class, ()->client.getInputStream().read()); + assertThrows(SocketTimeoutException.class, () -> client.getInputStream().read()); // Renegotiation Change Cipher record = proxy.readFromClient(); @@ -1544,8 +1560,8 @@ public class SslBytesServerTest extends SslBytesTest // Write only part of the body automaticProxyFlow = proxy.startAutomaticFlow(); - clientOutput.write(("" + - "POST / HTTP/1.1\r\n" + + clientOutput.write(( + "POST / HTTP/1.1\r\n" + "Host: localhost\r\n" + "Content-Type: text/plain\r\n" + "Content-Length: " + (content1.length() + content2.length()) + "\r\n" + @@ -1590,7 +1606,7 @@ public class SslBytesServerTest extends SslBytesTest // Trigger a read to have the client write the final renegotiation steps client.setSoTimeout(100); - assertThrows(SocketTimeoutException.class, ()->client.getInputStream().read()); + assertThrows(SocketTimeoutException.class, () -> client.getInputStream().read()); // Renegotiation Change Cipher record = proxy.readFromClient(); @@ -1683,8 +1699,8 @@ public class SslBytesServerTest extends SslBytesTest Arrays.fill(data, (byte)'Y'); String content = new String(data, StandardCharsets.UTF_8); automaticProxyFlow = proxy.startAutomaticFlow(); - clientOutput.write(("" + - "POST / HTTP/1.1\r\n" + + clientOutput.write(( + "POST / HTTP/1.1\r\n" + "Host: localhost\r\n" + "Content-Type: text/plain\r\n" + "Content-Length: " + content.length() + "\r\n" + @@ -1762,13 +1778,13 @@ public class SslBytesServerTest extends SslBytesTest idleHook = () -> { - if (latch.getCount()==0) + if (latch.getCount() == 0) return; try { // Send request - clientOutput.write(("" + - "GET / HTTP/1.1\r\n" + + clientOutput.write(( + "GET / HTTP/1.1\r\n" + "Host: localhost\r\n" + "\r\n").getBytes(StandardCharsets.UTF_8)); clientOutput.flush(); @@ -1787,7 +1803,7 @@ public class SslBytesServerTest extends SslBytesTest assertTrue(latch.await(idleTimeout * 2, TimeUnit.MILLISECONDS)); - // Be sure that the server sent a SSL close alert + // Be sure that the server sent an SSL close alert TLSRecord record = proxy.readFromServer(); assertNotNull(record); assertEquals(TLSRecord.Type.ALERT, record.getType()); @@ -1853,9 +1869,9 @@ public class SslBytesServerTest extends SslBytesTest // Socket close record = proxy.readFromServer(); - if (record!=null) + if (record != null) { - assertEquals(record.getType(),Type.ALERT); + assertEquals(record.getType(), Type.ALERT); record = proxy.readFromServer(); } assertNull(record); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesTest.java index 8e3de549a35..d3c94429527 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,8 +18,6 @@ package org.eclipse.jetty.client.ssl; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.EOFException; import java.io.IOException; import java.io.InputStream; @@ -38,6 +36,7 @@ import java.util.concurrent.TimeUnit; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; +import static org.junit.jupiter.api.Assertions.assertTrue; public abstract class SslBytesTest { @@ -149,7 +148,7 @@ public abstract class SslBytesTest { logger.info(x.getClass() + ": " + x.getMessage()); - if(logger.isDebugEnabled()) + if (logger.isDebugEnabled()) logger.debug(x); } } diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslConnectionTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslConnectionTest.java index 4293b831c6b..9fa25956d48 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslConnectionTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslConnectionTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,11 +18,8 @@ package org.eclipse.jetty.client.ssl; -import static org.junit.jupiter.api.Assertions.assertThrows; - import java.io.File; import java.nio.ByteBuffer; - import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLHandshakeException; @@ -36,16 +33,17 @@ import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.thread.QueuedThreadPool; - import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertThrows; + public class SslConnectionTest { @Test public void testSslConnectionClosedBeforeFill() throws Exception { File keyStore = MavenTestingUtils.getTestResourceFile("keystore.jks"); - SslContextFactory sslContextFactory = new SslContextFactory(); + SslContextFactory sslContextFactory = new SslContextFactory.Server(); sslContextFactory.setKeyStorePath(keyStore.getAbsolutePath()); sslContextFactory.setKeyStorePassword("storepwd"); sslContextFactory.start(); @@ -83,6 +81,6 @@ public class SslConnectionTest // We want SSLHandshakeException to be thrown instead, because it is // handled better (it is an IOException) by the Connection code that // reads from the EndPoint. - assertThrows(SSLHandshakeException.class, ()->sslEndPoint.fill(BufferUtil.EMPTY_BUFFER)); + assertThrows(SSLHandshakeException.class, () -> sslEndPoint.fill(BufferUtil.EMPTY_BUFFER)); } } diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/util/DeferredContentProviderTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/util/DeferredContentProviderTest.java index 9d3e42c5e0d..b8e26dd99b9 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/util/DeferredContentProviderTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/util/DeferredContentProviderTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,10 +18,6 @@ package org.eclipse.jetty.client.util; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.nio.ByteBuffer; import java.util.Iterator; import java.util.NoSuchElementException; @@ -37,6 +33,10 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class DeferredContentProviderTest { private ExecutorService executor; @@ -131,7 +131,7 @@ public class DeferredContentProviderTest assertFalse(iterator.hasNext()); - assertThrows(NoSuchElementException.class, ()->iterator.next()); + assertThrows(NoSuchElementException.class, () -> iterator.next()); assertFalse(iterator.hasNext()); } diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/util/InputStreamContentProviderTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/util/InputStreamContentProviderTest.java index b2e232cff41..727edc85687 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/util/InputStreamContentProviderTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/util/InputStreamContentProviderTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,11 +18,6 @@ package org.eclipse.jetty.client.util; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; @@ -31,9 +26,13 @@ import java.util.Iterator; import java.util.NoSuchElementException; import java.util.concurrent.atomic.AtomicBoolean; - import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class InputStreamContentProviderTest { @Test @@ -91,7 +90,7 @@ public class InputStreamContentProviderTest assertNotNull(buffer); - assertThrows(NoSuchElementException.class, ()->iterator.next()); + assertThrows(NoSuchElementException.class, () -> iterator.next()); assertFalse(iterator.hasNext()); assertTrue(closed.get()); @@ -122,7 +121,7 @@ public class InputStreamContentProviderTest assertNotNull(iterator); - assertThrows(NoSuchElementException.class, ()->iterator.next()); + assertThrows(NoSuchElementException.class, () -> iterator.next()); assertFalse(iterator.hasNext()); assertTrue(closed.get()); @@ -154,7 +153,7 @@ public class InputStreamContentProviderTest assertNotNull(iterator); assertTrue(iterator.hasNext()); - assertThrows(NoSuchElementException.class, ()->iterator.next()); + assertThrows(NoSuchElementException.class, () -> iterator.next()); assertFalse(iterator.hasNext()); assertTrue(closed.get()); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/util/MultiPartContentProviderTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/util/MultiPartContentProviderTest.java index d8c89eb0532..e1d855e3e2b 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/util/MultiPartContentProviderTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/util/MultiPartContentProviderTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,12 +18,6 @@ package org.eclipse.jetty.client.util; -import static org.eclipse.jetty.toolchain.test.StackUtils.supply; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.BufferedWriter; import java.io.ByteArrayInputStream; import java.io.File; @@ -41,7 +35,6 @@ import java.util.List; import java.util.Random; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; - import javax.servlet.MultipartConfigElement; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -60,6 +53,12 @@ import org.eclipse.jetty.util.IO; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsSource; +import static org.eclipse.jetty.toolchain.test.StackUtils.supply; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class MultiPartContentProviderTest extends AbstractHttpClientServerTest { @ParameterizedTest @@ -79,10 +78,10 @@ public class MultiPartContentProviderTest extends AbstractHttpClientServerTest MultiPartContentProvider multiPart = new MultiPartContentProvider(); multiPart.close(); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .method(HttpMethod.POST) - .content(multiPart) - .send(); + .scheme(scenario.getScheme()) + .method(HttpMethod.POST) + .content(multiPart) + .send(); assertEquals(200, response.getStatus()); } @@ -110,10 +109,10 @@ public class MultiPartContentProviderTest extends AbstractHttpClientServerTest multiPart.addFieldPart(name, new StringContentProvider(value), null); multiPart.close(); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .method(HttpMethod.POST) - .content(multiPart) - .send(); + .scheme(scenario.getScheme()) + .method(HttpMethod.POST) + .content(multiPart) + .send(); assertEquals(200, response.getStatus()); } @@ -150,10 +149,10 @@ public class MultiPartContentProviderTest extends AbstractHttpClientServerTest multiPart.addFieldPart(name, content, fields); multiPart.close(); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .method(HttpMethod.POST) - .content(multiPart) - .send(); + .scheme(scenario.getScheme()) + .method(HttpMethod.POST) + .content(multiPart) + .send(); assertEquals(200, response.getStatus()); } @@ -184,15 +183,15 @@ public class MultiPartContentProviderTest extends AbstractHttpClientServerTest multiPart.close(); CountDownLatch responseLatch = new CountDownLatch(1); client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .method(HttpMethod.POST) - .content(multiPart) - .send(result -> - { - assertTrue(result.isSucceeded(),supply(result.getFailure())); - assertEquals(200, result.getResponse().getStatus()); - responseLatch.countDown(); - }); + .scheme(scenario.getScheme()) + .method(HttpMethod.POST) + .content(multiPart) + .send(result -> + { + assertTrue(result.isSucceeded(), supply(result.getFailure())); + assertEquals(200, result.getResponse().getStatus()); + responseLatch.countDown(); + }); // Wait until the request has been sent. Thread.sleep(1000); @@ -245,10 +244,10 @@ public class MultiPartContentProviderTest extends AbstractHttpClientServerTest multiPart.addFilePart(name, fileName, content, fields); multiPart.close(); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .method(HttpMethod.POST) - .content(multiPart) - .send(); + .scheme(scenario.getScheme()) + .method(HttpMethod.POST) + .content(multiPart) + .send(); assertTrue(closeLatch.await(5, TimeUnit.SECONDS)); assertEquals(200, response.getStatus()); @@ -292,10 +291,10 @@ public class MultiPartContentProviderTest extends AbstractHttpClientServerTest multiPart.addFilePart(name, tmpPath.getFileName().toString(), content, null); multiPart.close(); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .method(HttpMethod.POST) - .content(multiPart) - .send(); + .scheme(scenario.getScheme()) + .method(HttpMethod.POST) + .content(multiPart) + .send(); assertEquals(200, response.getStatus()); @@ -359,10 +358,10 @@ public class MultiPartContentProviderTest extends AbstractHttpClientServerTest multiPart.addFilePart(fileField, tmpPath.getFileName().toString(), new PathContentProvider(tmpPath), null); multiPart.close(); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .method(HttpMethod.POST) - .content(multiPart) - .send(); + .scheme(scenario.getScheme()) + .method(HttpMethod.POST) + .content(multiPart) + .send(); assertEquals(200, response.getStatus()); @@ -409,15 +408,15 @@ public class MultiPartContentProviderTest extends AbstractHttpClientServerTest multiPart.addFilePart("file", "fileName", fileContent, null); CountDownLatch responseLatch = new CountDownLatch(1); client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .method(HttpMethod.POST) - .content(multiPart) - .send(result -> - { - assertTrue(result.isSucceeded(),supply(result.getFailure())); - assertEquals(200, result.getResponse().getStatus()); - responseLatch.countDown(); - }); + .scheme(scenario.getScheme()) + .method(HttpMethod.POST) + .content(multiPart) + .send(result -> + { + assertTrue(result.isSucceeded(), supply(result.getFailure())); + assertEquals(200, result.getResponse().getStatus()); + responseLatch.countDown(); + }); // Wait until the request has been sent. Thread.sleep(1000); @@ -436,14 +435,14 @@ public class MultiPartContentProviderTest extends AbstractHttpClientServerTest assertTrue(responseLatch.await(5, TimeUnit.SECONDS)); } - private static abstract class AbstractMultiPartHandler extends AbstractHandler + private abstract static class AbstractMultiPartHandler extends AbstractHandler { @Override public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { baseRequest.setHandled(true); File tmpDir = MavenTestingUtils.getTargetTestingDir(); - request.setAttribute(Request.__MULTIPART_CONFIG_ELEMENT, new MultipartConfigElement(tmpDir.getAbsolutePath())); + request.setAttribute(Request.MULTIPART_CONFIG_ELEMENT, new MultipartConfigElement(tmpDir.getAbsolutePath())); handle(request, response); } diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/util/SPNEGOAuthenticationTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/util/SPNEGOAuthenticationTest.java new file mode 100644 index 00000000000..d4899900ba8 --- /dev/null +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/util/SPNEGOAuthenticationTest.java @@ -0,0 +1,300 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.client.util; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Duration; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.kerby.kerberos.kerb.server.SimpleKdcServer; +import org.eclipse.jetty.client.AbstractHttpClientServerTest; +import org.eclipse.jetty.client.EmptyServerHandler; +import org.eclipse.jetty.client.api.Authentication; +import org.eclipse.jetty.client.api.AuthenticationStore; +import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.client.api.Request; +import org.eclipse.jetty.client.api.Response; +import org.eclipse.jetty.security.ConfigurableSpnegoLoginService; +import org.eclipse.jetty.security.ConstraintMapping; +import org.eclipse.jetty.security.ConstraintSecurityHandler; +import org.eclipse.jetty.security.HashLoginService; +import org.eclipse.jetty.security.authentication.AuthorizationService; +import org.eclipse.jetty.security.authentication.ConfigurableSpnegoAuthenticator; +import org.eclipse.jetty.server.Handler; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.session.DefaultSessionIdManager; +import org.eclipse.jetty.server.session.SessionHandler; +import org.eclipse.jetty.toolchain.test.MavenTestingUtils; +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.security.Constraint; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.condition.DisabledOnJre; +import org.junit.jupiter.api.condition.JRE; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ArgumentsSource; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +// Apparently only JDK 11 is able to run these tests. +// See for example: https://bugs.openjdk.java.net/browse/JDK-8202439 +// where apparently the compiler gets the AES CPU instructions wrong. +@DisabledOnJre({JRE.JAVA_8, JRE.JAVA_9, JRE.JAVA_10}) +public class SPNEGOAuthenticationTest extends AbstractHttpClientServerTest +{ + private static final Logger LOG = Log.getLogger(SPNEGOAuthenticationTest.class); + + static + { + if (LOG.isDebugEnabled()) + { + System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "debug"); + System.setProperty("sun.security.jgss.debug", "true"); + System.setProperty("sun.security.krb5.debug", "true"); + System.setProperty("sun.security.spnego.debug", "true"); + } + } + + private Path testDirPath = MavenTestingUtils.getTargetTestingPath(SPNEGOAuthenticationTest.class.getSimpleName()); + private String clientName = "spnego_client"; + private String clientPassword = "spnego_client_pwd"; + private String serviceName = "srvc"; + private String serviceHost = "localhost"; + private String realm = "jetty.org"; + private Path realmPropsPath = MavenTestingUtils.getTestResourcePath("realm.properties"); + private Path serviceKeyTabPath = testDirPath.resolve("service.keytab"); + private Path clientKeyTabPath = testDirPath.resolve("client.keytab"); + private SimpleKdcServer kdc; + private ConfigurableSpnegoAuthenticator authenticator; + + @BeforeEach + public void prepare() throws Exception + { + IO.delete(testDirPath.toFile()); + Files.createDirectories(testDirPath); + System.setProperty("java.security.krb5.conf", testDirPath.toAbsolutePath().toString()); + + kdc = new SimpleKdcServer(); + kdc.setAllowUdp(false); + kdc.setAllowTcp(true); + kdc.setKdcRealm(realm); + kdc.setWorkDir(testDirPath.toFile()); + kdc.init(); + + kdc.createAndExportPrincipals(serviceKeyTabPath.toFile(), serviceName + "/" + serviceHost); + kdc.createPrincipal(clientName + "@" + realm, clientPassword); + kdc.exportPrincipal(clientName, clientKeyTabPath.toFile()); + kdc.start(); + + if (LOG.isDebugEnabled()) + { + LOG.debug("KDC started on port {}", kdc.getKdcTcpPort()); + String krb5 = Files.readAllLines(testDirPath.resolve("krb5.conf")).stream() + .filter(line -> !line.startsWith("#")) + .collect(Collectors.joining(System.lineSeparator())); + LOG.debug("krb5.conf{}{}", System.lineSeparator(), krb5); + } + } + + @AfterEach + public void dispose() throws Exception + { + if (kdc != null) + kdc.stop(); + } + + private void startSPNEGO(Scenario scenario, Handler handler) throws Exception + { + server = new Server(); + server.setSessionIdManager(new DefaultSessionIdManager(server)); + HashLoginService authorizationService = new HashLoginService(realm, realmPropsPath.toString()); + ConfigurableSpnegoLoginService loginService = new ConfigurableSpnegoLoginService(realm, AuthorizationService.from(authorizationService, "")); + loginService.addBean(authorizationService); + loginService.setKeyTabPath(serviceKeyTabPath); + loginService.setServiceName(serviceName); + loginService.setHostName(serviceHost); + server.addBean(loginService); + + ConstraintSecurityHandler securityHandler = new ConstraintSecurityHandler(); + Constraint constraint = new Constraint(); + constraint.setAuthenticate(true); + constraint.setRoles(new String[]{"**"}); //allow any authenticated user + ConstraintMapping mapping = new ConstraintMapping(); + mapping.setPathSpec("/secure"); + mapping.setConstraint(constraint); + securityHandler.addConstraintMapping(mapping); + authenticator = new ConfigurableSpnegoAuthenticator(); + securityHandler.setAuthenticator(authenticator); + securityHandler.setLoginService(loginService); + securityHandler.setHandler(handler); + + SessionHandler sessionHandler = new SessionHandler(); + sessionHandler.setHandler(securityHandler); + start(scenario, sessionHandler); + } + + @ParameterizedTest + @ArgumentsSource(ScenarioProvider.class) + public void testPasswordSPNEGOAuthentication(Scenario scenario) throws Exception + { + testSPNEGOAuthentication(scenario, false); + } + + @ParameterizedTest + @ArgumentsSource(ScenarioProvider.class) + public void testKeyTabSPNEGOAuthentication(Scenario scenario) throws Exception + { + testSPNEGOAuthentication(scenario, true); + } + + private void testSPNEGOAuthentication(Scenario scenario, boolean useKeyTab) throws Exception + { + startSPNEGO(scenario, new EmptyServerHandler()); + authenticator.setAuthenticationDuration(Duration.ZERO); + + URI uri = URI.create(scenario.getScheme() + "://localhost:" + connector.getLocalPort()); + + // Request without Authentication causes a 401 + Request request = client.newRequest(uri).path("/secure"); + ContentResponse response = request.timeout(15, TimeUnit.SECONDS).send(); + assertNotNull(response); + assertEquals(401, response.getStatus()); + + // Add authentication. + SPNEGOAuthentication authentication = new SPNEGOAuthentication(uri); + authentication.setUserName(clientName + "@" + realm); + if (useKeyTab) + authentication.setUserKeyTabPath(clientKeyTabPath); + else + authentication.setUserPassword(clientPassword); + authentication.setServiceName(serviceName); + AuthenticationStore authenticationStore = client.getAuthenticationStore(); + authenticationStore.addAuthentication(authentication); + + // Request with authentication causes a 401 (no previous successful authentication) + 200 + request = client.newRequest(uri).path("/secure"); + response = request.timeout(15, TimeUnit.SECONDS).send(); + assertNotNull(response); + assertEquals(200, response.getStatus()); + // Authentication results for SPNEGO cannot be cached. + Authentication.Result authnResult = authenticationStore.findAuthenticationResult(uri); + assertNull(authnResult); + + AtomicInteger requests = new AtomicInteger(); + client.getRequestListeners().add(new Request.Listener.Adapter() + { + @Override + public void onSuccess(Request request) + { + requests.incrementAndGet(); + } + }); + + // The server has infinite authentication duration, so + // subsequent requests will be preemptively authorized. + request = client.newRequest(uri).path("/secure"); + response = request.timeout(15, TimeUnit.SECONDS).send(); + assertNotNull(response); + assertEquals(200, response.getStatus()); + assertEquals(1, requests.get()); + } + + @ParameterizedTest + @ArgumentsSource(ScenarioProvider.class) + public void testAuthenticationExpiration(Scenario scenario) throws Exception + { + startSPNEGO(scenario, new EmptyServerHandler() + { + @Override + protected void service(String target, org.eclipse.jetty.server.Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException + { + IO.readBytes(request.getInputStream()); + } + }); + long timeout = 1000; + authenticator.setAuthenticationDuration(Duration.ofMillis(timeout)); + + URI uri = URI.create(scenario.getScheme() + "://localhost:" + connector.getLocalPort()); + + // Add authentication. + SPNEGOAuthentication authentication = new SPNEGOAuthentication(uri); + authentication.setUserName(clientName + "@" + realm); + authentication.setUserPassword(clientPassword); + authentication.setServiceName(serviceName); + AuthenticationStore authenticationStore = client.getAuthenticationStore(); + authenticationStore.addAuthentication(authentication); + + AtomicInteger requests = new AtomicInteger(); + client.getRequestListeners().add(new Request.Listener.Adapter() + { + @Override + public void onSuccess(Request request) + { + requests.incrementAndGet(); + } + }); + + Request request = client.newRequest(uri).path("/secure"); + Response response = request.timeout(15, TimeUnit.SECONDS).send(); + assertEquals(200, response.getStatus()); + // Expect 401 + 200. + assertEquals(2, requests.get()); + + requests.set(0); + request = client.newRequest(uri).path("/secure"); + response = request.timeout(15, TimeUnit.SECONDS).send(); + assertEquals(200, response.getStatus()); + // Authentication not expired on server, expect 200 only. + assertEquals(1, requests.get()); + + // Let authentication expire. + Thread.sleep(2 * timeout); + + requests.set(0); + request = client.newRequest(uri).path("/secure"); + response = request.timeout(15, TimeUnit.SECONDS).send(); + assertEquals(200, response.getStatus()); + // Authentication expired, expect 401 + 200. + assertEquals(2, requests.get()); + + // Let authentication expire again. + Thread.sleep(2 * timeout); + + requests.set(0); + ByteArrayInputStream input = new ByteArrayInputStream("hello_world".getBytes(StandardCharsets.UTF_8)); + request = client.newRequest(uri).method("POST").path("/secure").content(new InputStreamContentProvider(input)); + response = request.timeout(15, TimeUnit.SECONDS).send(); + assertEquals(200, response.getStatus()); + // Authentication expired, but POSTs are allowed. + assertEquals(1, requests.get()); + } +} diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/util/TypedContentProviderTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/util/TypedContentProviderTest.java index 7bdea0f738c..f25ba5fdc00 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/util/TypedContentProviderTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/util/TypedContentProviderTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,13 +18,8 @@ package org.eclipse.jetty.client.util; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; - import java.io.IOException; import java.nio.charset.StandardCharsets; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -42,6 +37,10 @@ import org.hamcrest.Matchers; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsSource; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + public class TypedContentProviderTest extends AbstractHttpClientServerTest { @ParameterizedTest @@ -106,11 +105,11 @@ public class TypedContentProviderTest extends AbstractHttpClientServerTest }); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .method(HttpMethod.POST) - .content(new FormContentProvider(fields)) - .header(HttpHeader.CONTENT_TYPE, contentType) - .send(); + .scheme(scenario.getScheme()) + .method(HttpMethod.POST) + .content(new FormContentProvider(fields)) + .header(HttpHeader.CONTENT_TYPE, contentType) + .send(); assertEquals(200, response.getStatus()); } @@ -134,9 +133,9 @@ public class TypedContentProviderTest extends AbstractHttpClientServerTest }); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scenario.getScheme()) - .content(new StringContentProvider(null, content, StandardCharsets.UTF_8)) - .send(); + .scheme(scenario.getScheme()) + .content(new StringContentProvider(null, content, StandardCharsets.UTF_8)) + .send(); assertEquals(200, response.getStatus()); } diff --git a/jetty-client/src/test/resources/jetty-logging.properties b/jetty-client/src/test/resources/jetty-logging.properties index 50f3165273b..f74a4da98d1 100644 --- a/jetty-client/src/test/resources/jetty-logging.properties +++ b/jetty-client/src/test/resources/jetty-logging.properties @@ -1,5 +1,5 @@ -class=org.eclipse.jetty.util.log.StdErrLog -#org.eclipse.jetty.LEVEL=INFO +org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog +#org.eclipse.jetty.LEVEL=DEBUG #org.eclipse.jetty.client.LEVEL=DEBUG #org.eclipse.jetty.io.ChannelEndPoint.LEVEL=DEBUG #org.eclipse.jetty.io.ssl.LEVEL=DEBUG diff --git a/jetty-client/src/test/resources/realm.properties b/jetty-client/src/test/resources/realm.properties index 54ace472cb6..27e300ad53c 100644 --- a/jetty-client/src/test/resources/realm.properties +++ b/jetty-client/src/test/resources/realm.properties @@ -1,3 +1,4 @@ # Format is :, basic:basic digest:digest +spnego_client:,admin diff --git a/jetty-continuation/pom.xml b/jetty-continuation/pom.xml index 05bb24b9448..cae5f587d6c 100644 --- a/jetty-continuation/pom.xml +++ b/jetty-continuation/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 jetty-continuation @@ -25,9 +25,9 @@ - javax.servlet + javax.servlet javax.servlet-api provided - + diff --git a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Continuation.java b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Continuation.java index 441c84e7ec3..c5edaf09993 100644 --- a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Continuation.java +++ b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Continuation.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -25,32 +25,32 @@ import javax.servlet.ServletResponseWrapper; /** * Continuation. - *

      - * A continuation is a mechanism by which a HTTP Request can be suspended and + *

      + * A continuation is a mechanism by which an HTTP Request can be suspended and * restarted after a timeout or an asynchronous event has occurred. *

      - * The continuation mechanism is a portable mechanism that will work - * asynchronously without additional configuration of all jetty-7, - * jetty-8 and Servlet 3.0 containers. With the addition of + * The continuation mechanism is a portable mechanism that will work + * asynchronously without additional configuration of all jetty-7, + * jetty-8 and Servlet 3.0 containers. With the addition of * the {@link ContinuationFilter}, the mechanism will also work - * asynchronously on jetty-6 and non-asynchronously on any + * asynchronously on jetty-6 and non-asynchronously on any * servlet 2.5 container. *

      * The Continuation API is a simplification of the richer async API * provided by the servlet-3.0 and an enhancement of the continuation - * API that was introduced with jetty-6. + * API that was introduced with jetty-6. *

      *

      Continuation Usage

      *

      - * A continuation object is obtained for a request by calling the + * A continuation object is obtained for a request by calling the * factory method {@link ContinuationSupport#getContinuation(ServletRequest)}. * The continuation type returned will depend on the servlet container * being used. - *

      + *

      *

      * There are two distinct style of operation of the continuation API. *

      - *

      Suspend/Resume Usage

      + *

      Suspend/Resume Usage

      *

      The suspend/resume style is used when a servlet and/or * filter is used to generate the response after a asynchronous wait that is * terminated by an asynchronous handler. @@ -66,16 +66,16 @@ import javax.servlet.ServletResponseWrapper; * myAsyncHandler.register(continuation); * return; // or continuation.undispatch(); * } - * + * * async wait ... - * + * * Async Handler: * // when the waited for event happens * continuation.setAttribute("results",event); * continuation.resume(); - * + * * Filter/Servlet: - * // when the request is redispatched + * // when the request is redispatched * if (results==null) * { * ... // see above @@ -84,10 +84,10 @@ import javax.servlet.ServletResponseWrapper; * { * response.getOutputStream().write(process(results)); * } - * - *

      Suspend/Complete Usage

      + * + *

      Suspend/Complete Usage

      *

      - * The suspend/complete style is used when an asynchronous handler is used to + * The suspend/complete style is used when an asynchronous handler is used to * generate the response: *

      *
      @@ -119,48 +119,44 @@ import javax.servlet.ServletResponseWrapper;
        *   continuation.getServletResponse().getOutputStream().write(process(event));
        *   continuation.complete()
        * 
      - * + * *

      Continuation Timeout

      *

      * If a continuation is suspended, but neither {@link #complete()} or {@link #resume()} is * called during the period set by {@link #setTimeout(long)}, then the continuation will - * expire and {@link #isExpired()} will return true. + * expire and {@link #isExpired()} will return true. *

      *

      * When a continuation expires, the {@link ContinuationListener#onTimeout(Continuation)} * method is called on any {@link ContinuationListener} that has been registered via the - * {@link #addContinuationListener(ContinuationListener)} method. The onTimeout handlers - * may write a response and call {@link #complete()}. If {@link #complete()} is not called, + * {@link #addContinuationListener(ContinuationListener)} method. The onTimeout handlers + * may write a response and call {@link #complete()}. If {@link #complete()} is not called, * then the container will redispatch the request as if {@link #resume()} had been called, * except that {@link #isExpired()} will be true and {@link #isResumed()} will be false. *

      - * + * * @see ContinuationSupport * @see ContinuationListener - * * @deprecated use Servlet 3.0 {@link javax.servlet.AsyncContext} instead */ @Deprecated public interface Continuation { - public final static String ATTRIBUTE = "org.eclipse.jetty.continuation"; + String ATTRIBUTE = "org.eclipse.jetty.continuation"; - /* ------------------------------------------------------------ */ /** * Set the continuation timeout. - * - * @param timeoutMs - * The time in milliseconds to wait before expiring this - * continuation after a call to {@link #suspend()} or {@link #suspend(ServletResponse)}. - * A timeout of <=0 means the continuation will never expire. + * + * @param timeoutMs The time in milliseconds to wait before expiring this + * continuation after a call to {@link #suspend()} or {@link #suspend(ServletResponse)}. + * A timeout of <=0 means the continuation will never expire. */ void setTimeout(long timeoutMs); - /* ------------------------------------------------------------ */ /** * Suspend the processing of the request and associated * {@link ServletResponse}. - * + * *

      * After this method has been called, the lifecycle of the request will be * extended beyond the return to the container from the @@ -170,7 +166,7 @@ public interface Continuation * a dispatch, then the container will not commit the associated response * (unless an exception other than {@link ContinuationThrowable} is thrown). *

      - * + * *

      * When the thread calling the filter chain and/or servlet has returned to * the container with a suspended request, the thread is freed for other @@ -182,21 +178,18 @@ public interface Continuation * *

      * Typically suspend with no arguments is uses when a call to {@link #resume()} - * is expected. If a call to {@link #complete()} is expected, then the + * is expected. If a call to {@link #complete()} is expected, then the * {@link #suspend(ServletResponse)} method should be used instead of this method. *

      - * - * @exception IllegalStateException - * If the request cannot be suspended + * + * @throws IllegalStateException If the request cannot be suspended */ void suspend(); - - - /* ------------------------------------------------------------ */ + /** * Suspend the processing of the request and associated * {@link ServletResponse}. - * + * *

      * After this method has been called, the lifecycle of the request will be * extended beyond the return to the container from the @@ -217,27 +210,25 @@ public interface Continuation * *

      * Typically suspend with a response argument is uses when a call to {@link #complete()} - * is expected. If a call to {@link #resume()} is expected, then the + * is expected. If a call to {@link #resume()} is expected, then the * {@link #suspend()} method should be used instead of this method. *

      *

      * Filters that may wrap the response object should check {@link #isResponseWrapped()} * to decide if they should destroy/finish the wrapper. If {@link #isResponseWrapped()} * returns true, then the wrapped request has been passed to the asynchronous - * handler and the wrapper should not be destroyed/finished until after a call to + * handler and the wrapper should not be destroyed/finished until after a call to * {@link #complete()} (potentially using a {@link ContinuationListener#onComplete(Continuation)} * listener). - * + * * @param response The response to return via a call to {@link #getServletResponse()} - * @exception IllegalStateException - * If the request cannot be suspended + * @throws IllegalStateException If the request cannot be suspended */ void suspend(ServletResponse response); - /* ------------------------------------------------------------ */ /** * Resume a suspended request. - * + * *

      * This method can be called by any thread that has been passed a reference * to a continuation. When called the request is redispatched to the @@ -254,26 +245,24 @@ public interface Continuation *

      * Typically resume() is used after a call to {@link #suspend()} with * no arguments. The dispatch after a resume call will use the original - * request and response objects, even if {@link #suspend(ServletResponse)} + * request and response objects, even if {@link #suspend(ServletResponse)} * had been passed a wrapped response. *

      - * + * + * @throws IllegalStateException if the request is not suspended. * @see #suspend() - * @exception IllegalStateException if the request is not suspended. - * */ void resume(); - /* ------------------------------------------------------------ */ /** * Complete a suspended request. - * + * *

      * This method can be called by any thread that has been passed a reference * to a suspended request. When a request is completed, the associated * response object committed and flushed. The request is not redispatched. *

      - * + * *

      * If complete is called before a suspended request is returned to the * container (ie the thread that called {@link #suspend()} is still @@ -282,123 +271,117 @@ public interface Continuation * returns to the container. In this case both {@link #isSuspended()} and * {@link #isResumed()} return true. *

      - * + * *

      * Typically resume() is used after a call to {@link #suspend(ServletResponse)} with * a possibly wrapped response. The async handler should use the response * provided by {@link #getServletResponse()} to write the response before - * calling {@link #complete()}. If the request was suspended with a + * calling {@link #complete()}. If the request was suspended with a * call to {@link #suspend()} then no response object will be available via * {@link #getServletResponse()}. *

      - * + * *

      * Once complete has been called and any thread calling the filter chain * and/or servlet chain has returned to the container, the request lifecycle * is complete. The container is able to recycle request objects, so it is - * not valid hold a request or continuation reference after the end of the + * not valid hold a request or continuation reference after the end of the * life cycle. - * + * + * @throws IllegalStateException if the request is not suspended. * @see #suspend() - * @exception IllegalStateException - * if the request is not suspended. - * */ void complete(); - /* ------------------------------------------------------------ */ /** * @return true after {@link #suspend()} has been called and before the - * request has been redispatched due to being resumed, completed or - * timed out. + * request has been redispatched due to being resumed, completed or + * timed out. */ boolean isSuspended(); - /* ------------------------------------------------------------ */ /** * @return true if the request has been redispatched by a call to - * {@link #resume()}. Returns false after any subsequent call to - * suspend + * {@link #resume()}. Returns false after any subsequent call to + * suspend */ boolean isResumed(); - /* ------------------------------------------------------------ */ /** * @return true after a request has been redispatched as the result of a - * timeout. Returns false after any subsequent call to suspend. + * timeout. Returns false after any subsequent call to suspend. */ boolean isExpired(); - /* ------------------------------------------------------------ */ /** * @return true while the request is within the initial dispatch to the - * filter chain and/or servlet. Will return false once the calling - * thread has returned to the container after suspend has been - * called and during any subsequent redispatch. + * filter chain and/or servlet. Will return false once the calling + * thread has returned to the container after suspend has been + * called and during any subsequent redispatch. */ boolean isInitial(); - /* ------------------------------------------------------------ */ /** * Is the suspended response wrapped. *

      - * Filters that wrap the response object should check this method to - * determine if they should destroy/finish the wrapped response. If + * Filters that wrap the response object should check this method to + * determine if they should destroy/finish the wrapped response. If * the request was suspended with a call to {@link #suspend(ServletResponse)} * that passed the wrapped response, then the filter should register * a {@link ContinuationListener} to destroy/finish the wrapped response * during a call to {@link ContinuationListener#onComplete(Continuation)}. + * * @return True if {@link #suspend(ServletResponse)} has been passed a * {@link ServletResponseWrapper} instance. */ boolean isResponseWrapped(); - - /* ------------------------------------------------------------ */ /** * Get the suspended response. + * * @return the {@link ServletResponse} passed to {@link #suspend(ServletResponse)}. */ ServletResponse getServletResponse(); - - /* ------------------------------------------------------------ */ - /** + + /** * Add a ContinuationListener. - * + * * @param listener the listener */ void addContinuationListener(ContinuationListener listener); - - /* ------------------------------------------------------------ */ - /** Set a request attribute. + + /** + * Set a request attribute. * This method is a convenience method to call the {@link ServletRequest#setAttribute(String, Object)} * method on the associated request object. * This is a thread safe call and may be called by any thread. + * * @param name the attribute name * @param attribute the attribute value */ - public void setAttribute(String name, Object attribute); - - /* ------------------------------------------------------------ */ - /** Get a request attribute. + void setAttribute(String name, Object attribute); + + /** + * Get a request attribute. * This method is a convenience method to call the {@link ServletRequest#getAttribute(String)} * method on the associated request object. * This is a thread safe call and may be called by any thread. + * * @param name the attribute name * @return the attribute value */ - public Object getAttribute(String name); - - /* ------------------------------------------------------------ */ - /** Remove a request attribute. + Object getAttribute(String name); + + /** + * Remove a request attribute. * This method is a convenience method to call the {@link ServletRequest#removeAttribute(String)} * method on the associated request object. * This is a thread safe call and may be called by any thread. + * * @param name the attribute name */ - public void removeAttribute(String name); - - /* ------------------------------------------------------------ */ + void removeAttribute(String name); + /** * Undispatch the request. *

      @@ -411,9 +394,9 @@ public interface Continuation *

      * This method should only be used as a last resort and a normal return is a prefereable * solution if filters can be updated to handle that case. - * - * @throws ContinuationThrowable thrown if the request is suspended. The instance of the + * + * @throws ContinuationThrowable thrown if the request is suspended. The instance of the * exception may be reused on subsequent calls, so the stack frame may not be accurate. */ - public void undispatch() throws ContinuationThrowable; + void undispatch() throws ContinuationThrowable; } diff --git a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationFilter.java b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationFilter.java index 7c450225d28..88e115ebe55 100644 --- a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationFilter.java +++ b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationFilter.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,7 +19,6 @@ package org.eclipse.jetty.continuation; import java.io.IOException; - import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; @@ -28,9 +27,6 @@ import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; - - -/* ------------------------------------------------------------ */ /** *

      ContinuationFilter must be applied to servlet paths that make use of * the asynchronous features provided by {@link Continuation} APIs, but that @@ -48,6 +44,7 @@ import javax.servlet.ServletResponse; * {@link Continuation#complete()} is called.

      *

      Faux continuations are not threadless continuations (they are "faux" - fake - for this reason) * and as such they will scale less than proper continuations.

      + * * @deprecated use Servlet 3.0 {@link javax.servlet.AsyncContext} instead */ @Deprecated @@ -64,29 +61,29 @@ public class ContinuationFilter implements Filter public void init(FilterConfig filterConfig) throws ServletException { filterConfig.getServletContext().log("WARNING: " + this.getClass().getName() + " is now DEPRECATED, use Servlet 3.0 AsyncContext instead."); - boolean jetty_7_or_greater="org.eclipse.jetty.servlet".equals(filterConfig.getClass().getPackage().getName()); + boolean jetty7OrGreater = "org.eclipse.jetty.servlet".equals(filterConfig.getClass().getPackage().getName()); _context = filterConfig.getServletContext(); - String param=filterConfig.getInitParameter("debug"); - _debug=param!=null&&Boolean.parseBoolean(param); + String param = filterConfig.getInitParameter("debug"); + _debug = param != null && Boolean.parseBoolean(param); if (_debug) - __debug=true; + __debug = true; - param=filterConfig.getInitParameter("partial"); - param=filterConfig.getInitParameter("faux"); - if (param!=null) - _faux=Boolean.parseBoolean(param); + param = filterConfig.getInitParameter("partial"); + param = filterConfig.getInitParameter("faux"); + if (param != null) + _faux = Boolean.parseBoolean(param); else - _faux=!(jetty_7_or_greater || _context.getMajorVersion()>=3); + _faux = !(jetty7OrGreater || _context.getMajorVersion() >= 3); - _filtered=_faux; + _filtered = _faux; if (_debug) - _context.log("ContinuationFilter "+ - " jetty="+jetty_7_or_greater+ - " faux="+_faux+ - " filtered="+_filtered+ - " servlet3="+ContinuationSupport.__servlet3); - _initialized=true; + _context.log("ContinuationFilter " + + " jetty=" + jetty7OrGreater + + " faux=" + _faux + + " filtered=" + _filtered + + " servlet3=" + ContinuationSupport.__servlet3); + _initialized = true; } @Override @@ -94,34 +91,34 @@ public class ContinuationFilter implements Filter { if (_filtered) { - Continuation c = (Continuation) request.getAttribute(Continuation.ATTRIBUTE); + Continuation c = (Continuation)request.getAttribute(Continuation.ATTRIBUTE); FilteredContinuation fc; - if (_faux && (c==null || !(c instanceof FauxContinuation))) + if (_faux && (c == null || !(c instanceof FauxContinuation))) { fc = new FauxContinuation(request); - request.setAttribute(Continuation.ATTRIBUTE,fc); + request.setAttribute(Continuation.ATTRIBUTE, fc); } else - fc=(FilteredContinuation)c; + fc = (FilteredContinuation)c; - boolean complete=false; + boolean complete = false; while (!complete) { try { - if (fc==null || (fc).enter(response)) - chain.doFilter(request,response); + if (fc == null || (fc).enter(response)) + chain.doFilter(request, response); } catch (ContinuationThrowable e) { - debug("faux",e); + debug("faux", e); } finally { - if (fc==null) - fc = (FilteredContinuation) request.getAttribute(Continuation.ATTRIBUTE); + if (fc == null) + fc = (FilteredContinuation)request.getAttribute(Continuation.ATTRIBUTE); - complete=fc==null || (fc).exit(); + complete = fc == null || (fc).exit(); } } } @@ -129,11 +126,11 @@ public class ContinuationFilter implements Filter { try { - chain.doFilter(request,response); + chain.doFilter(request, response); } catch (ContinuationThrowable e) { - debug("caught",e); + debug("caught", e); } } } @@ -151,9 +148,9 @@ public class ContinuationFilter implements Filter if (_debug) { if (th instanceof ContinuationThrowable) - _context.log(string+":"+th); + _context.log(string + ":" + th); else - _context.log(string,th); + _context.log(string, th); } } @@ -165,6 +162,7 @@ public class ContinuationFilter implements Filter public interface FilteredContinuation extends Continuation { boolean enter(ServletResponse response); + boolean exit(); } } diff --git a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationListener.java b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationListener.java index b055f9f95dc..59ca9615271 100644 --- a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationListener.java +++ b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationListener.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,20 +19,20 @@ package org.eclipse.jetty.continuation; import java.util.EventListener; - import javax.servlet.ServletRequestListener; -/** +/** * A Continuation Listener *

      * A ContinuationListener may be registered with a call to * {@link Continuation#addContinuationListener(ContinuationListener)}. + * * @deprecated use Servlet 3.0 {@link javax.servlet.AsyncContext} instead */ @Deprecated public interface ContinuationListener extends EventListener { - /* ------------------------------------------------------------ */ + /** * Called when a continuation life cycle is complete and after * any calls to {@link ServletRequestListener#requestDestroyed(javax.servlet.ServletRequestEvent)} @@ -40,16 +40,15 @@ public interface ContinuationListener extends EventListener * * @param continuation the continuation */ - public void onComplete(Continuation continuation); + void onComplete(Continuation continuation); - /* ------------------------------------------------------------ */ /** * Called when a suspended continuation has timed out. * The response may be written to and the methods * {@link Continuation#resume()} or {@link Continuation#complete()} * may be called by a onTimeout implementation, + * * @param continuation the continuation */ - public void onTimeout(Continuation continuation); - + void onTimeout(Continuation continuation); } diff --git a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationSupport.java b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationSupport.java index cd3f62f358a..8e1a21d39de 100644 --- a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationSupport.java +++ b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationSupport.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,16 +19,16 @@ package org.eclipse.jetty.continuation; import java.lang.reflect.Constructor; - import javax.servlet.ServletRequest; import javax.servlet.ServletRequestWrapper; import javax.servlet.ServletResponse; -/** +/** * ContinuationSupport. * * Factory class for accessing Continuation instances, which with either be * a servlet 3.0 or a faux continuation. + * * @deprecated use Servlet 3.0 {@link javax.servlet.AsyncContext} instead */ @Deprecated @@ -37,43 +37,44 @@ public class ContinuationSupport static final boolean __servlet3; static final Class __waitingContinuation; static final Constructor __newServlet3Continuation; + static { - boolean servlet3Support=false; - Constructors3cc=null; + boolean servlet3Support = false; + Constructor s3cc = null; try { - boolean servlet3=ServletRequest.class.getMethod("startAsync")!=null; + boolean servlet3 = ServletRequest.class.getMethod("startAsync") != null; if (servlet3) { Class s3c = ContinuationSupport.class.getClassLoader().loadClass("org.eclipse.jetty.continuation.Servlet3Continuation").asSubclass(Continuation.class); - s3cc=s3c.getConstructor(ServletRequest.class); - servlet3Support=true; + s3cc = s3c.getConstructor(ServletRequest.class); + servlet3Support = true; } } - catch (Exception e) - {} + catch (Exception ignored) + { + } finally { - __servlet3=servlet3Support; - __newServlet3Continuation=s3cc; + __servlet3 = servlet3Support; + __newServlet3Continuation = s3cc; } - Class waiting=null; + Class waiting = null; try { - waiting=ContinuationSupport.class.getClassLoader().loadClass("org.mortbay.util.ajax.WaitingContinuation"); + waiting = ContinuationSupport.class.getClassLoader().loadClass("org.mortbay.util.ajax.WaitingContinuation"); } - catch (Exception e) + catch (Exception ignored) { } finally { - __waitingContinuation=waiting; + __waitingContinuation = waiting; } } - /* ------------------------------------------------------------ */ /** * Get a Continuation. The type of the Continuation returned may * vary depending on the container in which the application is @@ -81,27 +82,30 @@ public class ContinuationSupport * org.eclipse.jetty.server.AsyncContinuation) or one of the utility * implementations provided such as an internal FauxContinuation * or a real implementation like {@link org.eclipse.jetty.continuation.Servlet3Continuation}. + * * @param request The request * @return a Continuation instance */ public static Continuation getContinuation(ServletRequest request) { - Continuation continuation = (Continuation) request.getAttribute(Continuation.ATTRIBUTE); - if (continuation!=null) + Continuation continuation = (Continuation)request.getAttribute(Continuation.ATTRIBUTE); + if (continuation != null) return continuation; while (request instanceof ServletRequestWrapper) - request=((ServletRequestWrapper)request).getRequest(); + { + request = ((ServletRequestWrapper)request).getRequest(); + } - if (__servlet3 ) + if (__servlet3) { try { - continuation=__newServlet3Continuation.newInstance(request); - request.setAttribute(Continuation.ATTRIBUTE,continuation); + continuation = __newServlet3Continuation.newInstance(request); + request.setAttribute(Continuation.ATTRIBUTE, continuation); return continuation; } - catch(Exception e) + catch (Exception e) { throw new RuntimeException(e); } @@ -110,12 +114,11 @@ public class ContinuationSupport throw new IllegalStateException("!(Jetty || Servlet 3.0 || ContinuationFilter)"); } - /* ------------------------------------------------------------ */ /** * @param request the servlet request * @param response the servlet response - * @deprecated use {@link #getContinuation(ServletRequest)} * @return the continuation + * @deprecated use {@link #getContinuation(ServletRequest)} */ @Deprecated public static Continuation getContinuation(final ServletRequest request, final ServletResponse response) diff --git a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationThrowable.java b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationThrowable.java index 0461e53f54b..58c7504673a 100644 --- a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationThrowable.java +++ b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationThrowable.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,16 +16,14 @@ // ======================================================================== // - package org.eclipse.jetty.continuation; - -/* ------------------------------------------------------------ */ -/** ContinuationThrowable +/** + * ContinuationThrowable *

      * A ContinuationThrowable is throw by {@link Continuation#undispatch()} * in order to exit the dispatch to a Filter or Servlet. Use of - * ContinuationThrowable is discouraged and it is preferable to + * ContinuationThrowable is discouraged and it is preferable to * allow return to be used. ContinuationThrowables should only be * used when there is a Filter/Servlet which cannot be modified * to avoid committing a response when {@link Continuation#isSuspended()} @@ -41,6 +39,7 @@ package org.eclipse.jetty.continuation; * to be uncaught (or rethrown) by a Filter/Servlet. A ContinuationThrowable * does not represent and error condition. *

      + * * @deprecated use Servlet 3.0 {@link javax.servlet.AsyncContext} instead */ @Deprecated diff --git a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/FauxContinuation.java b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/FauxContinuation.java index f72e664d62a..f108ade96a0 100644 --- a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/FauxContinuation.java +++ b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/FauxContinuation.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,23 +16,20 @@ // ======================================================================== // - package org.eclipse.jetty.continuation; import java.util.ArrayList; - import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.ServletResponseWrapper; import org.eclipse.jetty.continuation.ContinuationFilter.FilteredContinuation; - -/* ------------------------------------------------------------ */ /** * A blocking implementation of Continuation. * This implementation of Continuation is used by the {@link ContinuationFilter} * when there are is no native or asynchronous continuation type available. + * * @deprecated use Servlet 3.0 {@link javax.servlet.AsyncContext} instead */ @Deprecated @@ -40,50 +37,51 @@ class FauxContinuation implements FilteredContinuation { // common exception used for all continuations. // Turn on debug in ContinuationFilter to see real stack trace. - private final static ContinuationThrowable __exception = new ContinuationThrowable(); + private static final ContinuationThrowable __exception = new ContinuationThrowable(); - private static final int __HANDLING=1; // Request dispatched to filter/servlet - private static final int __SUSPENDING=2; // Suspend called, but not yet returned to container - private static final int __RESUMING=3; // resumed while suspending - private static final int __COMPLETING=4; // resumed while suspending or suspended - private static final int __SUSPENDED=5; // Suspended and parked - private static final int __UNSUSPENDING=6; - private static final int __COMPLETE=7; + private static final int __HANDLING = 1; // Request dispatched to filter/servlet + private static final int __SUSPENDING = 2; // Suspend called, but not yet returned to container + private static final int __RESUMING = 3; // resumed while suspending + private static final int __COMPLETING = 4; // resumed while suspending or suspended + private static final int __SUSPENDED = 5; // Suspended and parked + private static final int __UNSUSPENDING = 6; + private static final int __COMPLETE = 7; private final ServletRequest _request; private ServletResponse _response; - private int _state=__HANDLING; - private boolean _initial=true; - private boolean _resumed=false; - private boolean _timeout=false; - private boolean _responseWrapped=false; - private long _timeoutMs=30000; + private int _state = __HANDLING; + private boolean _initial = true; + private boolean _resumed = false; + private boolean _timeout = false; + private boolean _responseWrapped = false; + private long _timeoutMs = 30000; private ArrayList _listeners; FauxContinuation(final ServletRequest request) { - _request=request; + _request = request; } - /* ------------------------------------------------------------ */ public void onComplete() { - if (_listeners!=null) - for (ContinuationListener l:_listeners) + if (_listeners != null) + for (ContinuationListener l : _listeners) + { l.onComplete(this); + } } - /* ------------------------------------------------------------ */ public void onTimeout() { - if (_listeners!=null) - for (ContinuationListener l:_listeners) + if (_listeners != null) + for (ContinuationListener l : _listeners) + { l.onTimeout(this); + } } - /* ------------------------------------------------------------ */ /** * @see org.eclipse.jetty.continuation.Continuation#isResponseWrapped() */ @@ -93,33 +91,30 @@ class FauxContinuation implements FilteredContinuation return _responseWrapped; } - /* ------------------------------------------------------------ */ @Override public boolean isInitial() { - synchronized(this) + synchronized (this) { return _initial; } } - /* ------------------------------------------------------------ */ @Override public boolean isResumed() { - synchronized(this) + synchronized (this) { return _resumed; } } - /* ------------------------------------------------------------ */ @Override public boolean isSuspended() { - synchronized(this) + synchronized (this) { - switch(_state) + switch (_state) { case __HANDLING: return false; @@ -135,44 +130,40 @@ class FauxContinuation implements FilteredContinuation } } - /* ------------------------------------------------------------ */ @Override public boolean isExpired() { - synchronized(this) + synchronized (this) { return _timeout; } } - /* ------------------------------------------------------------ */ @Override public void setTimeout(long timeoutMs) { _timeoutMs = timeoutMs; } - /* ------------------------------------------------------------ */ @Override public void suspend(ServletResponse response) { - _response=response; - _responseWrapped=response instanceof ServletResponseWrapper; + _response = response; + _responseWrapped = response instanceof ServletResponseWrapper; suspend(); } - /* ------------------------------------------------------------ */ @Override public void suspend() { synchronized (this) { - switch(_state) + switch (_state) { case __HANDLING: - _timeout=false; - _resumed=false; - _state=__SUSPENDING; + _timeout = false; + _resumed = false; + _state = __SUSPENDING; return; case __SUSPENDING: @@ -185,14 +176,11 @@ class FauxContinuation implements FilteredContinuation throw new IllegalStateException(this.getStatusString()); default: - throw new IllegalStateException(""+_state); + throw new IllegalStateException("" + _state); } - } } - - /* ------------------------------------------------------------ */ /* (non-Javadoc) * @see org.mortbay.jetty.Suspendor#resume() */ @@ -201,15 +189,15 @@ class FauxContinuation implements FilteredContinuation { synchronized (this) { - switch(_state) + switch (_state) { case __HANDLING: - _resumed=true; + _resumed = true; return; case __SUSPENDING: - _resumed=true; - _state=__RESUMING; + _resumed = true; + _state = __RESUMING; return; case __RESUMING: @@ -218,36 +206,33 @@ class FauxContinuation implements FilteredContinuation case __SUSPENDED: fauxResume(); - _resumed=true; - _state=__UNSUSPENDING; + _resumed = true; + _state = __UNSUSPENDING; break; case __UNSUSPENDING: - _resumed=true; + _resumed = true; return; default: throw new IllegalStateException(this.getStatusString()); } } - } - - /* ------------------------------------------------------------ */ @Override public void complete() { // just like resume, except don't set _resumed=true; synchronized (this) { - switch(_state) + switch (_state) { case __HANDLING: throw new IllegalStateException(this.getStatusString()); case __SUSPENDING: - _state=__COMPLETING; + _state = __COMPLETING; break; case __RESUMING: @@ -257,7 +242,7 @@ class FauxContinuation implements FilteredContinuation return; case __SUSPENDED: - _state=__COMPLETING; + _state = __COMPLETING; fauxResume(); break; @@ -270,18 +255,16 @@ class FauxContinuation implements FilteredContinuation } } - /* ------------------------------------------------------------ */ /** * @see org.eclipse.jetty.continuation.Continuation#getServletResponse() */ @Override public boolean enter(ServletResponse response) { - _response=response; + _response = response; return true; } - /* ------------------------------------------------------------ */ /** * @see org.eclipse.jetty.continuation.Continuation#getServletResponse() */ @@ -291,14 +274,12 @@ class FauxContinuation implements FilteredContinuation return _response; } - - /* ------------------------------------------------------------ */ void handling() { synchronized (this) { - _responseWrapped=false; - switch(_state) + _responseWrapped = false; + switch (_state) { case __HANDLING: throw new IllegalStateException(this.getStatusString()); @@ -312,21 +293,19 @@ class FauxContinuation implements FilteredContinuation case __SUSPENDED: fauxResume(); - _state=__HANDLING; + _state = __HANDLING; return; - + case __UNSUSPENDING: - _state=__HANDLING; + _state = __HANDLING; return; default: - throw new IllegalStateException(""+_state); + throw new IllegalStateException("" + _state); } - } } - /* ------------------------------------------------------------ */ /** * @return true if handling is complete */ @@ -335,35 +314,35 @@ class FauxContinuation implements FilteredContinuation { synchronized (this) { - switch(_state) + switch (_state) { case __HANDLING: - _state=__COMPLETE; + _state = __COMPLETE; onComplete(); return true; case __SUSPENDING: - _initial=false; - _state=__SUSPENDED; + _initial = false; + _state = __SUSPENDED; fauxSuspend(); // could block and change state. - if (_state==__SUSPENDED || _state==__COMPLETING) + if (_state == __SUSPENDED || _state == __COMPLETING) { onComplete(); return true; } - _initial=false; - _state=__HANDLING; + _initial = false; + _state = __HANDLING; return false; case __RESUMING: - _initial=false; - _state=__HANDLING; + _initial = false; + _state = __HANDLING; return false; case __COMPLETING: - _initial=false; - _state=__COMPLETE; + _initial = false; + _state = __COMPLETE; onComplete(); return true; @@ -375,28 +354,27 @@ class FauxContinuation implements FilteredContinuation } } - /* ------------------------------------------------------------ */ protected void expire() { // just like resume, except don't set _resumed=true; synchronized (this) { - _timeout=true; + _timeout = true; } onTimeout(); synchronized (this) { - switch(_state) + switch (_state) { case __HANDLING: return; case __SUSPENDING: - _timeout=true; - _state=__RESUMING; + _timeout = true; + _state = __RESUMING; fauxResume(); return; @@ -407,12 +385,12 @@ class FauxContinuation implements FilteredContinuation return; case __SUSPENDED: - _timeout=true; - _state=__UNSUSPENDING; + _timeout = true; + _state = __UNSUSPENDING; break; case __UNSUSPENDING: - _timeout=true; + _timeout = true; return; default: @@ -423,9 +401,9 @@ class FauxContinuation implements FilteredContinuation private void fauxSuspend() { - long expire_at = System.currentTimeMillis()+_timeoutMs; - long wait=_timeoutMs; - while (_timeoutMs>0 && wait>0) + long expireAt = System.currentTimeMillis() + _timeoutMs; + long wait = _timeoutMs; + while (_timeoutMs > 0 && wait > 0) { try { @@ -435,16 +413,16 @@ class FauxContinuation implements FilteredContinuation { break; } - wait=expire_at-System.currentTimeMillis(); + wait = expireAt - System.currentTimeMillis(); } - if (_timeoutMs>0 && wait<=0) + if (_timeoutMs > 0 && wait <= 0) expire(); } private void fauxResume() { - _timeoutMs=0; + _timeoutMs = 0; this.notifyAll(); } @@ -459,30 +437,27 @@ class FauxContinuation implements FilteredContinuation synchronized (this) { return - ((_state==__HANDLING)?"HANDLING": - (_state==__SUSPENDING)?"SUSPENDING": - (_state==__SUSPENDED)?"SUSPENDED": - (_state==__RESUMING)?"RESUMING": - (_state==__UNSUSPENDING)?"UNSUSPENDING": - (_state==__COMPLETING)?"COMPLETING": - ("???"+_state))+ - (_initial?",initial":"")+ - (_resumed?",resumed":"")+ - (_timeout?",timeout":""); + ((_state == __HANDLING) ? "HANDLING" + : (_state == __SUSPENDING) ? "SUSPENDING" + : (_state == __SUSPENDED) ? "SUSPENDED" + : (_state == __RESUMING) ? "RESUMING" + : (_state == __UNSUSPENDING) ? "UNSUSPENDING" + : (_state == __COMPLETING) ? "COMPLETING" + : ("???" + _state)) + + (_initial ? ",initial" : "") + + (_resumed ? ",resumed" : "") + + (_timeout ? ",timeout" : ""); } } - @Override public void addContinuationListener(ContinuationListener listener) { - if (_listeners==null) - _listeners=new ArrayList(); + if (_listeners == null) + _listeners = new ArrayList(); _listeners.add(listener); - } - /* ------------------------------------------------------------ */ /** * @see org.eclipse.jetty.continuation.Continuation#getAttribute(java.lang.String) */ @@ -492,7 +467,6 @@ class FauxContinuation implements FilteredContinuation return _request.getAttribute(name); } - /* ------------------------------------------------------------ */ /** * @see org.eclipse.jetty.continuation.Continuation#removeAttribute(java.lang.String) */ @@ -502,17 +476,15 @@ class FauxContinuation implements FilteredContinuation _request.removeAttribute(name); } - /* ------------------------------------------------------------ */ /** * @see org.eclipse.jetty.continuation.Continuation#setAttribute(java.lang.String, java.lang.Object) */ @Override public void setAttribute(String name, Object attribute) { - _request.setAttribute(name,attribute); + _request.setAttribute(name, attribute); } - /* ------------------------------------------------------------ */ /** * @see org.eclipse.jetty.continuation.Continuation#undispatch() */ @@ -526,6 +498,5 @@ class FauxContinuation implements FilteredContinuation throw __exception; } throw new IllegalStateException("!suspended"); - } } diff --git a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Servlet3Continuation.java b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Servlet3Continuation.java index 7a93ec480bc..d368d1171c0 100644 --- a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Servlet3Continuation.java +++ b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Servlet3Continuation.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -21,7 +21,6 @@ package org.eclipse.jetty.continuation; import java.io.IOException; import java.util.ArrayList; import java.util.List; - import javax.servlet.AsyncContext; import javax.servlet.AsyncEvent; import javax.servlet.AsyncListener; @@ -30,12 +29,11 @@ import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.ServletResponseWrapper; - -/* ------------------------------------------------------------ */ /** * This implementation of Continuation is used by {@link ContinuationSupport} * when it detects that the application has been deployed in a Servlet 3 * server. + * * @deprecated use Servlet 3.0 {@link javax.servlet.AsyncContext} instead */ @Deprecated @@ -43,71 +41,63 @@ public class Servlet3Continuation implements Continuation, AsyncListener { // Exception reused for all continuations // Turn on debug in ContinuationFilter to see real stack trace. - private final static ContinuationThrowable __exception = new ContinuationThrowable(); + private static final ContinuationThrowable __exception = new ContinuationThrowable(); private final ServletRequest _request; private ServletResponse _response; private AsyncContext _context; - private final List _listeners=new ArrayList(); - private volatile boolean _initial=true; - private volatile boolean _resumed=false; - private volatile boolean _expired=false; - private volatile boolean _responseWrapped=false; + private final List _listeners = new ArrayList(); + private volatile boolean _initial = true; + private volatile boolean _resumed = false; + private volatile boolean _expired = false; + private volatile boolean _responseWrapped = false; - private long _timeoutMs=-1; + private long _timeoutMs = -1; - /* ------------------------------------------------------------ */ public Servlet3Continuation(ServletRequest request) { - _request=request; + _request = request; } - /* ------------------------------------------------------------ */ @Override public void addContinuationListener(final ContinuationListener listener) { _listeners.add(listener); } - /* ------------------------------------------------------------ */ @Override public void complete() { - AsyncContext context=_context; - if (context==null) + AsyncContext context = _context; + if (context == null) throw new IllegalStateException(); _context.complete(); } - /* ------------------------------------------------------------ */ @Override public ServletResponse getServletResponse() { return _response; } - /* ------------------------------------------------------------ */ @Override public boolean isExpired() { return _expired; } - /* ------------------------------------------------------------ */ @Override public boolean isInitial() { - return _initial&&_request.getDispatcherType()!=DispatcherType.ASYNC; + return _initial && _request.getDispatcherType() != DispatcherType.ASYNC; } - /* ------------------------------------------------------------ */ @Override public boolean isResumed() { return _resumed; } - /* ------------------------------------------------------------ */ @Override public boolean isSuspended() { @@ -115,73 +105,66 @@ public class Servlet3Continuation implements Continuation, AsyncListener return true; try { - return _request.getAsyncContext()!=null; + return _request.getAsyncContext() != null; } - catch(IllegalStateException e) + catch (IllegalStateException e) { // ignored } return false; } - /* ------------------------------------------------------------ */ public void keepWrappers() { - _responseWrapped=true; + _responseWrapped = true; } - /* ------------------------------------------------------------ */ @Override public void resume() { - AsyncContext context=_context; - if (context==null) + AsyncContext context = _context; + if (context == null) throw new IllegalStateException(); - _resumed=true; + _resumed = true; _context.dispatch(); } - /* ------------------------------------------------------------ */ @Override public void setTimeout(long timeoutMs) { - _timeoutMs=timeoutMs; - if (_context!=null) + _timeoutMs = timeoutMs; + if (_context != null) _context.setTimeout(timeoutMs); } - /* ------------------------------------------------------------ */ @Override public void suspend(ServletResponse response) { - _response=response; - _responseWrapped=response instanceof ServletResponseWrapper; - _resumed=false; - _expired=false; - _context=_request.startAsync(); + _response = response; + _responseWrapped = response instanceof ServletResponseWrapper; + _resumed = false; + _expired = false; + _context = _request.startAsync(); _context.setTimeout(_timeoutMs); _context.addListener(this); } - /* ------------------------------------------------------------ */ @Override public void suspend() { - _resumed=false; - _expired=false; - _context=_request.startAsync(); + _resumed = false; + _expired = false; + _context = _request.startAsync(); _context.setTimeout(_timeoutMs); _context.addListener(this); } - /* ------------------------------------------------------------ */ @Override public boolean isResponseWrapped() { return _responseWrapped; } - /* ------------------------------------------------------------ */ /** * @see org.eclipse.jetty.continuation.Continuation#getAttribute(java.lang.String) */ @@ -191,7 +174,6 @@ public class Servlet3Continuation implements Continuation, AsyncListener return _request.getAttribute(name); } - /* ------------------------------------------------------------ */ /** * @see org.eclipse.jetty.continuation.Continuation#removeAttribute(java.lang.String) */ @@ -201,17 +183,15 @@ public class Servlet3Continuation implements Continuation, AsyncListener _request.removeAttribute(name); } - /* ------------------------------------------------------------ */ /** * @see org.eclipse.jetty.continuation.Continuation#setAttribute(java.lang.String, java.lang.Object) */ @Override public void setAttribute(String name, Object attribute) { - _request.setAttribute(name,attribute); + _request.setAttribute(name, attribute); } - /* ------------------------------------------------------------ */ /** * @see org.eclipse.jetty.continuation.Continuation#undispatch() */ @@ -220,42 +200,41 @@ public class Servlet3Continuation implements Continuation, AsyncListener { if (isSuspended()) { - _initial=false; + _initial = false; if (ContinuationFilter.__debug) throw new ContinuationThrowable(); throw __exception; } throw new IllegalStateException("!suspended"); } - - /* ------------------------------------------------------------ */ @Override public void onComplete(AsyncEvent event) throws IOException { - for (ContinuationListener listener:_listeners) + for (ContinuationListener listener : _listeners) + { listener.onComplete(this); + } } - /* ------------------------------------------------------------ */ @Override public void onError(AsyncEvent event) throws IOException { } - /* ------------------------------------------------------------ */ @Override public void onStartAsync(AsyncEvent event) throws IOException { } - /* ------------------------------------------------------------ */ @Override public void onTimeout(AsyncEvent event) throws IOException { - _expired=true; - for (ContinuationListener listener:_listeners) + _expired = true; + for (ContinuationListener listener : _listeners) + { listener.onTimeout(this); + } if (event.getSuppliedRequest().isAsyncStarted()) event.getAsyncContext().dispatch(); } diff --git a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/package-info.java b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/package-info.java index 84f209572ea..ae9a1242fef 100644 --- a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/package-info.java +++ b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-deploy/pom.xml b/jetty-deploy/pom.xml index 494743c4d96..6e98cb18fe1 100644 --- a/jetty-deploy/pom.xml +++ b/jetty-deploy/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 jetty-deploy diff --git a/jetty-cdi/cdi-2/src/main/config/etc/cdi2/jetty-cdi2.xml b/jetty-deploy/src/main/config/etc/jetty-decorate.xml similarity index 51% rename from jetty-cdi/cdi-2/src/main/config/etc/cdi2/jetty-cdi2.xml rename to jetty-deploy/src/main/config/etc/jetty-decorate.xml index 3af8f23f2b2..9bbeba9f394 100644 --- a/jetty-cdi/cdi-2/src/main/config/etc/cdi2/jetty-cdi2.xml +++ b/jetty-deploy/src/main/config/etc/jetty-decorate.xml @@ -1,16 +1,15 @@ - - + - - - + + - /etc/cdi2/jetty-web-cdi2.xml + /etc/jetty-web-decorate.xml + diff --git a/jetty-deploy/src/main/config/etc/jetty-deploy.xml b/jetty-deploy/src/main/config/etc/jetty-deploy.xml index c27fb3ec2d7..a5c38d33d03 100644 --- a/jetty-deploy/src/main/config/etc/jetty-deploy.xml +++ b/jetty-deploy/src/main/config/etc/jetty-deploy.xml @@ -1,13 +1,6 @@ - - + - - - - - - - + diff --git a/jetty-deploy/src/main/config/etc/jetty-web-decorate.xml b/jetty-deploy/src/main/config/etc/jetty-web-decorate.xml new file mode 100644 index 00000000000..f91048c4b73 --- /dev/null +++ b/jetty-deploy/src/main/config/etc/jetty-web-decorate.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/jetty-deploy/src/main/config/modules/decorate.mod b/jetty-deploy/src/main/config/modules/decorate.mod new file mode 100644 index 00000000000..85bc367b981 --- /dev/null +++ b/jetty-deploy/src/main/config/modules/decorate.mod @@ -0,0 +1,14 @@ +# DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + +[description] +Jetty setup to support Decoration of Listeners, Filters and Servlets within a deployed webapp. +This module uses the DecoratingListener to register an object set as a context attribute +as a dynamic decorator. This module sets the "org.eclipse.jetty.webapp.DecoratingListener" +context attribute with the name of the context attribute that will be listened to. +By default the attribute is "org.eclipse.jetty.webapp.decorator". + +[depend] +deploy + +[xml] +etc/jetty-decorate.xml diff --git a/jetty-deploy/src/main/config/modules/global-webapp-common.d/global-webapp-common.xml b/jetty-deploy/src/main/config/modules/global-webapp-common.d/global-webapp-common.xml index aa3d308bbf7..d53d32d57f1 100644 --- a/jetty-deploy/src/main/config/modules/global-webapp-common.d/global-webapp-common.xml +++ b/jetty-deploy/src/main/config/modules/global-webapp-common.d/global-webapp-common.xml @@ -1,5 +1,4 @@ - - + diff --git a/jetty-deploy/src/main/config/modules/global-webapp-common.d/webapp-common.xml b/jetty-deploy/src/main/config/modules/global-webapp-common.d/webapp-common.xml index 3a056f63569..f05b034bd8b 100644 --- a/jetty-deploy/src/main/config/modules/global-webapp-common.d/webapp-common.xml +++ b/jetty-deploy/src/main/config/modules/global-webapp-common.d/webapp-common.xml @@ -1,5 +1,4 @@ - - + diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/App.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/App.java index eadadce0bad..186c1100ce8 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/App.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/App.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -33,12 +33,11 @@ public class App /** * Create an App with specified Origin ID and archivePath - * - * @param manager the deployment manager + * + * @param manager the deployment manager * @param provider the app provider - * @param originId - * the origin ID (The ID that the {@link AppProvider} knows - * about) + * @param originId the origin ID (The ID that the {@link AppProvider} knows + * about) * @see App#getOriginId() * @see App#getContextPath() */ @@ -51,25 +50,22 @@ public class App /** * Create an App with specified Origin ID and archivePath - * - * @param manager the deployment manager + * + * @param manager the deployment manager * @param provider the app provider - * @param originId - * the origin ID (The ID that the {@link AppProvider} knows - * about) + * @param originId the origin ID (The ID that the {@link AppProvider} knows + * about) + * @param context Some implementations of AppProvider might have to use an + * already created ContextHandler. * @see App#getOriginId() * @see App#getContextPath() - * @param context - * Some implementations of AppProvider might have to use an - * already created ContextHandler. */ public App(DeploymentManager manager, AppProvider provider, String originId, ContextHandler context) { - this(manager,provider,originId); + this(manager, provider, originId); _context = context; } - /* ------------------------------------------------------------ */ /** * @return The deployment manager */ @@ -78,7 +74,6 @@ public class App return _manager; } - /* ------------------------------------------------------------ */ /** * @return The AppProvider */ @@ -87,15 +82,14 @@ public class App return _provider; } - /* ------------------------------------------------------------ */ /** * Get ContextHandler for the App. - * + * * Create it if needed. - * + * * @return the {@link ContextHandler} to use for the App when fully started. - * (Portions of which might be ignored when App is not yet - * {@link AppLifeCycle#DEPLOYED} or {@link AppLifeCycle#STARTED}) + * (Portions of which might be ignored when App is not yet + * {@link AppLifeCycle#DEPLOYED} or {@link AppLifeCycle#STARTED}) * @throws Exception if unable to get the context handler */ public ContextHandler getContextHandler() throws Exception @@ -103,9 +97,9 @@ public class App if (_context == null) { _context = getAppProvider().createContextHandler(this); - + AttributesMap attributes = _manager.getContextAttributes(); - if (attributes!=null && attributes.size()>0) + if (attributes != null && attributes.size() > 0) { // Merge the manager attributes under the existing attributes attributes = new AttributesMap(attributes); @@ -116,28 +110,26 @@ public class App return _context; } - /** * The context path {@link App} relating to how it is installed on the * jetty server side. - * + * * NOTE that although the method name indicates that this is a unique * identifier, it is not, as many contexts may have the same contextPath, * yet different virtual hosts. - * - * @deprecated Use getContextPath instead. + * * @return the context path for the App + * @deprecated Use getContextPath instead. */ public String getContextId() { return getContextPath(); } - - + /** * The context path {@link App} relating to how it is installed on the * jetty server side. - * + * * @return the contextPath for the App */ public String getContextPath() @@ -149,10 +141,9 @@ public class App return this._context.getContextPath(); } - /** * The origin of this {@link App} as specified by the {@link AppProvider} - * + * * @return String representing the origin of this app. */ public String getOriginId() diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/AppLifeCycle.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/AppLifeCycle.java index 3035dcd4768..e789ca62677 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/AppLifeCycle.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/AppLifeCycle.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -44,24 +44,21 @@ public class AppLifeCycle extends Graph private static final String ALL_NODES = "*"; - public static interface Binding + public interface Binding { /** * Get a list of targets that this implementation should bind to. - * + * * @return the array of String node names to bind to. (use "*" to bind to all known node names) */ String[] getBindingTargets(); /** * Event called to process a {@link AppLifeCycle} binding. - * - * @param node - * the node being processed - * @param app - * the app being processed - * @throws Exception - * if any problem severe enough to halt the AppLifeCycle processing + * + * @param node the node being processed + * @param app the app being processed + * @throws Exception if any problem severe enough to halt the AppLifeCycle processing */ void processBinding(Node node, App app) throws Exception; } @@ -75,8 +72,7 @@ public class AppLifeCycle extends Graph public static final String STOPPING = "stopping"; public static final String UNDEPLOYING = "undeploying"; public static final String FAILED = "failed"; - - + private Map> lifecyclebindings = new HashMap>(); public AppLifeCycle() @@ -84,20 +80,20 @@ public class AppLifeCycle extends Graph // Define Default Graph // undeployed -> deployed - addEdge(UNDEPLOYED,DEPLOYING); - addEdge(DEPLOYING,DEPLOYED); + addEdge(UNDEPLOYED, DEPLOYING); + addEdge(DEPLOYING, DEPLOYED); // deployed -> started - addEdge(DEPLOYED,STARTING); - addEdge(STARTING,STARTED); + addEdge(DEPLOYED, STARTING); + addEdge(STARTING, STARTED); // started -> deployed - addEdge(STARTED,STOPPING); - addEdge(STOPPING,DEPLOYED); + addEdge(STARTED, STOPPING); + addEdge(STOPPING, DEPLOYED); // deployed -> undeployed - addEdge(DEPLOYED,UNDEPLOYING); - addEdge(UNDEPLOYING,UNDEPLOYED); + addEdge(DEPLOYED, UNDEPLOYING); + addEdge(UNDEPLOYING, UNDEPLOYED); // failed (unconnected) addNode(new Node(FAILED)); @@ -114,10 +110,10 @@ public class AppLifeCycle extends Graph } bindings.add(binding); - lifecyclebindings.put(nodeName,bindings); + lifecyclebindings.put(nodeName, bindings); } } - + public void removeBinding(AppLifeCycle.Binding binding) { for (String nodeName : binding.getBindingTargets()) @@ -130,7 +126,7 @@ public class AppLifeCycle extends Graph /** * Get all {@link Node} bound objects. - * + * * @return Set of Object(s) for all lifecycle bindings. never null. */ public Set getBindings() @@ -147,8 +143,8 @@ public class AppLifeCycle extends Graph /** * Get all objects bound to a specific {@link Node} - * - * @param node the deployment graph node + * + * @param node the deployment graph node * @return Set of Object(s) for specific lifecycle bindings. never null. */ public Set getBindings(Node node) @@ -158,8 +154,8 @@ public class AppLifeCycle extends Graph /** * Get all objects bound to a specific {@link Node} - * - * @param nodeName the node name + * + * @param nodeName the node name * @return Set of Object(s) for specific lifecycle bindings. never null. */ public Set getBindings(String nodeName) @@ -188,8 +184,8 @@ public class AppLifeCycle extends Graph for (Binding binding : getBindings(node)) { if (LOG.isDebugEnabled()) - LOG.debug("Calling " + binding.getClass().getName()+" for "+app); - binding.processBinding(node,app); + LOG.debug("Calling " + binding.getClass().getName() + " for " + app); + binding.processBinding(node, app); } } } diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/AppProvider.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/AppProvider.java index d2c12b82c58..2f186c29579 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/AppProvider.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/AppProvider.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -30,15 +30,15 @@ public interface AppProvider extends LifeCycle { /** * Set the Deployment Manager - * + * * @param deploymentManager the deployment manager - * @throws IllegalStateException - * if the provider {@link #isRunning()}. + * @throws IllegalStateException if the provider {@link #isRunning()}. */ void setDeploymentManager(DeploymentManager deploymentManager); - - /* ------------------------------------------------------------ */ - /** Create a ContextHandler for an App + + /** + * Create a ContextHandler for an App + * * @param app The App * @return A ContextHandler * @throws IOException if unable to create context diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/ConfigurationManager.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/ConfigurationManager.java index 7ad819df9ea..b7759dc8e36 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/ConfigurationManager.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/ConfigurationManager.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -22,10 +22,10 @@ import java.util.Map; /** * ConfigurationManager - * + * * Type for allow injection of property values for replacement in jetty xml files during deployment. */ public interface ConfigurationManager { - public Map getProperties(); + Map getProperties(); } diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/DeploymentManager.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/DeploymentManager.java index 48648c606c0..4b8f3d96c1d 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/DeploymentManager.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/DeploymentManager.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -40,6 +40,7 @@ import org.eclipse.jetty.deploy.graph.Path; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.ContextHandlerCollection; import org.eclipse.jetty.util.AttributesMap; +import org.eclipse.jetty.util.MultiException; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.annotation.ManagedOperation; @@ -68,6 +69,7 @@ import org.eclipse.jetty.xml.XmlConfiguration; public class DeploymentManager extends ContainerLifeCycle { private static final Logger LOG = Log.getLogger(DeploymentManager.class); + private MultiException onStartupErrors; /** * Represents a single tracked app within the deployment manager. @@ -76,7 +78,7 @@ public class DeploymentManager extends ContainerLifeCycle { /** * Version of the app. - * + * * Note: Auto-increments on each {@link DeploymentManager#addApp(App)} */ private int version; @@ -119,7 +121,7 @@ public class DeploymentManager extends ContainerLifeCycle void setLifeCycleNode(Node node) { this.lifecyleNode = node; - this.stateTimestamps.put(node,Long.valueOf(System.currentTimeMillis())); + this.stateTimestamps.put(node, Long.valueOf(System.currentTimeMillis())); } } @@ -133,13 +135,14 @@ public class DeploymentManager extends ContainerLifeCycle /** * Receive an app for processing. - * + * * Most commonly used by the various {@link AppProvider} implementations. + * * @param app the app */ public void addApp(App app) { - LOG.debug("Deployable added: {}",app.getOriginId()); + LOG.debug("Deployable added: {}", app.getOriginId()); AppEntry entry = new AppEntry(); entry.app = app; entry.setLifeCycleNode(_lifecycle.getNodeByName("undeployed")); @@ -148,40 +151,42 @@ public class DeploymentManager extends ContainerLifeCycle if (isRunning() && _defaultLifeCycleGoal != null) { // Immediately attempt to go to default lifecycle state - this.requestAppGoal(entry,_defaultLifeCycleGoal); + this.requestAppGoal(entry, _defaultLifeCycleGoal); } } - /* ------------------------------------------------------------ */ - /** Set the AppProviders. - * The providers passed are added via {@link #addBean(Object)} so that + /** + * Set the AppProviders. + * The providers passed are added via {@link #addBean(Object)} so that * their lifecycles may be managed as a {@link ContainerLifeCycle}. + * * @param providers the app provider list */ public void setAppProviders(Collection providers) { if (isRunning()) throw new IllegalStateException(); - + _providers.clear(); removeBeans(); - for (AppProvider provider:providers) + for (AppProvider provider : providers) + { if (_providers.add(provider)) addBean(provider); + } } - @ManagedAttribute("Application Providers") public Collection getAppProviders() { return Collections.unmodifiableList(_providers); } - + public void addAppProvider(AppProvider provider) { if (isRunning()) throw new IllegalStateException(); _providers.add(provider); - addBean(provider); + addBean(provider); } public void setLifeCycleBindings(Collection bindings) @@ -189,16 +194,20 @@ public class DeploymentManager extends ContainerLifeCycle if (isRunning()) throw new IllegalStateException(); for (AppLifeCycle.Binding b : _lifecycle.getBindings()) + { _lifecycle.removeBinding(b); + } for (AppLifeCycle.Binding b : bindings) + { _lifecycle.addBinding(b); + } } public Collection getLifeCycleBindings() { return Collections.unmodifiableSet(_lifecycle.getBindings()); } - + public void addLifeCycleBinding(AppLifeCycle.Binding binding) { _lifecycle.addBinding(binding); @@ -206,7 +215,7 @@ public class DeploymentManager extends ContainerLifeCycle /** * Convenience method to allow for insertion of nodes into the lifecycle. - * + * * @param existingFromNodeName the existing node start * @param existingToNodeName the existing node end * @param insertedNodeName the new node to create between the existing nodes @@ -215,16 +224,16 @@ public class DeploymentManager extends ContainerLifeCycle { Node fromNode = _lifecycle.getNodeByName(existingFromNodeName); Node toNode = _lifecycle.getNodeByName(existingToNodeName); - Edge edge = new Edge(fromNode,toNode); - _lifecycle.insertNode(edge,insertedNodeName); + Edge edge = new Edge(fromNode, toNode); + _lifecycle.insertNode(edge, insertedNodeName); } @Override protected void doStart() throws Exception { - if (getContexts()==null) + if (getContexts() == null) throw new IllegalStateException("No Contexts"); - + if (_useStandardBindings) { LOG.debug("DeploymentManager using standard bindings"); @@ -239,6 +248,12 @@ public class DeploymentManager extends ContainerLifeCycle { startAppProvider(provider); } + + if (onStartupErrors != null) + { + onStartupErrors.ifExceptionThrow(); + } + super.doStart(); } @@ -254,7 +269,7 @@ public class DeploymentManager extends ContainerLifeCycle } catch (Exception e) { - LOG.warn("Unable to start AppProvider",e); + LOG.warn("Unable to start AppProvider", e); } } super.doStop(); @@ -276,7 +291,7 @@ public class DeploymentManager extends ContainerLifeCycle } return null; } - + public App getAppByOriginId(String originId) { AppEntry entry = findAppByOriginId(originId); @@ -292,10 +307,9 @@ public class DeploymentManager extends ContainerLifeCycle return Collections.unmodifiableCollection(_apps); } - @ManagedAttribute("Deployed Apps") public Collection getApps() { - List ret = new ArrayList< >(); + List ret = new ArrayList<>(); for (AppEntry entry : _apps) { ret.add(entry.app); @@ -305,15 +319,14 @@ public class DeploymentManager extends ContainerLifeCycle /** * Get Set of {@link App}s by {@link Node} - * - * @param node - * the node to look for. + * + * @param node the node to look for. * @return the collection of apps for the node */ public Collection getApps(Node node) { Objects.requireNonNull(node); - + List ret = new ArrayList<>(); for (AppEntry entry : _apps) { @@ -359,7 +372,7 @@ public class DeploymentManager extends ContainerLifeCycle /** * Get a contextAttribute that will be set for every Context deployed by this provider. - * + * * @param name context attribute name * @return the context attribute value */ @@ -400,9 +413,8 @@ public class DeploymentManager extends ContainerLifeCycle /** * Remove the app from the tracking of the DeploymentManager - * - * @param app - * if the app is Unavailable remove it from the deployment manager. + * + * @param app if the app is Unavailable remove it from the deployment manager. */ public void removeApp(App app) { @@ -412,32 +424,32 @@ public class DeploymentManager extends ContainerLifeCycle AppEntry entry = it.next(); if (entry.app.equals(app)) { - if (! AppLifeCycle.UNDEPLOYED.equals(entry.lifecyleNode.getName())) - requestAppGoal(entry.app,AppLifeCycle.UNDEPLOYED); + if (!AppLifeCycle.UNDEPLOYED.equals(entry.lifecyleNode.getName())) + requestAppGoal(entry.app, AppLifeCycle.UNDEPLOYED); it.remove(); - LOG.debug("Deployable removed: {}",entry.app); + LOG.debug("Deployable removed: {}", entry.app); } } } public void removeAppProvider(AppProvider provider) { - if(_providers.remove(provider)) + if (_providers.remove(provider)) removeBean(provider); - + try { provider.stop(); } catch (Exception e) { - LOG.warn("Unable to stop Provider",e); + LOG.warn("Unable to stop Provider", e); } } /** * Remove a contextAttribute that will be set for every Context deployed by this provider. - * + * * @param name the context attribute name */ public void removeContextAttribute(String name) @@ -448,11 +460,9 @@ public class DeploymentManager extends ContainerLifeCycle /** * Move an {@link App} through the {@link AppLifeCycle} to the desired {@link Node}, executing each lifecycle step * in the process to reach the desired state. - * - * @param app - * the app to move through the process - * @param nodeName - * the name of the node to attain + * + * @param app the app to move through the process + * @param nodeName the name of the node to attain */ public void requestAppGoal(App app, String nodeName) { @@ -461,18 +471,16 @@ public class DeploymentManager extends ContainerLifeCycle { throw new IllegalStateException("App not being tracked by Deployment Manager: " + app); } - - requestAppGoal(appentry,nodeName); + + requestAppGoal(appentry, nodeName); } /** * Move an {@link App} through the {@link AppLifeCycle} to the desired {@link Node}, executing each lifecycle step * in the process to reach the desired state. - * - * @param appentry - * the internal appentry to move through the process - * @param nodeName - * the name of the node to attain + * + * @param appentry the internal appentry to move through the process + * @param nodeName the name of the node to attain */ private void requestAppGoal(AppEntry appentry, String nodeName) { @@ -482,7 +490,7 @@ public class DeploymentManager extends ContainerLifeCycle throw new IllegalStateException("Node not present in Deployment Manager: " + nodeName); } // Compute lifecycle steps - Path path = _lifecycle.getPath(appentry.lifecyleNode,destinationNode); + Path path = _lifecycle.getPath(appentry.lifecyleNode, destinationNode); if (path.isEmpty()) { // nothing to do. already there. @@ -501,15 +509,15 @@ public class DeploymentManager extends ContainerLifeCycle while (it.hasNext()) { Node node = it.next(); - LOG.debug("Executing Node {}",node); - _lifecycle.runBindings(node,appentry.app,this); + LOG.debug("Executing Node {}", node); + _lifecycle.runBindings(node, appentry.app, this); appentry.setLifeCycleNode(node); } } } catch (Throwable t) { - LOG.warn("Unable to reach node goal: " + nodeName,t); + LOG.warn("Unable to reach node goal: " + nodeName, t); // migrate to FAILED node Node failed = _lifecycle.getNodeByName(AppLifeCycle.FAILED); appentry.setLifeCycleNode(failed); @@ -522,19 +530,31 @@ public class DeploymentManager extends ContainerLifeCycle // The runBindings failed for 'failed' node LOG.ignore(ignore); } + + if (isStarting()) + { + addOnStartupError(t); + } } } + private synchronized void addOnStartupError(Throwable cause) + { + if (onStartupErrors == null) + { + onStartupErrors = new MultiException(); + } + onStartupErrors.add(cause); + } + /** * Move an {@link App} through the {@link AppLifeCycle} to the desired {@link Node}, executing each lifecycle step * in the process to reach the desired state. - * - * @param appId - * the id of the app to move through the process - * @param nodeName - * the name of the node to attain + * + * @param appId the id of the app to move through the process + * @param nodeName the name of the node to attain */ - @ManagedOperation(value="request the app to be moved to the specified lifecycle node", impact="ACTION") + @ManagedOperation(value = "request the app to be moved to the specified lifecycle node", impact = "ACTION") public void requestAppGoal(@Name("appId") String appId, @Name("nodeName") String nodeName) { AppEntry appentry = findAppByOriginId(appId); @@ -542,18 +562,18 @@ public class DeploymentManager extends ContainerLifeCycle { throw new IllegalStateException("App not being tracked by Deployment Manager: " + appId); } - requestAppGoal(appentry,nodeName); + requestAppGoal(appentry, nodeName); } /** * Set a contextAttribute that will be set for every Context deployed by this provider. - * + * * @param name the context attribute name * @param value the context attribute value */ public void setContextAttribute(String name, Object value) { - _contextAttributes.setAttribute(name,value); + _contextAttributes.setAttribute(name, value); } public void setContextAttributes(AttributesMap contextAttributes) @@ -580,7 +600,7 @@ public class DeploymentManager extends ContainerLifeCycle } catch (Exception e) { - LOG.warn("Unable to start AppProvider",e); + LOG.warn("Unable to start AppProvider", e); } } @@ -589,7 +609,7 @@ public class DeploymentManager extends ContainerLifeCycle LOG.debug("Undeploy All"); for (AppEntry appentry : _apps) { - requestAppGoal(appentry,"undeployed"); + requestAppGoal(appentry, "undeployed"); } } @@ -616,6 +636,6 @@ public class DeploymentManager extends ContainerLifeCycle public void scope(XmlConfiguration xmlc, Resource webapp) throws IOException { - xmlc.setJettyStandardIdsAndProperties(getServer(),webapp); + xmlc.setJettyStandardIdsAndProperties(getServer(), webapp); } } diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/PropertiesConfigurationManager.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/PropertiesConfigurationManager.java index 5bf50024a74..b1ad5470221 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/PropertiesConfigurationManager.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/PropertiesConfigurationManager.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -33,27 +33,27 @@ import org.eclipse.jetty.util.resource.Resource; /** * FileConfigurationManager - * + * * Supplies properties defined in a file. */ @ManagedObject("Configure deployed webapps via properties") public class PropertiesConfigurationManager implements ConfigurationManager { private String _properties; - private final Map _map = new HashMap(); + private final Map _map = new HashMap(); public PropertiesConfigurationManager(String properties) { } - + public PropertiesConfigurationManager() { } @ManagedAttribute("A file or URL of properties") - public void setFile(String resource) throws MalformedURLException, IOException + public void setFile(String resource) throws IOException { - _properties=resource; + _properties = resource; _map.clear(); loadProperties(_properties); } @@ -62,13 +62,13 @@ public class PropertiesConfigurationManager implements ConfigurationManager { return _properties; } - + @ManagedOperation("Set a property") - public void put(@Name("name")String name, @Name("value")String value) + public void put(@Name("name") String name, @Name("value") String value) { - _map.put(name,value); + _map.put(name, value); } - + /** * @see org.eclipse.jetty.deploy.ConfigurationManager#getProperties() */ @@ -78,15 +78,17 @@ public class PropertiesConfigurationManager implements ConfigurationManager return new HashMap<>(_map); } - private void loadProperties(String resource) throws FileNotFoundException, IOException - { - Resource file=Resource.newResource(resource); - if (file!=null && file.exists()) + private void loadProperties(String resource) throws IOException + { + Resource file = Resource.newResource(resource); + if (file != null && file.exists()) { Properties properties = new Properties(); properties.load(file.getInputStream()); for (Map.Entry entry : properties.entrySet()) - _map.put(entry.getKey().toString(),String.valueOf(entry.getValue())); + { + _map.put(entry.getKey().toString(), String.valueOf(entry.getValue())); + } } } } diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/DebugBinding.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/DebugBinding.java index a3db7dba23e..8f29bc38f65 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/DebugBinding.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/DebugBinding.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -29,17 +29,17 @@ public class DebugBinding implements AppLifeCycle.Binding private static final Logger LOG = Log.getLogger(DebugBinding.class); final String[] _targets; - + public DebugBinding(String target) { - _targets=new String[]{target}; + _targets = new String[]{target}; } - + public DebugBinding(final String... targets) { - _targets=targets; + _targets = targets; } - + @Override public String[] getBindingTargets() { @@ -49,6 +49,6 @@ public class DebugBinding implements AppLifeCycle.Binding @Override public void processBinding(Node node, App app) throws Exception { - LOG.info("processBinding {} {}",node,app.getContextHandler()); + LOG.info("processBinding {} {}", node, app.getContextHandler()); } } diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/DebugListenerBinding.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/DebugListenerBinding.java index cef0ad3ec66..1a6b237fa54 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/DebugListenerBinding.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/DebugListenerBinding.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -22,8 +22,8 @@ import org.eclipse.jetty.deploy.App; import org.eclipse.jetty.deploy.graph.Node; import org.eclipse.jetty.server.DebugListener; - -/** A Deployment binding that installs a DebugListener in all deployed contexts +/** + * A Deployment binding that installs a DebugListener in all deployed contexts */ public class DebugListenerBinding extends DebugBinding { @@ -33,22 +33,21 @@ public class DebugListenerBinding extends DebugBinding { this(new DebugListener()); } - + public DebugListenerBinding(DebugListener debugListener) { super(new String[]{"deploying"}); - _debugListener=debugListener; + _debugListener = debugListener; } - + public DebugListener getDebugListener() { return _debugListener; } - + @Override public void processBinding(Node node, App app) throws Exception { app.getContextHandler().addEventListener(_debugListener); } - } diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/GlobalWebappConfigBinding.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/GlobalWebappConfigBinding.java index f5832d8dd24..4823b765ccb 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/GlobalWebappConfigBinding.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/GlobalWebappConfigBinding.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,8 +18,6 @@ package org.eclipse.jetty.deploy.bindings; -import java.io.File; - import org.eclipse.jetty.deploy.App; import org.eclipse.jetty.deploy.AppLifeCycle; import org.eclipse.jetty.deploy.graph.Node; @@ -42,13 +40,11 @@ import org.eclipse.jetty.xml.XmlConfiguration; * * Note: Currently properties from startup will not be available for * reference. - * */ public class GlobalWebappConfigBinding implements AppLifeCycle.Binding { private static final Logger LOG = Log.getLogger(GlobalWebappConfigBinding.class); - private String _jettyXml; public String getJettyXml() @@ -64,7 +60,7 @@ public class GlobalWebappConfigBinding implements AppLifeCycle.Binding @Override public String[] getBindingTargets() { - return new String[] { "deploying" }; + return new String[]{"deploying"}; } @Override @@ -85,7 +81,7 @@ public class GlobalWebappConfigBinding implements AppLifeCycle.Binding LOG.debug("Binding: Configuring webapp context with global settings from: " + _jettyXml); } - if ( _jettyXml == null ) + if (_jettyXml == null) { LOG.warn("Binding: global context binding is enabled but no jetty-web.xml file has been registered"); } @@ -94,9 +90,9 @@ public class GlobalWebappConfigBinding implements AppLifeCycle.Binding if (globalContextSettings.exists()) { - XmlConfiguration jettyXmlConfig = new XmlConfiguration(globalContextSettings.getInputStream()); + XmlConfiguration jettyXmlConfig = new XmlConfiguration(globalContextSettings); Resource resource = Resource.newResource(app.getOriginId()); - app.getDeploymentManager().scope(jettyXmlConfig,resource); + app.getDeploymentManager().scope(jettyXmlConfig, resource); jettyXmlConfig.configure(context); } else @@ -105,5 +101,4 @@ public class GlobalWebappConfigBinding implements AppLifeCycle.Binding } } } - } diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/OrderedGroupBinding.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/OrderedGroupBinding.java index 68f42b6df8e..8881bb62fc9 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/OrderedGroupBinding.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/OrderedGroupBinding.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -25,44 +25,43 @@ import org.eclipse.jetty.deploy.AppLifeCycle; import org.eclipse.jetty.deploy.graph.Node; /** - * Provides a way of forcing the ordered execution of bindings within + * Provides a way of forcing the ordered execution of bindings within * a declared binding target. - * */ public class OrderedGroupBinding implements AppLifeCycle.Binding { private String[] _bindingTargets; - + private LinkedList _orderedBindings; - - public OrderedGroupBinding( String[] bindingTargets ) - { + + public OrderedGroupBinding(String[] bindingTargets) + { _bindingTargets = bindingTargets; } - + public void addBinding(AppLifeCycle.Binding binding) { - if ( _orderedBindings == null ) - { + if (_orderedBindings == null) + { _orderedBindings = new LinkedList(); - } - + } + _orderedBindings.add(binding); } - + public void addBindings(AppLifeCycle.Binding[] bindings) { - if ( _orderedBindings == null ) + if (_orderedBindings == null) { - _orderedBindings = new LinkedList(); + _orderedBindings = new LinkedList(); } - + for (AppLifeCycle.Binding binding : bindings) { _orderedBindings.add(binding); } } - + @Override public String[] getBindingTargets() { @@ -72,9 +71,9 @@ public class OrderedGroupBinding implements AppLifeCycle.Binding @Override public void processBinding(Node node, App app) throws Exception { - for ( AppLifeCycle.Binding binding : _orderedBindings ) + for (AppLifeCycle.Binding binding : _orderedBindings) { - binding.processBinding(node,app); + binding.processBinding(node, app); } } } diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/StandardDeployer.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/StandardDeployer.java index f98cadeac85..74265086d27 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/StandardDeployer.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/StandardDeployer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -22,6 +22,7 @@ import org.eclipse.jetty.deploy.App; import org.eclipse.jetty.deploy.AppLifeCycle; import org.eclipse.jetty.deploy.graph.Node; import org.eclipse.jetty.server.handler.ContextHandler; +import org.eclipse.jetty.util.Callback; public class StandardDeployer implements AppLifeCycle.Binding { @@ -29,7 +30,7 @@ public class StandardDeployer implements AppLifeCycle.Binding public String[] getBindingTargets() { return new String[] - { "deploying" }; + {"deploying"}; } @Override @@ -37,9 +38,10 @@ public class StandardDeployer implements AppLifeCycle.Binding { ContextHandler handler = app.getContextHandler(); if (handler == null) - { throw new NullPointerException("No Handler created for App: " + app); - } - app.getDeploymentManager().getContexts().addHandler(handler); + + Callback.Completable blocker = new Callback.Completable(); + app.getDeploymentManager().getContexts().deployHandler(handler, blocker); + blocker.get(); } } diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/StandardStarter.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/StandardStarter.java index 30403641ae7..ca163866e3b 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/StandardStarter.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/StandardStarter.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -30,7 +30,7 @@ public class StandardStarter implements AppLifeCycle.Binding public String[] getBindingTargets() { return new String[] - { "starting" }; + {"starting"}; } @Override diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/StandardStopper.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/StandardStopper.java index 7d25afb1d10..b93a65943d5 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/StandardStopper.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/StandardStopper.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -29,17 +29,17 @@ public class StandardStopper implements AppLifeCycle.Binding public String[] getBindingTargets() { return new String[] - { "stopping" }; + {"stopping"}; } @Override public void processBinding(Node node, App app) throws Exception { ContextHandler handler = app.getContextHandler(); - + // Before stopping, take back management from the context app.getDeploymentManager().getContexts().unmanage(handler); - + // Stop it handler.stop(); } diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/StandardUndeployer.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/StandardUndeployer.java index 7336a4a54fa..562f3e1efe1 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/StandardUndeployer.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/StandardUndeployer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -21,54 +21,27 @@ package org.eclipse.jetty.deploy.bindings; import org.eclipse.jetty.deploy.App; import org.eclipse.jetty.deploy.AppLifeCycle; import org.eclipse.jetty.deploy.graph.Node; -import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandlerCollection; -import org.eclipse.jetty.server.handler.HandlerCollection; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.util.Callback; public class StandardUndeployer implements AppLifeCycle.Binding { - private static final Logger LOG = Log.getLogger(StandardUndeployer.class); - @Override public String[] getBindingTargets() { return new String[] - { "undeploying" }; + {"undeploying"}; } @Override public void processBinding(Node node, App app) throws Exception { - ContextHandler handler = app.getContextHandler(); - ContextHandlerCollection chcoll = app.getDeploymentManager().getContexts(); - - recursiveRemoveContext(chcoll,handler); - } - - private void recursiveRemoveContext(HandlerCollection coll, ContextHandler context) - { - Handler children[] = coll.getHandlers(); - int originalCount = children.length; - - for (int i = 0, n = children.length; i < n; i++) - { - Handler child = children[i]; - LOG.debug("Child handler {}",child); - if (child.equals(context)) - { - LOG.debug("Removing handler {}",child); - coll.removeHandler(child); - child.destroy(); - if (LOG.isDebugEnabled()) - LOG.debug("After removal: {} (originally {})",coll.getHandlers().length,originalCount); - } - else if (child instanceof HandlerCollection) - { - recursiveRemoveContext((HandlerCollection)child,context); - } - } + ContextHandlerCollection contexts = app.getDeploymentManager().getContexts(); + ContextHandler context = app.getContextHandler(); + Callback.Completable blocker = new Callback.Completable(); + contexts.undeployHandler(context, blocker); + blocker.get(); + context.destroy(); } } diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/package-info.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/package-info.java index eee11ea11df..db37dd12056 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/package-info.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/graph/Edge.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/graph/Edge.java index 83fec32fcc4..9b1d781cfc5 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/graph/Edge.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/graph/Edge.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -29,9 +29,9 @@ public final class Edge public Edge(Node from, Node to) { @SuppressWarnings("ReferenceEquality") - boolean sameObject = (from==to); - if (from==null || to==null || sameObject) - throw new IllegalArgumentException("from "+from+" to "+to); + boolean sameObject = (from == to); + if (from == null || to == null || sameObject) + throw new IllegalArgumentException("from " + from + " to " + to); _from = from; _to = to; } @@ -61,27 +61,25 @@ public final class Edge return false; if (_to == null) { - if (other._to != null) - return false; + return other._to == null; } - else if (!_to.equals(other._to)) - return false; - return true; + else + return _to.equals(other._to); } public Node getFrom() { return _from; } - + public Node getTo() { return _to; } - + @Override public String toString() { - return _from+"->"+_to; + return _from + "->" + _to; } } diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/graph/Graph.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/graph/Graph.java index a0fe24a7c95..6c59f8a7b0e 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/graph/Graph.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/graph/Graph.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -33,41 +33,41 @@ public class Graph public void addEdge(Edge edge) { Node fromNode = getNodeByName(edge.getFrom().getName()); - if (fromNode==null) - addNode(fromNode=edge.getFrom()); + if (fromNode == null) + addNode(fromNode = edge.getFrom()); Node toNode = getNodeByName(edge.getTo().getName()); - if (toNode==null) - addNode(toNode=edge.getTo()); - + if (toNode == null) + addNode(toNode = edge.getTo()); + // replace edge with normalized edge if (!edge.getFrom().equals(fromNode) || !edge.getTo().equals(toNode)) - edge=new Edge(fromNode,toNode); - + edge = new Edge(fromNode, toNode); + this._edges.add(edge); } public void addEdge(String from, String to) { Node fromNode = getNodeByName(from); - if (fromNode==null) + if (fromNode == null) { fromNode = new Node(from); addNode(fromNode); } - + Node toNode = getNodeByName(to); - if (toNode==null) + if (toNode == null) { toNode = new Node(to); addNode(toNode); } - addEdge(fromNode,toNode); + addEdge(fromNode, toNode); } private void addEdge(Node fromNode, Node toNode) { - Edge edge = new Edge(fromNode,toNode); + Edge edge = new Edge(fromNode, toNode); addEdge(edge); } @@ -78,30 +78,26 @@ public class Graph /** * Convenience method for {@link #insertNode(Edge, Node)} - * - * @param edge - * the edge to split and insert a node into - * @param nodeName - * the name of the node to insert along the edge + * + * @param edge the edge to split and insert a node into + * @param nodeName the name of the node to insert along the edge */ public void insertNode(Edge edge, String nodeName) { Node node = getNodeByName(nodeName); - if (node==null) + if (node == null) { node = new Node(nodeName); } - insertNode(edge,node); + insertNode(edge, node); } /** * Insert an arbitrary node on an existing edge. - * - * @param edge - * the edge to split and insert a node into - * @param node - * the node to insert along the edge + * + * @param edge the edge to split and insert a node into + * @param node the node to insert along the edge */ public void insertNode(Edge edge, Node node) { @@ -110,17 +106,16 @@ public class Graph // Ensure node is added addNode(node); // Add start edge - addEdge(edge.getFrom(),node); + addEdge(edge.getFrom(), node); // Add second edge - addEdge(node,edge.getTo()); + addEdge(node, edge.getTo()); } /** * Find all edges that are connected to the specific node, both as an outgoing {@link Edge#getFrom()} or incoming * {@link Edge#getTo()} end point. - * - * @param node - * the node with potential end points + * + * @param node the node with potential end points * @return the set of edges connected to the node */ public Set findEdges(Node node) @@ -140,9 +135,8 @@ public class Graph /** * Find all edges that are connected {@link Edge#getFrom()} the specific node. - * - * @param from - * the node with potential edges from it + * + * @param from the node with potential edges from it * @return the set of edges from the node */ public Set findEdgesFrom(Node from) @@ -162,11 +156,9 @@ public class Graph /** * Convenience method for {@link #getPath(Node, Node)} - * - * @param nodeNameOrigin - * the name of the node to the path origin. - * @param nodeNameDest - * the name of the node to the path destination. + * + * @param nodeNameOrigin the name of the node to the path origin. + * @param nodeNameDest the name of the node to the path destination. * @return the path to take */ public Path getPath(String nodeNameOrigin, String nodeNameDest) @@ -178,75 +170,71 @@ public class Graph Node from = getNodeByName(nodeNameOrigin); Node to = getNodeByName(nodeNameDest); - return getPath(from,to); + return getPath(from, to); } /** * Using BFS (Breadth First Search) return the path from a any arbitrary node to any other. - * - * @param from - * the node from - * @param to - * the node to + * + * @param from the node from + * @param to the node to * @return the path to take or null if there is no path. */ public Path getPath(Node from, Node to) { @SuppressWarnings("ReferenceEquality") - boolean sameObject = (from==to); + boolean sameObject = (from == to); if (sameObject) { return new Path(); } // Perform a Breadth First Search (BFS) of the tree. - Path path = breadthFirst(from,to,new CopyOnWriteArrayList(),new HashSet()); + Path path = breadthFirst(from, to, new CopyOnWriteArrayList(), new HashSet()); return path; } - private Path breadthFirst(Node from, Node destination, CopyOnWriteArrayList paths, Set seen) { // Add next unseen segments to paths. boolean edgesAdded = false; - if (paths.size()==0) + if (paths.size() == 0) paths.add(new Path()); for (Path path : paths) { - Set next = findEdgesFrom(path.nodes()==0?from:path.lastNode()); + Set next = findEdgesFrom(path.nodes() == 0 ? from : path.lastNode()); if (next.size() == 0) continue; // no new edges // Split path for other edges - int splits=0; - for (Edge edge:next) + int splits = 0; + for (Edge edge : next) { if (seen.contains(edge)) continue; seen.add(edge); - Path nextPath = (++splits==next.size())?path:path.forkPath(); + Path nextPath = (++splits == next.size()) ? path : path.forkPath(); // Add segment to split'd path nextPath.add(edge); - + // Are we there yet? if (destination.equals(edge.getTo())) return nextPath; edgesAdded = true; - + // Add to extra paths - if (nextPath!=path) + if (nextPath != path) paths.add(nextPath); } } if (edgesAdded) - return breadthFirst(from,destination,paths,seen); + return breadthFirst(from, destination, paths, seen); return null; } - public Set getEdges() { return _edges; @@ -254,9 +242,8 @@ public class Graph /** * Get the Node by Name. - * - * @param name - * the name to lookup + * + * @param name the name to lookup * @return the node if found or null if not found. */ public Node getNodeByName(String name) @@ -285,7 +272,7 @@ public class Graph { Node fromNode = getNodeByName(fromNodeName); Node toNode = getNodeByName(toNodeName); - Edge edge = new Edge(fromNode,toNode); + Edge edge = new Edge(fromNode, toNode); removeEdge(edge); } diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/graph/GraphOutputDot.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/graph/GraphOutputDot.java index 90753a792f9..f462d5b400f 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/graph/GraphOutputDot.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/graph/GraphOutputDot.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -43,7 +43,7 @@ public class GraphOutputDot /** * Comparator that makes the 'undeployed' node the first node in the sort list. - * + * * This makes the 'undeployed' node show up at the top of the generated graph. */ private static class TopNodeSort implements Comparator @@ -96,12 +96,12 @@ public class GraphOutputDot for (Node node : nodes) { - writeNode(out,node); + writeNode(out, node); } for (Edge edge : graph.getEdges()) { - writeEdge(out,edge); + writeEdge(out, edge); } out.println("}"); @@ -117,7 +117,7 @@ public class GraphOutputDot { out.println(); out.println(" // Edge"); - out.printf(" \"%s\" -> \"%s\" [%n",toId(edge.getFrom()),toId(edge.getTo())); + out.printf(" \"%s\" -> \"%s\" [%n", toId(edge.getFrom()), toId(edge.getTo())); out.println(" arrowtail=none,"); out.println(" arrowhead=normal"); out.println(" ];"); @@ -127,8 +127,8 @@ public class GraphOutputDot { out.println(); out.println(" // Node"); - out.printf(" \"%s\" [%n",toId(node)); - out.printf(" label=\"%s\",%n",node.getName()); + out.printf(" \"%s\" [%n", toId(node)); + out.printf(" label=\"%s\",%n", node.getName()); if (node.getName().endsWith("ed")) { out.println(" color=\"#ddddff\","); diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/graph/Node.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/graph/Node.java index 3fc75a0a8c5..ad779ff2e4c 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/graph/Node.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/graph/Node.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -27,7 +27,7 @@ public final class Node public Node(String name) { - assert name!=null; + assert name != null; this._name = name; } @@ -60,11 +60,9 @@ public final class Node Node other = (Node)obj; if (_name == null) { - if (other._name != null) - return false; + return other._name == null; } - else if (!_name.equals(other._name)) - return false; - return true; + else + return _name.equals(other._name); } } diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/graph/Path.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/graph/Path.java index 950eed16695..2e2c5d5b12c 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/graph/Path.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/graph/Path.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/graph/package-info.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/graph/package-info.java index 40e5bedf610..0b9feab60e8 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/graph/package-info.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/graph/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/jmx/DeploymentManagerMBean.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/jmx/DeploymentManagerMBean.java index 165d10a122a..42f076ed0a6 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/jmx/DeploymentManagerMBean.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/jmx/DeploymentManagerMBean.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -24,11 +24,11 @@ import java.util.List; import java.util.stream.Collectors; import org.eclipse.jetty.deploy.App; -import org.eclipse.jetty.deploy.AppProvider; import org.eclipse.jetty.deploy.DeploymentManager; import org.eclipse.jetty.deploy.graph.Node; import org.eclipse.jetty.jmx.ObjectMBean; import org.eclipse.jetty.server.handler.ContextHandler; +import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.annotation.ManagedOperation; import org.eclipse.jetty.util.annotation.Name; @@ -42,10 +42,10 @@ public class DeploymentManagerMBean extends ObjectMBean public DeploymentManagerMBean(Object managedObject) { super(managedObject); - _manager = (DeploymentManager) managedObject; + _manager = (DeploymentManager)managedObject; } - @ManagedOperation(value = "list apps being tracked", impact = "INFO") + @ManagedAttribute(value = "list apps being tracked") public Collection getApps() { List ret = new ArrayList<>(); @@ -91,13 +91,16 @@ public class DeploymentManagerMBean extends ObjectMBean { List apps = new ArrayList(); for (App app : _manager.getApps()) + { apps.add(app.getContextHandler()); + } return apps; } - public Collection getAppProviders() + @ManagedAttribute("Registered AppProviders") + public List getAppProviders() { - return _manager.getAppProviders(); + return _manager.getAppProviders().stream().map(String::valueOf).collect(Collectors.toList()); } public void requestAppGoal(String appId, String nodeName) diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/jmx/package-info.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/jmx/package-info.java index 0e0e6e0d423..1e7beb0e2b6 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/jmx/package-info.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/jmx/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/package-info.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/package-info.java index d2f6e5c9fb1..5df065738a2 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/package-info.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/ScanningAppProvider.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/ScanningAppProvider.java index 0112a88f7ed..0507816c76b 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/ScanningAppProvider.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/ScanningAppProvider.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -27,6 +27,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.stream.Collectors; import org.eclipse.jetty.deploy.App; import org.eclipse.jetty.deploy.AppProvider; @@ -34,12 +35,14 @@ import org.eclipse.jetty.deploy.DeploymentManager; import org.eclipse.jetty.util.Scanner; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; +import org.eclipse.jetty.util.annotation.ManagedOperation; import org.eclipse.jetty.util.component.AbstractLifeCycle; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.resource.Resource; /** + * */ @ManagedObject("Abstract Provider for loading webapps") public abstract class ScanningAppProvider extends AbstractLifeCycle implements AppProvider @@ -50,12 +53,11 @@ public abstract class ScanningAppProvider extends AbstractLifeCycle implements A private DeploymentManager _deploymentManager; protected FilenameFilter _filenameFilter; - private final List _monitored= new CopyOnWriteArrayList<>(); + private final List _monitored = new CopyOnWriteArrayList<>(); private boolean _recursive = false; private int _scanInterval = 10; private Scanner _scanner; - /* ------------------------------------------------------------ */ private final Scanner.DiscreteListener _scannerListener = new Scanner.DiscreteListener() { @Override @@ -77,26 +79,22 @@ public abstract class ScanningAppProvider extends AbstractLifeCycle implements A } }; - /* ------------------------------------------------------------ */ protected ScanningAppProvider() { } - - /* ------------------------------------------------------------ */ + protected ScanningAppProvider(FilenameFilter filter) { _filenameFilter = filter; } - /* ------------------------------------------------------------ */ protected void setFilenameFilter(FilenameFilter filter) { if (isRunning()) throw new IllegalStateException(); _filenameFilter = filter; } - - /* ------------------------------------------------------------ */ + /** * @return The index of currently deployed applications. */ @@ -105,41 +103,38 @@ public abstract class ScanningAppProvider extends AbstractLifeCycle implements A return _appMap; } - /* ------------------------------------------------------------ */ /** * Called by the Scanner.DiscreteListener to create a new App object. * Isolated in a method so that it is possible to override the default App * object for specialized implementations of the AppProvider. - * - * @param filename - * The file that is the context.xml. It is resolved by - * {@link Resource#newResource(String)} + * + * @param filename The file that is the context.xml. It is resolved by + * {@link Resource#newResource(String)} * @return The App object for this particular context definition file. */ protected App createApp(String filename) { - return new App(_deploymentManager,this,filename); + return new App(_deploymentManager, this, filename); } - /* ------------------------------------------------------------ */ @Override protected void doStart() throws Exception { - if (LOG.isDebugEnabled()) + if (LOG.isDebugEnabled()) LOG.debug(this.getClass().getSimpleName() + ".doStart()"); - if (_monitored.size()==0) + if (_monitored.size() == 0) throw new IllegalStateException("No configuration dir specified"); LOG.info("Deployment monitor " + _monitored + " at interval " + _scanInterval); List files = new ArrayList<>(); - for (Resource resource:_monitored) + for (Resource resource : _monitored) { if (resource.exists() && resource.getFile().canRead()) files.add(resource.getFile()); else - LOG.warn("Does not exist: "+resource); + LOG.warn("Does not exist: " + resource); } - + _scanner = new Scanner(); _scanner.setScanDirs(files); _scanner.setScanInterval(_scanInterval); @@ -150,42 +145,38 @@ public abstract class ScanningAppProvider extends AbstractLifeCycle implements A _scanner.start(); } - /* ------------------------------------------------------------ */ @Override protected void doStop() throws Exception { - if (_scanner!=null) + if (_scanner != null) { _scanner.stop(); _scanner.removeListener(_scannerListener); _scanner = null; } } - - /* ------------------------------------------------------------ */ + protected boolean exists(String path) { return _scanner.exists(path); } - /* ------------------------------------------------------------ */ protected void fileAdded(String filename) throws Exception { - if (LOG.isDebugEnabled()) - LOG.debug("added {}",filename); + if (LOG.isDebugEnabled()) + LOG.debug("added {}", filename); App app = ScanningAppProvider.this.createApp(filename); if (app != null) { - _appMap.put(filename,app); + _appMap.put(filename, app); _deploymentManager.addApp(app); } } - /* ------------------------------------------------------------ */ protected void fileChanged(String filename) throws Exception { - if (LOG.isDebugEnabled()) - LOG.debug("changed {}",filename); + if (LOG.isDebugEnabled()) + LOG.debug("changed {}", filename); App app = _appMap.remove(filename); if (app != null) { @@ -194,25 +185,23 @@ public abstract class ScanningAppProvider extends AbstractLifeCycle implements A app = ScanningAppProvider.this.createApp(filename); if (app != null) { - _appMap.put(filename,app); + _appMap.put(filename, app); _deploymentManager.addApp(app); } } - - /* ------------------------------------------------------------ */ + protected void fileRemoved(String filename) throws Exception { - if (LOG.isDebugEnabled()) - LOG.debug("removed {}",filename); + if (LOG.isDebugEnabled()) + LOG.debug("removed {}", filename); App app = _appMap.remove(filename); if (app != null) _deploymentManager.removeApp(app); } - - /* ------------------------------------------------------------ */ + /** * Get the deploymentManager. - * + * * @return the deploymentManager */ public DeploymentManager getDeploymentManager() @@ -220,88 +209,77 @@ public abstract class ScanningAppProvider extends AbstractLifeCycle implements A return _deploymentManager; } - - /* ------------------------------------------------------------ */ public Resource getMonitoredDirResource() { - if (_monitored.size()==0) + if (_monitored.size() == 0) return null; - if (_monitored.size()>1) + if (_monitored.size() > 1) throw new IllegalStateException(); return _monitored.get(0); } - /* ------------------------------------------------------------ */ public String getMonitoredDirName() { - Resource resource=getMonitoredDirResource(); - return resource==null?null:resource.toString(); + Resource resource = getMonitoredDirResource(); + return resource == null ? null : resource.toString(); } - /* ------------------------------------------------------------ */ @ManagedAttribute("scanning interval to detect changes which need reloaded") public int getScanInterval() { return _scanInterval; } - /* ------------------------------------------------------------ */ @ManagedAttribute("recursive scanning supported") public boolean isRecursive() { return _recursive; } - /* ------------------------------------------------------------ */ @Override public void setDeploymentManager(DeploymentManager deploymentManager) { _deploymentManager = deploymentManager; } - - /* ------------------------------------------------------------ */ + public void setMonitoredResources(List resources) { _monitored.clear(); _monitored.addAll(resources); } - - /* ------------------------------------------------------------ */ + public List getMonitoredResources() { return Collections.unmodifiableList(_monitored); } - - /* ------------------------------------------------------------ */ + public void setMonitoredDirResource(Resource resource) { setMonitoredResources(Collections.singletonList(resource)); } - /* ------------------------------------------------------------ */ public void addScannerListener(Scanner.Listener listener) { _scanner.addListener(listener); } - - /* ------------------------------------------------------------ */ + /** - * @param dir - * Directory to scan for context descriptors or war files + * @param dir Directory to scan for context descriptors or war files */ public void setMonitoredDirName(String dir) { setMonitoredDirectories(Collections.singletonList(dir)); } - /* ------------------------------------------------------------ */ public void setMonitoredDirectories(Collection directories) { try { List resources = new ArrayList<>(); - for (String dir:directories) + for (String dir : directories) + { resources.add(Resource.newResource(dir)); + } setMonitoredResources(resources); } catch (Exception e) @@ -309,16 +287,24 @@ public abstract class ScanningAppProvider extends AbstractLifeCycle implements A throw new IllegalArgumentException(e); } } - - /* ------------------------------------------------------------ */ + protected void setRecursive(boolean recursive) { _recursive = recursive; } - /* ------------------------------------------------------------ */ public void setScanInterval(int scanInterval) { _scanInterval = scanInterval; } + + @ManagedOperation(value = "Scan the monitored directories", impact = "ACTION") + public void scan() + { + LOG.info("Performing scan of monitored directories: {}", + getMonitoredResources().stream().map((r) -> r.getURI().toASCIIString()) + .collect(Collectors.joining(", ", "[", "]")) + ); + _scanner.scan(); + } } diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java index cf73d9bac65..9cc87b055c3 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -34,7 +34,7 @@ import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.webapp.WebAppContext; import org.eclipse.jetty.xml.XmlConfiguration; -/** +/** * The webapps directory scanning provider. *

      * This provider scans one or more directories (typically "webapps") for contexts to @@ -80,7 +80,7 @@ public class WebAppProvider extends ScanningAppProvider } String lowername = name.toLowerCase(Locale.ENGLISH); - File file = new File(dir,name); + File file = new File(dir, name); // ignore hidden files if (lowername.startsWith(".")) @@ -94,19 +94,15 @@ public class WebAppProvider extends ScanningAppProvider return false; // is it an unpacked directory for an existing war file? - if (exists(name+".war")||exists(name+".WAR")) + if (exists(name + ".war") || exists(name + ".WAR")) return false; // is it a directory for an existing xml file? - if (exists(name+".xml")||exists(name+".XML")) + if (exists(name + ".xml") || exists(name + ".XML")) return false; //is it a sccs dir? - if ("cvs".equals(lowername) || "cvsroot".equals(lowername)) - return false; - - // OK to deploy it then - return true; + return !"cvs".equals(lowername) && !"cvsroot".equals(lowername);// OK to deploy it then } // else is it a war file @@ -117,14 +113,10 @@ public class WebAppProvider extends ScanningAppProvider } // else is it a context XML file - if (lowername.endsWith(".xml")) - return true; - - return false; + return lowername.endsWith(".xml"); } } - /* ------------------------------------------------------------ */ public WebAppProvider() { super(); @@ -132,8 +124,9 @@ public class WebAppProvider extends ScanningAppProvider setScanInterval(0); } - /* ------------------------------------------------------------ */ - /** Get the extractWars. + /** + * Get the extractWars. + * * @return the extractWars */ @ManagedAttribute("extract war files") @@ -142,8 +135,9 @@ public class WebAppProvider extends ScanningAppProvider return _extractWars; } - /* ------------------------------------------------------------ */ - /** Set the extractWars. + /** + * Set the extractWars. + * * @param extractWars the extractWars to set */ public void setExtractWars(boolean extractWars) @@ -151,8 +145,9 @@ public class WebAppProvider extends ScanningAppProvider _extractWars = extractWars; } - /* ------------------------------------------------------------ */ - /** Get the parentLoaderPriority. + /** + * Get the parentLoaderPriority. + * * @return the parentLoaderPriority */ @ManagedAttribute("parent classloader has priority") @@ -161,17 +156,19 @@ public class WebAppProvider extends ScanningAppProvider return _parentLoaderPriority; } - /* ------------------------------------------------------------ */ - /** Set the parentLoaderPriority. + /** + * Set the parentLoaderPriority. + * * @param parentLoaderPriority the parentLoaderPriority to set */ public void setParentLoaderPriority(boolean parentLoaderPriority) { _parentLoaderPriority = parentLoaderPriority; } - - /* ------------------------------------------------------------ */ - /** Get the defaultsDescriptor. + + /** + * Get the defaultsDescriptor. + * * @return the defaultsDescriptor */ @ManagedAttribute("default descriptor for webapps") @@ -180,8 +177,9 @@ public class WebAppProvider extends ScanningAppProvider return _defaultsDescriptor; } - /* ------------------------------------------------------------ */ - /** Set the defaultsDescriptor. + /** + * Set the defaultsDescriptor. + * * @param defaultsDescriptor the defaultsDescriptor to set */ public void setDefaultsDescriptor(String defaultsDescriptor) @@ -189,31 +187,29 @@ public class WebAppProvider extends ScanningAppProvider _defaultsDescriptor = defaultsDescriptor; } - /* ------------------------------------------------------------ */ public ConfigurationManager getConfigurationManager() { return _configurationManager; } - - /* ------------------------------------------------------------ */ - /** Set the configurationManager. + + /** + * Set the configurationManager. + * * @param configurationManager the configurationManager to set */ public void setConfigurationManager(ConfigurationManager configurationManager) { _configurationManager = configurationManager; } - - /* ------------------------------------------------------------ */ + /** * @param configurations The configuration class names. */ public void setConfigurationClasses(String[] configurations) { - _configurationClasses = configurations==null?null:(String[])configurations.clone(); - } - - /* ------------------------------------------------------------ */ + _configurationClasses = configurations == null ? null : configurations.clone(); + } + @ManagedAttribute("configuration classes for webapps to be processed through") public String[] getConfigurationClasses() { @@ -231,8 +227,7 @@ public class WebAppProvider extends ScanningAppProvider { _tempDirectory = directory; } - - /* ------------------------------------------------------------ */ + /** * Get the user supplied Work Directory. * @@ -244,7 +239,6 @@ public class WebAppProvider extends ScanningAppProvider return _tempDirectory; } - /* ------------------------------------------------------------ */ protected void initializeWebAppContextDefaults(WebAppContext webapp) { if (_defaultsDescriptor != null) @@ -258,22 +252,21 @@ public class WebAppProvider extends ScanningAppProvider { /* Since the Temp Dir is really a context base temp directory, * Lets set the Temp Directory in a way similar to how WebInfConfiguration does it, - * instead of setting the WebAppContext.setTempDirectory(File). + * instead of setting the WebAppContext.setTempDirectory(File). * If we used .setTempDirectory(File) all webapps will wind up in the * same temp / work directory, overwriting each others work. */ webapp.setAttribute(WebAppContext.BASETEMPDIR, _tempDirectory); } } - - /* ------------------------------------------------------------ */ + @Override public ContextHandler createContextHandler(final App app) throws Exception { Resource resource = Resource.newResource(app.getOriginId()); File file = resource.getFile(); if (!resource.exists()) - throw new IllegalStateException("App resource does not exist "+resource); + throw new IllegalStateException("App resource does not exist " + resource); String context = file.getName(); @@ -293,8 +286,8 @@ public class WebAppProvider extends ScanningAppProvider } } }; - - getDeploymentManager().scope(xmlc,resource); + + getDeploymentManager().scope(xmlc, resource); if (getConfigurationManager() != null) xmlc.getProperties().putAll(getConfigurationManager().getProperties()); @@ -307,17 +300,17 @@ public class WebAppProvider extends ScanningAppProvider else if (FileID.isWebArchiveFile(file)) { // Context Path is the same as the archive. - context = context.substring(0,context.length() - 4); + context = context.substring(0, context.length() - 4); } else { - throw new IllegalStateException("unable to create ContextHandler for "+app); + throw new IllegalStateException("unable to create ContextHandler for " + app); } // Ensure "/" is Not Trailing in context paths. if (context.endsWith("/") && context.length() > 0) { - context = context.substring(0,context.length() - 1); + context = context.substring(0, context.length() - 1); } // Start building the webapplication @@ -331,8 +324,8 @@ public class WebAppProvider extends ScanningAppProvider } else if (context.toLowerCase(Locale.ENGLISH).startsWith("root-")) { - int dash=context.toLowerCase(Locale.ENGLISH).indexOf('-'); - String virtual = context.substring(dash+1); + int dash = context.toLowerCase(Locale.ENGLISH).indexOf('-'); + String virtual = context.substring(dash + 1); webAppContext.setVirtualHosts(new String[]{virtual}); context = URIUtil.SLASH; } @@ -349,49 +342,47 @@ public class WebAppProvider extends ScanningAppProvider return webAppContext; } - - /* ------------------------------------------------------------ */ + @Override protected void fileChanged(String filename) throws Exception - { + { File file = new File(filename); if (!file.exists()) return; - + File parent = file.getParentFile(); - + //is the file that changed a directory? if (file.isDirectory()) { //is there a .xml file of the same name? - if (exists(file.getName()+".xml")||exists(file.getName()+".XML")) + if (exists(file.getName() + ".xml") || exists(file.getName() + ".XML")) return; //ignore it //is there .war file of the same name? - if (exists(file.getName()+".war")||exists(file.getName()+".WAR")) + if (exists(file.getName() + ".war") || exists(file.getName() + ".WAR")) return; //ignore it - super.fileChanged(filename); - return; + super.fileChanged(filename); + return; } - - + String lowname = file.getName().toLowerCase(Locale.ENGLISH); //is the file that changed a .war file? if (lowname.endsWith(".war")) { String name = file.getName(); - String base=name.substring(0,name.length()-4); - String xmlname = base+".xml"; + String base = name.substring(0, name.length() - 4); + String xmlname = base + ".xml"; if (exists(xmlname)) { //if a .xml file exists for it, then redeploy that instead - File xml = new File (parent, xmlname); + File xml = new File(parent, xmlname); super.fileChanged(xml.getCanonicalPath()); return; } - - xmlname = base+".XML"; + + xmlname = base + ".XML"; if (exists(xmlname)) { //if a .XML file exists for it, then redeploy that instead @@ -399,7 +390,7 @@ public class WebAppProvider extends ScanningAppProvider super.fileChanged(xml.getCanonicalPath()); return; } - + //redeploy the changed war super.fileChanged(filename); return; @@ -410,7 +401,6 @@ public class WebAppProvider extends ScanningAppProvider super.fileChanged(filename); } - /* ------------------------------------------------------------ */ @Override protected void fileAdded(String filename) throws Exception { @@ -422,26 +412,25 @@ public class WebAppProvider extends ScanningAppProvider if (file.isDirectory()) { //is there a .xml file of the same name? - if (exists(file.getName()+".xml")||exists(file.getName()+".XML")) + if (exists(file.getName() + ".xml") || exists(file.getName() + ".XML")) return; //assume we will get added events for the xml file //is there .war file of the same name? - if (exists(file.getName()+".war")||exists(file.getName()+".WAR")) + if (exists(file.getName() + ".war") || exists(file.getName() + ".WAR")) return; //assume we will get added events for the war file super.fileAdded(filename); return; } - //is the file that was added a .war file? String lowname = file.getName().toLowerCase(Locale.ENGLISH); if (lowname.endsWith(".war")) { String name = file.getName(); - String base=name.substring(0,name.length()-4); + String base = name.substring(0, name.length() - 4); //is there a .xml file of the same name? - if (exists(base+".xml")||exists(base+".XML")) + if (exists(base + ".xml") || exists(base + ".XML")) return; //ignore it as we should get addition of the xml file super.fileAdded(filename); @@ -453,11 +442,9 @@ public class WebAppProvider extends ScanningAppProvider super.fileAdded(filename); } - - /* ------------------------------------------------------------ */ @Override protected void fileRemoved(String filename) throws Exception - { + { File file = new File(filename); //is the file that was removed a .war file? @@ -466,8 +453,8 @@ public class WebAppProvider extends ScanningAppProvider { //is there a .xml file of the same name? String name = file.getName(); - String base=name.substring(0,name.length()-4); - if (exists(base+".xml")||exists(base+".XML")) + String base = name.substring(0, name.length() - 4); + if (exists(base + ".xml") || exists(base + ".XML")) return; //ignore it as we should get removal of the xml file super.fileRemoved(filename); @@ -482,14 +469,13 @@ public class WebAppProvider extends ScanningAppProvider } //is there a .xml file of the same name? - if (exists(file.getName()+".xml")||exists(file.getName()+".XML")) + if (exists(file.getName() + ".xml") || exists(file.getName() + ".XML")) return; //assume we will get removed events for the xml file //is there .war file of the same name? - if (exists(file.getName()+".war")||exists(file.getName()+".WAR")) + if (exists(file.getName() + ".war") || exists(file.getName() + ".WAR")) return; //assume we will get removed events for the war file super.fileRemoved(filename); } - } diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/jmx/WebAppProviderMBean.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/jmx/WebAppProviderMBean.java new file mode 100644 index 00000000000..55c1a13ee7b --- /dev/null +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/jmx/WebAppProviderMBean.java @@ -0,0 +1,44 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.deploy.providers.jmx; + +import java.util.List; +import java.util.stream.Collectors; + +import org.eclipse.jetty.deploy.providers.WebAppProvider; +import org.eclipse.jetty.server.handler.jmx.AbstractHandlerMBean; +import org.eclipse.jetty.util.annotation.ManagedAttribute; +import org.eclipse.jetty.util.annotation.ManagedObject; + +@ManagedObject("WebAppProvider mbean wrapper") +public class WebAppProviderMBean extends AbstractHandlerMBean +{ + public WebAppProviderMBean(Object managedObject) + { + super(managedObject); + } + + @ManagedAttribute("List of monitored resources") + public List getMonitoredResources() + { + return ((WebAppProvider)_managed).getMonitoredResources().stream() + .map((r) -> r.getURI().toASCIIString()) + .collect(Collectors.toList()); + } +} diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/package-info.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/package-info.java index 6c9eb32866b..dabea2eaa3f 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/package-info.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/util/FileID.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/util/FileID.java index 3415ef9b2be..4bd620aba16 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/util/FileID.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/util/FileID.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -29,9 +29,8 @@ public class FileID { /** * Is the path a Web Archive? - * - * @param path - * the path to test. + * + * @param path the path to test. * @return True if a .war or .jar or exploded web directory * @see FileID#isWebArchiveFile(File) */ @@ -43,16 +42,15 @@ public class FileID return (name.endsWith(".war") || name.endsWith(".jar")); } - File webInf = new File(path,"WEB-INF"); - File webXml = new File(webInf,"web.xml"); + File webInf = new File(path, "WEB-INF"); + File webXml = new File(webInf, "web.xml"); return webXml.exists() && webXml.isFile(); } /** * Is the path a Web Archive File (not directory) - * - * @param path - * the path to test. + * + * @param path the path to test. * @return True if a .war or .jar file. * @see FileID#isWebArchive(File) */ diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/util/package-info.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/util/package-info.java index fd6c3793f9d..81856ab941b 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/util/package-info.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/util/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/AppLifeCyclePathCollector.java b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/AppLifeCyclePathCollector.java index 354ba79963c..454a24296e3 100644 --- a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/AppLifeCyclePathCollector.java +++ b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/AppLifeCyclePathCollector.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,13 +18,12 @@ package org.eclipse.jetty.deploy; -import static org.junit.jupiter.api.Assertions.assertEquals; - import java.util.ArrayList; import java.util.List; import org.eclipse.jetty.deploy.graph.Node; +import static org.junit.jupiter.api.Assertions.assertEquals; /** * Binds to all lifecycle nodes, and tracks the order of the lifecycle nodes for testing purposes. @@ -47,7 +46,7 @@ public class AppLifeCyclePathCollector implements AppLifeCycle.Binding public String[] getBindingTargets() { return new String[] - { "*" }; + {"*"}; } @Override @@ -71,12 +70,12 @@ public class AppLifeCyclePathCollector implements AppLifeCycle.Binding System.out.println(path.getName()); } - assertEquals(expectedOrder.size(),actualOrder.size(),msg + " / count"); + assertEquals(expectedOrder.size(), actualOrder.size(), msg + " / count"); } for (int i = 0, n = expectedOrder.size(); i < n; i++) { - assertEquals(expectedOrder.get(i),actualOrder.get(i).getName(),msg + "[" + i + "]"); + assertEquals(expectedOrder.get(i), actualOrder.get(i).getName(), msg + "[" + i + "]"); } } } diff --git a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/AppLifeCycleTest.java b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/AppLifeCycleTest.java index 3a62b1c734c..8008425d5ae 100644 --- a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/AppLifeCycleTest.java +++ b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/AppLifeCycleTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,9 +18,6 @@ package org.eclipse.jetty.deploy; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; - import java.io.File; import java.io.IOException; import java.util.ArrayList; @@ -34,6 +31,9 @@ import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + /** * Just an overly picky test case to validate the potential paths. */ @@ -44,21 +44,21 @@ public class AppLifeCycleTest private void assertNoPath(String from, String to) { - assertPath(from,to,new ArrayList()); + assertPath(from, to, new ArrayList()); } private void assertPath(AppLifeCycle lifecycle, String from, String to, List expected) { Node fromNode = lifecycle.getNodeByName(from); Node toNode = lifecycle.getNodeByName(to); - Path actual = lifecycle.getPath(fromNode,toNode); + Path actual = lifecycle.getPath(fromNode, toNode); String msg = "LifeCycle path from " + from + " to " + to; - assertNotNull(actual,msg + " should never be null"); + assertNotNull(actual, msg + " should never be null"); if (expected.size() != actual.nodes()) { System.out.println(); - System.out.printf("/* from '%s' -> '%s' */%n",from,to); + System.out.printf("/* from '%s' -> '%s' */%n", from, to); System.out.println("/* Expected Path */"); for (String path : expected) { @@ -70,25 +70,25 @@ public class AppLifeCycleTest System.out.println(path.getName()); } - assertEquals(expected.size(),actual.nodes(),msg + " / count"); + assertEquals(expected.size(), actual.nodes(), msg + " / count"); } for (int i = 0, n = expected.size(); i < n; i++) { - assertEquals(expected.get(i),actual.getNode(i).getName(),msg + "[" + i + "]"); + assertEquals(expected.get(i), actual.getNode(i).getName(), msg + "[" + i + "]"); } } private void assertPath(String from, String to, List expected) { AppLifeCycle lifecycle = new AppLifeCycle(); - assertPath(lifecycle,from,to,expected); + assertPath(lifecycle, from, to, expected); } @Test public void testFindPath_Deployed_Deployed() { - assertNoPath("deployed","deployed"); + assertNoPath("deployed", "deployed"); } @Test @@ -98,7 +98,7 @@ public class AppLifeCycleTest expected.add("deployed"); expected.add("starting"); expected.add("started"); - assertPath("deployed","started",expected); + assertPath("deployed", "started", expected); } @Test @@ -108,7 +108,7 @@ public class AppLifeCycleTest expected.add("deployed"); expected.add("undeploying"); expected.add("undeployed"); - assertPath("deployed","undeployed",expected); + assertPath("deployed", "undeployed", expected); } @Test @@ -118,13 +118,13 @@ public class AppLifeCycleTest expected.add("started"); expected.add("stopping"); expected.add("deployed"); - assertPath("started","deployed",expected); + assertPath("started", "deployed", expected); } @Test public void testFindPath_Started_Started() { - assertNoPath("started","started"); + assertNoPath("started", "started"); } @Test @@ -136,7 +136,7 @@ public class AppLifeCycleTest expected.add("deployed"); expected.add("undeploying"); expected.add("undeployed"); - assertPath("started","undeployed",expected); + assertPath("started", "undeployed", expected); } @Test @@ -146,7 +146,7 @@ public class AppLifeCycleTest expected.add("undeployed"); expected.add("deploying"); expected.add("deployed"); - assertPath("undeployed","deployed",expected); + assertPath("undeployed", "deployed", expected); } @Test @@ -158,19 +158,19 @@ public class AppLifeCycleTest expected.add("deployed"); expected.add("starting"); expected.add("started"); - assertPath("undeployed","started",expected); + assertPath("undeployed", "started", expected); } @Test public void testFindPath_Undeployed_Uavailable() { - assertNoPath("undeployed","undeployed"); + assertNoPath("undeployed", "undeployed"); } /** * Request multiple lifecycle paths with a single lifecycle instance. Just to ensure that there is no state * maintained between {@link AppLifeCycle#getPath(Node, Node)} requests. - * + * * @throws IOException on test failure */ @Test @@ -182,22 +182,22 @@ public class AppLifeCycleTest File outputDir = testdir.getEmptyPathDir().toFile(); // Modify graph to add new 'staging' -> 'staged' between 'deployed' and 'started' - GraphOutputDot.write(lifecycle,new File(outputDir,"multiple-1.dot")); // before change - lifecycle.insertNode(lifecycle.getPath("deployed","started").getEdge(0),"staging"); - GraphOutputDot.write(lifecycle,new File(outputDir,"multiple-2.dot")); // after first change - lifecycle.insertNode(lifecycle.getPath("staging","started").getEdge(0),"staged"); - GraphOutputDot.write(lifecycle,new File(outputDir,"multiple-3.dot")); // after second change + GraphOutputDot.write(lifecycle, new File(outputDir, "multiple-1.dot")); // before change + lifecycle.insertNode(lifecycle.getPath("deployed", "started").getEdge(0), "staging"); + GraphOutputDot.write(lifecycle, new File(outputDir, "multiple-2.dot")); // after first change + lifecycle.insertNode(lifecycle.getPath("staging", "started").getEdge(0), "staged"); + GraphOutputDot.write(lifecycle, new File(outputDir, "multiple-3.dot")); // after second change // Deployed -> Deployed expected.clear(); - assertPath(lifecycle,"deployed","deployed",expected); + assertPath(lifecycle, "deployed", "deployed", expected); // Deployed -> Staged expected.clear(); expected.add("deployed"); expected.add("staging"); expected.add("staged"); - assertPath(lifecycle,"deployed","staged",expected); + assertPath(lifecycle, "deployed", "staged", expected); // Staged -> Undeployed expected.clear(); @@ -208,7 +208,7 @@ public class AppLifeCycleTest expected.add("deployed"); expected.add("undeploying"); expected.add("undeployed"); - assertPath(lifecycle,"staged","undeployed",expected); + assertPath(lifecycle, "staged", "undeployed", expected); // Undeployed -> Started expected.clear(); @@ -219,7 +219,6 @@ public class AppLifeCycleTest expected.add("staged"); expected.add("starting"); expected.add("started"); - assertPath(lifecycle,"undeployed","started",expected); + assertPath(lifecycle, "undeployed", "started", expected); } - } diff --git a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/BadAppDeployTest.java b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/BadAppDeployTest.java new file mode 100644 index 00000000000..b939781fdaa --- /dev/null +++ b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/BadAppDeployTest.java @@ -0,0 +1,176 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.deploy; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import javax.servlet.ServletException; + +import org.eclipse.jetty.deploy.providers.WebAppProvider; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.handler.ContextHandlerCollection; +import org.eclipse.jetty.server.handler.DefaultHandler; +import org.eclipse.jetty.server.handler.HandlerCollection; +import org.eclipse.jetty.toolchain.test.FS; +import org.eclipse.jetty.toolchain.test.MavenTestingUtils; +import org.eclipse.jetty.toolchain.test.jupiter.WorkDir; +import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.StacklessLogging; +import org.eclipse.jetty.webapp.WebAppContext; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import static java.time.Duration.ofSeconds; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@ExtendWith(WorkDirExtension.class) +public class BadAppDeployTest +{ + public WorkDir workDir; + private Server server; + + @AfterEach + public void stopServer() throws Exception + { + if (server != null) + { + server.stop(); + } + } + + @Test + public void testBadApp_ThrowOnUnavailableTrue_XmlOrder() throws Exception + { + /* Non-working Bean Order as reported in Issue #3620 + It is important that this Order be maintained for an accurate test case. + ### BEAN: QueuedThreadPool[qtp1327763628]@4f2410ac{STOPPED,8<=0<=200,i=0,r=-1,q=0}[NO_TRY] + ### BEAN: ServerConnector@16f65612{HTTP/1.1,[http/1.1]}{0.0.0.0:8080} + ### BEAN: HandlerCollection@5f150435{STOPPED} + ### BEAN: DeploymentManager@1c53fd30{STOPPED} + */ + + server = new Server(); + ServerConnector connector = new ServerConnector(server); + connector.setPort(0); + server.addConnector(connector); + + ContextHandlerCollection contexts = new ContextHandlerCollection(); + HandlerCollection handlers = new HandlerCollection(); + handlers.addHandler(contexts); + handlers.addHandler(new DefaultHandler()); + server.setHandler(handlers); // this should be done before addBean(deploymentManager) + + DeploymentManager deploymentManager = new DeploymentManager(); + deploymentManager.setContexts(contexts); + WebAppProvider webAppProvider = new WebAppProvider(); + deploymentManager.addAppProvider(webAppProvider); + + Path webappsDir = workDir.getEmptyPathDir().resolve("webapps").toAbsolutePath(); + + FS.ensureDirExists(webappsDir); + + copyTestResource("webapps/badapp/badapp.war", webappsDir.resolve("badapp.war")); + copyTestResource("webapps/badapp/badapp.xml", webappsDir.resolve("badapp.xml")); + + webAppProvider.setMonitoredDirName(webappsDir.toString()); + webAppProvider.setScanInterval(1); + + server.addBean(deploymentManager); // this should be done after setHandler(handlers) + + assertTimeoutPreemptively(ofSeconds(10), () -> + { + + try (StacklessLogging ignore = new StacklessLogging(Log.getLogger(WebAppContext.class), + Log.getLogger(DeploymentManager.class), + Log.getLogger("org.eclipse.jetty.server.handler.ContextHandler.badapp"))) + { + ServletException cause = assertThrows(ServletException.class, () -> server.start()); + assertThat(cause.getMessage(), containsString("intentionally")); + assertTrue(server.isFailed(), "Server should be in failed state"); + } + }); + } + + @Test + public void testBadApp_ThrowOnUnavailableTrue_EmbeddedOrder() throws Exception + { + /* Working Bean Order + ### BEAN: QueuedThreadPool[qtp1530388690]@5b37e0d2{STOPPED,8<=0<=200,i=0,r=-1,q=0}[NO_TRY] + ### BEAN: ServerConnector@5e265ba4{HTTP/1.1,[http/1.1]}{0.0.0.0:8080} + ### BEAN: DeploymentManager@3419866c{STOPPED} + ### BEAN: HandlerCollection@63e31ee{STOPPED} + */ + + server = new Server(); + ServerConnector connector = new ServerConnector(server); + connector.setPort(0); + server.addConnector(connector); + + ContextHandlerCollection contexts = new ContextHandlerCollection(); + + DeploymentManager deploymentManager = new DeploymentManager(); + deploymentManager.setContexts(contexts); + WebAppProvider webAppProvider = new WebAppProvider(); + deploymentManager.addAppProvider(webAppProvider); + + Path webappsDir = workDir.getEmptyPathDir().resolve("webapps").toAbsolutePath(); + + FS.ensureDirExists(webappsDir); + + copyTestResource("webapps/badapp/badapp.war", webappsDir.resolve("badapp.war")); + copyTestResource("webapps/badapp/badapp.xml", webappsDir.resolve("badapp.xml")); + + webAppProvider.setMonitoredDirName(webappsDir.toString()); + webAppProvider.setScanInterval(1); + + server.addBean(deploymentManager); // this should be done before setHandler(handlers) + + HandlerCollection handlers = new HandlerCollection(); + handlers.addHandler(contexts); + handlers.addHandler(new DefaultHandler()); + server.setHandler(handlers); // this should be done after addBean(deploymentManager) + + assertTimeoutPreemptively(ofSeconds(10), () -> + { + + try (StacklessLogging ignore = new StacklessLogging(Log.getLogger(WebAppContext.class), + Log.getLogger(DeploymentManager.class), + Log.getLogger("org.eclipse.jetty.server.handler.ContextHandler.badapp"))) + { + ServletException cause = assertThrows(ServletException.class, () -> server.start()); + assertThat(cause.getMessage(), containsString("intentionally")); + assertTrue(server.isFailed(), "Server should be in failed state"); + } + }); + } + + private void copyTestResource(String testResourceFile, Path webappsFile) throws IOException + { + Path srcFile = MavenTestingUtils.getTestResourcePathFile(testResourceFile); + Files.copy(srcFile, webappsFile); + } +} diff --git a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/DeploymentManagerLifeCyclePathTest.java b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/DeploymentManagerLifeCyclePathTest.java index 728c1555e08..ba920b73a1e 100644 --- a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/DeploymentManagerLifeCyclePathTest.java +++ b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/DeploymentManagerLifeCyclePathTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -21,7 +21,6 @@ package org.eclipse.jetty.deploy; import java.lang.management.ManagementFactory; import java.util.ArrayList; import java.util.List; - import javax.management.MBeanServerConnection; import javax.management.ObjectName; @@ -53,7 +52,7 @@ public class DeploymentManagerLifeCyclePathTest App app = depman.getAppByOriginId("mock-foo-webapp-1.war"); // Request Deploy of App - depman.requestAppGoal(app,"deployed"); + depman.requestAppGoal(app, "deployed"); // Setup Expectations. List expected = new ArrayList(); @@ -61,7 +60,7 @@ public class DeploymentManagerLifeCyclePathTest expected.add("deploying"); expected.add("deployed"); - pathtracker.assertExpected("Test StateTransition / New -> Deployed",expected); + pathtracker.assertExpected("Test StateTransition / New -> Deployed", expected); } @Test @@ -87,7 +86,7 @@ public class DeploymentManagerLifeCyclePathTest // Setup Expectations. List expected = new ArrayList(); - pathtracker.assertExpected("Test StateTransition / New only",expected); + pathtracker.assertExpected("Test StateTransition / New only", expected); } @Test @@ -99,7 +98,7 @@ public class DeploymentManagerLifeCyclePathTest MockAppProvider mockProvider = new MockAppProvider(); // Setup JMX - MBeanContainer mbContainer=new MBeanContainer(ManagementFactory.getPlatformMBeanServer()); + MBeanContainer mbContainer = new MBeanContainer(ManagementFactory.getPlatformMBeanServer()); depman.addBean(mbContainer); depman.addLifeCycleBinding(pathtracker); @@ -115,15 +114,15 @@ public class DeploymentManagerLifeCyclePathTest App app = depman.getAppByOriginId("mock-foo-webapp-1.war"); // Request Deploy of App - depman.requestAppGoal(app,"deployed"); + depman.requestAppGoal(app, "deployed"); JmxServiceConnection jmxConnection = new JmxServiceConnection(); jmxConnection.connect(); MBeanServerConnection mbsConnection = jmxConnection.getConnection(); ObjectName dmObjName = new ObjectName("org.eclipse.jetty.deploy:type=deploymentmanager,id=0"); - String[] params = new String[] {"mock-foo-webapp-1.war", "undeployed"}; - String[] signature = new String[] {"java.lang.String", "java.lang.String"}; + String[] params = new String[]{"mock-foo-webapp-1.war", "undeployed"}; + String[] signature = new String[]{"java.lang.String", "java.lang.String"}; mbsConnection.invoke(dmObjName, "requestAppGoal", params, signature); // Setup Expectations. @@ -134,6 +133,6 @@ public class DeploymentManagerLifeCyclePathTest expected.add("undeploying"); expected.add("undeployed"); - pathtracker.assertExpected("Test JMX StateTransition / Deployed -> Undeployed",expected); + pathtracker.assertExpected("Test JMX StateTransition / Deployed -> Undeployed", expected); } } diff --git a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/DeploymentManagerTest.java b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/DeploymentManagerTest.java index 106ab164354..694fdb02a55 100644 --- a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/DeploymentManagerTest.java +++ b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/DeploymentManagerTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,9 +18,6 @@ package org.eclipse.jetty.deploy; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; - import java.util.Collection; import java.util.Set; @@ -31,6 +28,9 @@ import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + @ExtendWith(WorkDirExtension.class) public class DeploymentManagerTest { diff --git a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/JmxServiceConnection.java b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/JmxServiceConnection.java index 270306ba21e..30c5cc67b47 100644 --- a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/JmxServiceConnection.java +++ b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/JmxServiceConnection.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,7 +20,6 @@ package org.eclipse.jetty.deploy; import java.io.IOException; import java.lang.management.ManagementFactory; - import javax.management.MBeanServer; import javax.management.MBeanServerConnection; import javax.management.remote.JMXConnector; @@ -33,7 +32,7 @@ import org.eclipse.jetty.toolchain.test.IO; /** * JmxServiceConnection - * + * * Provides ability to create a connection to either an external * JMX server, or a loopback connection to the internal one. */ @@ -55,9 +54,8 @@ public class JmxServiceConnection /** * Construct a connection to specified server - * - * @param url - * URL of JMX server + * + * @param url URL of JMX server */ public JmxServiceConnection(String url) { @@ -66,7 +64,7 @@ public class JmxServiceConnection /** * Retrieve an external URL for the JMX server - * + * * @return service URL */ public String getServiceUrl() @@ -74,10 +72,9 @@ public class JmxServiceConnection return serviceUrl; } - /* ------------------------------------------------------------ */ /** * Retrieve a connection to MBean server - * + * * @return connection to MBean server */ public MBeanServerConnection getConnection() @@ -102,15 +99,13 @@ public class JmxServiceConnection /** * Open a loopback connection to local JMX server - * - * @throws IOException */ private void openLoopbackConnection() throws IOException { server = ManagementFactory.getPlatformMBeanServer(); JMXServiceURL serviceUrl = new JMXServiceURL("service:jmx:rmi://"); - connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(serviceUrl,null,server); + connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(serviceUrl, null, server); connectorServer.start(); this.serviceUrl = connectorServer.getAddress().toString(); @@ -121,9 +116,6 @@ public class JmxServiceConnection /** * Open a connection to remote JMX server - * - * @param url - * @throws IOException */ private void openServerConnection(String url) throws IOException { diff --git a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/MockAppProvider.java b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/MockAppProvider.java index 30e0fe72609..1625ed4353f 100644 --- a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/MockAppProvider.java +++ b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/MockAppProvider.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -47,7 +47,7 @@ public class MockAppProvider extends AbstractLifeCycle implements AppProvider public void findWebapp(String name) { - App app = new App(deployMan,this,"mock-" + name); + App app = new App(deployMan, this, "mock-" + name); this.deployMan.addApp(app); } @@ -56,17 +56,17 @@ public class MockAppProvider extends AbstractLifeCycle implements AppProvider { WebAppContext context = new WebAppContext(); - File war = new File(webappsDir,app.getOriginId().substring(5)); + File war = new File(webappsDir, app.getOriginId().substring(5)); context.setWar(Resource.newResource(Resource.toURL(war)).toString()); String path = war.getName(); - + if (FileID.isWebArchiveFile(war)) { // Context Path is the same as the archive. - path = path.substring(0,path.length() - 4); + path = path.substring(0, path.length() - 4); } - + // special case of archive (or dir) named "root" is / context if (path.equalsIgnoreCase("root") || path.equalsIgnoreCase("root/")) path = URIUtil.SLASH; @@ -77,10 +77,10 @@ public class MockAppProvider extends AbstractLifeCycle implements AppProvider // Ensure "/" is Not Trailing in context paths. if (path.endsWith("/") && path.length() > 0) - path = path.substring(0,path.length() - 1); + path = path.substring(0, path.length() - 1); context.setContextPath(path); - + return context; } } diff --git a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/bindings/GlobalWebappConfigBindingTest.java b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/bindings/GlobalWebappConfigBindingTest.java index 8b66fdf3b3d..540bba05b37 100644 --- a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/bindings/GlobalWebappConfigBindingTest.java +++ b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/bindings/GlobalWebappConfigBindingTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,13 +18,6 @@ package org.eclipse.jetty.deploy.bindings; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.greaterThan; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.isIn; -import static org.hamcrest.Matchers.not; -import static org.junit.jupiter.api.Assertions.assertNotNull; - import java.io.File; import java.util.List; @@ -41,6 +34,14 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.in; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; +import static org.junit.jupiter.api.Assertions.assertNotNull; + /** * Tests {@link ScanningAppProvider} as it starts up for the first time. */ @@ -58,9 +59,8 @@ public class GlobalWebappConfigBindingTest jetty.addConfiguration("jetty-http.xml"); // Setup initial context - jetty.copyWebapp("foo.xml","foo.xml"); - jetty.copyWebapp("foo-webapp-1.war","foo.war"); - + jetty.copyWebapp("foo.xml", "foo.xml"); + jetty.copyWebapp("foo-webapp-1.war", "foo.war"); } @AfterEach @@ -74,10 +74,10 @@ public class GlobalWebappConfigBindingTest public void testServerAndSystemClassesOverride() throws Exception { File srcXml = MavenTestingUtils.getTestResourceFile("context-binding-test-1.xml"); - File destXml = new File(jetty.getJettyHome(),"context-binding-test-1.xml"); - IO.copy(srcXml,destXml); + File destXml = new File(jetty.getJettyHome(), "context-binding-test-1.xml"); + IO.copy(srcXml, destXml); - PathAssert.assertFileExists("Context Binding XML",destXml); + PathAssert.assertFileExists("Context Binding XML", destXml); jetty.addConfiguration("binding-test-contexts-1.xml"); jetty.load(); @@ -89,12 +89,12 @@ public class GlobalWebappConfigBindingTest WebAppContext context = contexts.get(0); assertNotNull(context, "Context should not be null"); - String defaultClasses[] = context.getDefaultServerClasses(); - String currentClasses[] = context.getServerClasses(); + String[] defaultClasses = context.getDefaultServerClasses(); + String[] currentClasses = context.getServerClasses(); String addedClass = "org.eclipse.foo."; // What was added by the binding - assertThat("Default Server Classes",addedClass,not(isIn(defaultClasses))); - assertThat("Current Server Classes",addedClass,isIn(currentClasses)); + assertThat("Default Server Classes", addedClass, not(is(in(defaultClasses)))); + assertThat("Current Server Classes", addedClass, is(in(currentClasses))); // boolean jndiPackage = false; diff --git a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/graph/GraphTest.java b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/graph/GraphTest.java index 2a4399d76a6..f8d4525857f 100644 --- a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/graph/GraphTest.java +++ b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/graph/GraphTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,11 +18,10 @@ package org.eclipse.jetty.deploy.graph; +import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; -import org.junit.jupiter.api.Test; - public class GraphTest { final Node nodeA = new Node("A"); @@ -31,7 +30,6 @@ public class GraphTest final Node nodeD = new Node("D"); final Node nodeE = new Node("E"); - @Test public void testPath() { @@ -39,18 +37,18 @@ public class GraphTest Path path = new Path(); assertEquals(0, path.nodes()); - assertEquals(null,path.firstNode()); - assertEquals(null,path.lastNode()); + assertEquals(null, path.firstNode()); + assertEquals(null, path.lastNode()); - path.add(new Edge(nodeA ,nodeB)); - assertEquals(2,path.nodes()); - assertEquals(nodeA,path.firstNode()); - assertEquals(nodeB,path.lastNode()); + path.add(new Edge(nodeA, nodeB)); + assertEquals(2, path.nodes()); + assertEquals(nodeA, path.firstNode()); + assertEquals(nodeB, path.lastNode()); - path.add(new Edge(nodeB ,nodeC)); - assertEquals(3,path.nodes()); - assertEquals(nodeA,path.firstNode()); - assertEquals(nodeC,path.lastNode()); + path.add(new Edge(nodeB, nodeC)); + assertEquals(3, path.nodes()); + assertEquals(nodeA, path.firstNode()); + assertEquals(nodeC, path.lastNode()); } @Test @@ -58,81 +56,77 @@ public class GraphTest { Graph graph = new Graph(); graph.addNode(nodeA); - assertEquals(1,graph.getNodes().size()); - assertEquals(0,graph.getEdges().size()); - Path path = graph.getPath(nodeA,nodeA); - assertEquals(0,path.nodes()); + assertEquals(1, graph.getNodes().size()); + assertEquals(0, graph.getEdges().size()); + Path path = graph.getPath(nodeA, nodeA); + assertEquals(0, path.nodes()); } @Test public void testLine() { Graph graph = new Graph(); - graph.addEdge(new Edge(nodeA,nodeB)); - assertEquals(2,graph.getNodes().size()); - assertEquals(1,graph.getEdges().size()); - Path path = graph.getPath(nodeA,nodeB); - assertEquals(2,path.nodes()); + graph.addEdge(new Edge(nodeA, nodeB)); + assertEquals(2, graph.getNodes().size()); + assertEquals(1, graph.getEdges().size()); + Path path = graph.getPath(nodeA, nodeB); + assertEquals(2, path.nodes()); } @Test public void testTriangleDirected() { Graph graph = new Graph(); - graph.addEdge(new Edge(nodeA,nodeB)); - graph.addEdge(new Edge(nodeA,nodeC)); - graph.addEdge(new Edge(nodeB,nodeC)); - assertEquals(3,graph.getNodes().size()); - assertEquals(3,graph.getEdges().size()); - Path path = graph.getPath(nodeA,nodeB); - assertEquals(2,path.nodes()); - path = graph.getPath(nodeA,nodeC); - assertEquals(2,path.nodes()); - path = graph.getPath(nodeB,nodeC); - assertEquals(2,path.nodes()); - + graph.addEdge(new Edge(nodeA, nodeB)); + graph.addEdge(new Edge(nodeA, nodeC)); + graph.addEdge(new Edge(nodeB, nodeC)); + assertEquals(3, graph.getNodes().size()); + assertEquals(3, graph.getEdges().size()); + Path path = graph.getPath(nodeA, nodeB); + assertEquals(2, path.nodes()); + path = graph.getPath(nodeA, nodeC); + assertEquals(2, path.nodes()); + path = graph.getPath(nodeB, nodeC); + assertEquals(2, path.nodes()); } @Test public void testSquareDirected() { Graph graph = new Graph(); - graph.addEdge(new Edge(nodeA,nodeB)); - graph.addEdge(new Edge(nodeB,nodeC)); - graph.addEdge(new Edge(nodeA,nodeD)); - graph.addEdge(new Edge(nodeD,nodeC)); - assertEquals(4,graph.getNodes().size()); - assertEquals(4,graph.getEdges().size()); - Path path = graph.getPath(nodeA,nodeC); - assertEquals(3,path.nodes()); - - path = graph.getPath(nodeC,nodeA); - assertEquals(null,path); + graph.addEdge(new Edge(nodeA, nodeB)); + graph.addEdge(new Edge(nodeB, nodeC)); + graph.addEdge(new Edge(nodeA, nodeD)); + graph.addEdge(new Edge(nodeD, nodeC)); + assertEquals(4, graph.getNodes().size()); + assertEquals(4, graph.getEdges().size()); + Path path = graph.getPath(nodeA, nodeC); + assertEquals(3, path.nodes()); + path = graph.getPath(nodeC, nodeA); + assertEquals(null, path); } @Test public void testSquareCyclic() { Graph graph = new Graph(); - graph.addEdge(new Edge(nodeA,nodeB)); - graph.addEdge(new Edge(nodeB,nodeC)); - graph.addEdge(new Edge(nodeC,nodeD)); - graph.addEdge(new Edge(nodeD,nodeA)); - assertEquals(4,graph.getNodes().size()); - assertEquals(4,graph.getEdges().size()); - Path path = graph.getPath(nodeA,nodeB); - assertEquals(2,path.nodes()); + graph.addEdge(new Edge(nodeA, nodeB)); + graph.addEdge(new Edge(nodeB, nodeC)); + graph.addEdge(new Edge(nodeC, nodeD)); + graph.addEdge(new Edge(nodeD, nodeA)); + assertEquals(4, graph.getNodes().size()); + assertEquals(4, graph.getEdges().size()); + Path path = graph.getPath(nodeA, nodeB); + assertEquals(2, path.nodes()); - path = graph.getPath(nodeA,nodeC); - assertEquals(3,path.nodes()); - path = graph.getPath(nodeA,nodeD); - assertEquals(4,path.nodes()); + path = graph.getPath(nodeA, nodeC); + assertEquals(3, path.nodes()); + path = graph.getPath(nodeA, nodeD); + assertEquals(4, path.nodes()); graph.addNode(nodeE); - path = graph.getPath(nodeA,nodeE); - assertEquals(null,path); + path = graph.getPath(nodeA, nodeE); + assertEquals(null, path); } - - } diff --git a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/ScanningAppProviderRuntimeUpdatesTest.java b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/ScanningAppProviderRuntimeUpdatesTest.java index 5d38c2770a2..82bd338ca45 100644 --- a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/ScanningAppProviderRuntimeUpdatesTest.java +++ b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/ScanningAppProviderRuntimeUpdatesTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,8 +18,6 @@ package org.eclipse.jetty.deploy.providers; -import static org.junit.jupiter.api.condition.OS.WINDOWS; - import java.io.IOException; import java.util.concurrent.atomic.AtomicInteger; @@ -38,6 +36,8 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledOnOs; import org.junit.jupiter.api.extension.ExtendWith; +import static org.junit.jupiter.api.condition.OS.WINDOWS; + /** * Similar in scope to {@link ScanningAppProviderStartupTest}, except is concerned with the modification of existing * deployed webapps due to incoming changes identified by the {@link ScanningAppProvider}. @@ -57,7 +57,7 @@ public class ScanningAppProviderRuntimeUpdatesTest { testdir.ensureEmpty(); Resource.setDefaultUseCaches(false); - + jetty = new XmlConfiguredJetty(testdir.getEmptyPathDir()); jetty.addConfiguration("jetty.xml"); jetty.addConfiguration("jetty-http.xml"); @@ -86,7 +86,6 @@ public class ScanningAppProviderRuntimeUpdatesTest }); } } - } @AfterEach @@ -98,30 +97,31 @@ public class ScanningAppProviderRuntimeUpdatesTest public void waitForDirectoryScan() { - int scan=_scans.get()+(2*_providers); + int scan = _scans.get() + (2 * _providers); do { try { Thread.sleep(200); } - catch(InterruptedException e) + catch (InterruptedException e) { LOG.warn(e); } } - while(_scans.get() _xmlConfigurations; - private Map _properties = new HashMap<>(); + private Map _properties = new HashMap<>(); private Server _server; private int _serverPort; private String _scheme = HttpScheme.HTTP.asString(); @@ -88,29 +87,29 @@ public class XmlConfiguredJetty // Prepare Jetty.Home (Test) dir _jettyHome.mkdirs(); - File logsDir = new File(_jettyHome,"logs"); + File logsDir = new File(_jettyHome, "logs"); logsDir.mkdirs(); - File etcDir = new File(_jettyHome,"etc"); + File etcDir = new File(_jettyHome, "etc"); etcDir.mkdirs(); - IO.copyFile(MavenTestingUtils.getTestResourceFile("etc/realm.properties"),new File(etcDir,"realm.properties")); - IO.copyFile(MavenTestingUtils.getTestResourceFile("etc/webdefault.xml"),new File(etcDir,"webdefault.xml")); + IO.copyFile(MavenTestingUtils.getTestResourceFile("etc/realm.properties"), new File(etcDir, "realm.properties")); + IO.copyFile(MavenTestingUtils.getTestResourceFile("etc/webdefault.xml"), new File(etcDir, "webdefault.xml")); - File webappsDir = new File(_jettyHome,"webapps"); + File webappsDir = new File(_jettyHome, "webapps"); if (webappsDir.exists()) { deleteContents(webappsDir); } webappsDir.mkdirs(); - File tmpDir = new File(_jettyHome,"tmp"); + File tmpDir = new File(_jettyHome, "tmp"); if (tmpDir.exists()) { deleteContents(tmpDir); } tmpDir.mkdirs(); - File workishDir = new File(_jettyHome,"workish"); + File workishDir = new File(_jettyHome, "workish"); if (workishDir.exists()) { deleteContents(workishDir); @@ -118,23 +117,25 @@ public class XmlConfiguredJetty workishDir.mkdirs(); // Setup properties - System.setProperty("java.io.tmpdir",tmpDir.getAbsolutePath()); - properties.setProperty("jetty.home",_jettyHome.getAbsolutePath()); - System.setProperty("jetty.home",_jettyHome.getAbsolutePath()); - properties.setProperty("test.basedir",MavenTestingUtils.getBaseDir().getAbsolutePath()); - properties.setProperty("test.resourcesdir",MavenTestingUtils.getTestResourcesDir().getAbsolutePath()); - properties.setProperty("test.webapps",webappsDir.getAbsolutePath()); - properties.setProperty("test.targetdir",MavenTestingUtils.getTargetDir().getAbsolutePath()); - properties.setProperty("test.workdir",workishDir.getAbsolutePath()); + System.setProperty("java.io.tmpdir", tmpDir.getAbsolutePath()); + properties.setProperty("jetty.home", _jettyHome.getAbsolutePath()); + System.setProperty("jetty.home", _jettyHome.getAbsolutePath()); + properties.setProperty("test.basedir", MavenTestingUtils.getBaseDir().getAbsolutePath()); + properties.setProperty("test.resourcesdir", MavenTestingUtils.getTestResourcesDir().getAbsolutePath()); + properties.setProperty("test.webapps", webappsDir.getAbsolutePath()); + properties.setProperty("test.targetdir", MavenTestingUtils.getTargetDir().getAbsolutePath()); + properties.setProperty("test.workdir", workishDir.getAbsolutePath()); // Write out configuration for use by ConfigurationManager. File testConfig = new File(_jettyHome, "xml-configured-jetty.properties"); try (OutputStream out = new FileOutputStream(testConfig)) { - properties.store(out,"Generated by " + XmlConfiguredJetty.class.getName()); + properties.store(out, "Generated by " + XmlConfiguredJetty.class.getName()); + } + for (Object key : properties.keySet()) + { + setProperty(String.valueOf(key), String.valueOf(properties.get(key))); } - for (Object key:properties.keySet()) - setProperty(String.valueOf(key),String.valueOf(properties.get(key))); } public void addConfiguration(File xmlConfigFile) throws MalformedURLException @@ -203,7 +204,7 @@ public class XmlConfiguredJetty System.err.println("## Actual Contexts"); for (WebAppContext context : contexts) { - System.err.printf("%s ## %s%n",context.getContextPath(),context); + System.err.printf("%s ## %s%n", context.getContextPath(), context); } assertEquals(expectedContextPaths.length, contexts.size(), "Contexts.size"); } @@ -220,29 +221,29 @@ public class XmlConfiguredJetty break; } } - assertTrue(found,"Did not find Expected Context Path " + expectedPath); + assertTrue(found, "Did not find Expected Context Path " + expectedPath); } } private void copyFile(String type, File srcFile, File destFile) throws IOException { - PathAssert.assertFileExists(type + " File",srcFile); - IO.copyFile(srcFile,destFile); - PathAssert.assertFileExists(type + " File",destFile); - System.err.printf("Copy %s: %s%n To %s: %s%n",type,srcFile,type,destFile); - System.err.printf("Destination Exists: %s - %s%n",destFile.exists(),destFile); + PathAssert.assertFileExists(type + " File", srcFile); + IO.copyFile(srcFile, destFile); + PathAssert.assertFileExists(type + " File", destFile); + System.err.printf("Copy %s: %s%n To %s: %s%n", type, srcFile, type, destFile); + System.err.printf("Destination Exists: %s - %s%n", destFile.exists(), destFile); } public void copyWebapp(String srcName, String destName) throws IOException { - System.err.printf("Copying Webapp: %s -> %s%n",srcName,destName); + System.err.printf("Copying Webapp: %s -> %s%n", srcName, destName); File srcDir = MavenTestingUtils.getTestResourceDir("webapps"); - File destDir = new File(_jettyHome,"webapps"); + File destDir = new File(_jettyHome, "webapps"); - File srcFile = new File(srcDir,srcName); - File destFile = new File(destDir,destName); + File srcFile = new File(srcDir, srcName); + File destFile = new File(destDir, destName); - copyFile("Webapp",srcFile,destFile); + copyFile("Webapp", srcFile, destFile); } private void deleteContents(File dir) @@ -262,11 +263,11 @@ public class XmlConfiguredJetty if (file.isDirectory() && file.getAbsolutePath().contains("target" + File.separator)) { deleteContents(file); - assertTrue(file.delete(),"Delete failed: " + file.getAbsolutePath()); + assertTrue(file.delete(), "Delete failed: " + file.getAbsolutePath()); } else { - assertTrue(file.delete(),"Delete failed: " + file.getAbsolutePath()); + assertTrue(file.delete(), "Delete failed: " + file.getAbsolutePath()); } } } @@ -274,7 +275,7 @@ public class XmlConfiguredJetty public File getJettyDir(String name) { - return new File(_jettyHome,name); + return new File(_jettyHome, name); } public File getJettyHome() @@ -308,7 +309,7 @@ public class XmlConfiguredJetty { List contexts = new ArrayList<>(); HandlerCollection handlers = (HandlerCollection)_server.getHandler(); - Handler children[] = handlers.getChildHandlers(); + Handler[] children = handlers.getChildHandlers(); for (Handler handler : children) { @@ -369,17 +370,17 @@ public class XmlConfiguredJetty public void removeWebapp(String name) { - File destDir = new File(_jettyHome,"webapps"); - File contextFile = new File(destDir,name); + File destDir = new File(_jettyHome, "webapps"); + File contextFile = new File(destDir, name); if (contextFile.exists()) { - assertTrue(contextFile.delete(),"Delete of Webapp file: " + contextFile.getAbsolutePath()); + assertTrue(contextFile.delete(), "Delete of Webapp file: " + contextFile.getAbsolutePath()); } } public void setProperty(String key, String value) { - _properties.put(key,value); + _properties.put(key, value); } public void setScheme(String scheme) @@ -395,18 +396,18 @@ public class XmlConfiguredJetty // Find the active server port. _serverPort = -1; - Connector connectors[] = _server.getConnectors(); - for (int i = 0; _serverPort<0 && i < connectors.length; i++) + Connector[] connectors = _server.getConnectors(); + for (int i = 0; _serverPort < 0 && i < connectors.length; i++) { if (connectors[i] instanceof NetworkConnector) { int port = ((NetworkConnector)connectors[i]).getLocalPort(); - if (port>0) - _serverPort=port; + if (port > 0) + _serverPort = port; } } - assertTrue((1 <= this._serverPort) && (this._serverPort <= 65535),"Server Port is between 1 and 65535. Was actually <" + _serverPort + ">"); + assertTrue((1 <= this._serverPort) && (this._serverPort <= 65535), "Server Port is between 1 and 65535. Was actually <" + _serverPort + ">"); // Uncomment to have server start and continue to run (without exiting) // System.err.printf("Listening to port %d%n",this.serverPort); diff --git a/jetty-deploy/src/test/resources/jetty-deploy-wars.xml b/jetty-deploy/src/test/resources/jetty-deploy-wars.xml index 1760a674f51..7dc7aca095d 100644 --- a/jetty-deploy/src/test/resources/jetty-deploy-wars.xml +++ b/jetty-deploy/src/test/resources/jetty-deploy-wars.xml @@ -1,5 +1,4 @@ - - + diff --git a/jetty-deploy/src/test/resources/jetty-deploymgr-contexts.xml b/jetty-deploy/src/test/resources/jetty-deploymgr-contexts.xml index b16fbd7101e..f321fdfe527 100644 --- a/jetty-deploy/src/test/resources/jetty-deploymgr-contexts.xml +++ b/jetty-deploy/src/test/resources/jetty-deploymgr-contexts.xml @@ -1,5 +1,4 @@ - - + diff --git a/jetty-deploy/src/test/resources/jetty-http.xml b/jetty-deploy/src/test/resources/jetty-http.xml index 7fa6def071a..43ed57d5425 100644 --- a/jetty-deploy/src/test/resources/jetty-http.xml +++ b/jetty-deploy/src/test/resources/jetty-http.xml @@ -1,15 +1,10 @@ - - + - - - - - + - + diff --git a/jetty-deploy/src/test/resources/jetty.xml b/jetty-deploy/src/test/resources/jetty.xml index 00fcd1a9329..c780fdfea5b 100644 --- a/jetty-deploy/src/test/resources/jetty.xml +++ b/jetty-deploy/src/test/resources/jetty.xml @@ -1,28 +1,8 @@ - - + - - - - - - - - - - - - + - - - - - - - - - + diff --git a/jetty-deploy/src/test/resources/webapps/badapp/badapp.war b/jetty-deploy/src/test/resources/webapps/badapp/badapp.war new file mode 100644 index 00000000000..3fc1a60d5fe Binary files /dev/null and b/jetty-deploy/src/test/resources/webapps/badapp/badapp.war differ diff --git a/jetty-deploy/src/test/resources/webapps/badapp/badapp.xml b/jetty-deploy/src/test/resources/webapps/badapp/badapp.xml new file mode 100644 index 00000000000..d085d7b9cec --- /dev/null +++ b/jetty-deploy/src/test/resources/webapps/badapp/badapp.xml @@ -0,0 +1,8 @@ + + + + + /badapp + /badapp.war + true + diff --git a/jetty-deploy/src/test/resources/webapps/foo.xml b/jetty-deploy/src/test/resources/webapps/foo.xml index f0a96119a3f..4b978059063 100644 --- a/jetty-deploy/src/test/resources/webapps/foo.xml +++ b/jetty-deploy/src/test/resources/webapps/foo.xml @@ -1,5 +1,4 @@ - - + /foo diff --git a/jetty-distribution/pom.xml b/jetty-distribution/pom.xml index c3fe2a86ae1..cf3f7c40b2e 100644 --- a/jetty-distribution/pom.xml +++ b/jetty-distribution/pom.xml @@ -1,10 +1,8 @@ - + org.eclipse.jetty jetty-project - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 jetty-distribution @@ -29,7 +27,7 @@ copy-base-assembly-tree - package + prepare-package copy-resources @@ -47,6 +45,7 @@ + org.apache.maven.plugins maven-dependency-plugin diff --git a/jetty-documentation/pom.xml b/jetty-documentation/pom.xml index c0d5a837f41..8568850be1a 100644 --- a/jetty-documentation/pom.xml +++ b/jetty-documentation/pom.xml @@ -1,11 +1,11 @@ 4.0.0 - + org.eclipse.jetty jetty-project - 9.4.13-SNAPSHOT - + 9.4.21-SNAPSHOT + jetty-documentation Jetty :: Documentation pom diff --git a/jetty-documentation/src/main/asciidoc/administration/alpn/alpn.adoc b/jetty-documentation/src/main/asciidoc/administration/alpn/alpn.adoc index adb8a86e31a..87e793af3af 100644 --- a/jetty-documentation/src/main/asciidoc/administration/alpn/alpn.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/alpn/alpn.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -347,6 +347,14 @@ The ALPN implementation, relying on modifications of OpenJDK classes, updates ev |1.8.0u171 |8.1.12.v20180117 |1.8.0u172 |8.1.12.v20180117 |1.8.0u181 |8.1.12.v20180117 +|1.8.0u191 |8.1.13.v20181017 +|1.8.0u192 |8.1.13.v20181017 +|1.8.0u201 |8.1.13.v20181017 +|1.8.0u202 |8.1.13.v20181017 +|1.8.0u211 |8.1.13.v20181017 +|1.8.0u212 |8.1.13.v20181017 +|1.8.0u221 |8.1.13.v20181017 +|1.8.0u222 |8.1.13.v20181017 |============================= [[alpn-build]] diff --git a/jetty-documentation/src/main/asciidoc/administration/alpn/chapter.adoc b/jetty-documentation/src/main/asciidoc/administration/alpn/chapter.adoc index 490f689ec1a..fbb80ba6e18 100644 --- a/jetty-documentation/src/main/asciidoc/administration/alpn/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/alpn/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/annotations/chapter.adoc b/jetty-documentation/src/main/asciidoc/administration/annotations/chapter.adoc index b0cbff8e453..088f4c730d6 100644 --- a/jetty-documentation/src/main/asciidoc/administration/annotations/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/annotations/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/annotations/quick-annotations-setup.adoc b/jetty-documentation/src/main/asciidoc/administration/annotations/quick-annotations-setup.adoc index 5eb90f2d4e5..302cbff1756 100644 --- a/jetty-documentation/src/main/asciidoc/administration/annotations/quick-annotations-setup.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/annotations/quick-annotations-setup.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/annotations/using-annotations-embedded.adoc b/jetty-documentation/src/main/asciidoc/administration/annotations/using-annotations-embedded.adoc index a296e879f82..dca6e528b35 100644 --- a/jetty-documentation/src/main/asciidoc/administration/annotations/using-annotations-embedded.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/annotations/using-annotations-embedded.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/annotations/using-annotations.adoc b/jetty-documentation/src/main/asciidoc/administration/annotations/using-annotations.adoc index d84ec8bd691..43e070094a2 100644 --- a/jetty-documentation/src/main/asciidoc/administration/annotations/using-annotations.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/annotations/using-annotations.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -119,6 +119,13 @@ By default Jetty will call them in the following order: As is the case with annotation scanning, the link:#using-extra-classpath-method[extraClasspath] is fully considered for `ServletContainerInitializer` callbacks. `ServletContainerInitializer` derived from a classes directory on the `extraClasspath` and jars from an `extraClasspath` for the webapp are called in step 2 and 3, respectively. +____ +[NOTE] +As of Jetty-9.4.4, unless the `web.xml` is version 3.0 or greater, only `ServletContainerInitializers` that are on the container classpath will be discovered. +Users wishing to use `ServletContainerInitializers` from within the webapp with older versions of `web.xml` must either upgrade their `web.xml` version, or call `WebAppContext.setConfigurationDiscovered(true)` either programmatically or in xml. +Upgrading the `web.xml` version is preferable. +____ + ===== Controlling the order of ServletContainerInitializer invocation If you need `ServletContainerInitializer` classes called in a specific order that is different from that outlined above, you can use the link:#context_attributes[context attribute] `org.eclipse.jetty.containerInitializerOrder`. diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/balancer-servlet.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/balancer-servlet.adoc index 1059cc42ca5..199f5af55d4 100644 --- a/jetty-documentation/src/main/asciidoc/administration/extras/balancer-servlet.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/extras/balancer-servlet.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/cgi-servlet.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/cgi-servlet.adoc index 2cca30b128a..2b4c07f310a 100644 --- a/jetty-documentation/src/main/asciidoc/administration/extras/cgi-servlet.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/extras/cgi-servlet.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/chapter.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/chapter.adoc index 136234beb50..2f26f645529 100644 --- a/jetty-documentation/src/main/asciidoc/administration/extras/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/extras/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/cross-origin-filter.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/cross-origin-filter.adoc index bbc4ad75286..50cbf4144a9 100644 --- a/jetty-documentation/src/main/asciidoc/administration/extras/cross-origin-filter.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/extras/cross-origin-filter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/debug-handler.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/debug-handler.adoc index a693ecbe637..fe28c883170 100644 --- a/jetty-documentation/src/main/asciidoc/administration/extras/debug-handler.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/extras/debug-handler.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/default-handler.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/default-handler.adoc index b15c4e68f86..642f24b9388 100644 --- a/jetty-documentation/src/main/asciidoc/administration/extras/default-handler.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/extras/default-handler.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/default-servlet.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/default-servlet.adoc index f91059a8e6c..4182ad6ae00 100644 --- a/jetty-documentation/src/main/asciidoc/administration/extras/default-servlet.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/extras/default-servlet.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/dos-filter.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/dos-filter.adoc index eb96c9badfb..07be5b0cbee 100644 --- a/jetty-documentation/src/main/asciidoc/administration/extras/dos-filter.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/extras/dos-filter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/error-handler.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/error-handler.adoc index 3b580181139..400842899de 100644 --- a/jetty-documentation/src/main/asciidoc/administration/extras/error-handler.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/extras/error-handler.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/gzip-filter.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/gzip-filter.adoc index 7d962dae2aa..18bdb5b0236 100644 --- a/jetty-documentation/src/main/asciidoc/administration/extras/gzip-filter.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/extras/gzip-filter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/header-filter.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/header-filter.adoc index 8de9536b95a..8fdbfa489d1 100644 --- a/jetty-documentation/src/main/asciidoc/administration/extras/header-filter.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/extras/header-filter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/ipaccess-handler.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/ipaccess-handler.adoc index 8ac09fa6a9f..45811f9b063 100644 --- a/jetty-documentation/src/main/asciidoc/administration/extras/ipaccess-handler.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/extras/ipaccess-handler.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/moved-context-handler.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/moved-context-handler.adoc index e4a68f83213..da5bf832b7e 100644 --- a/jetty-documentation/src/main/asciidoc/administration/extras/moved-context-handler.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/extras/moved-context-handler.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/proxy-servlet.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/proxy-servlet.adoc index 16486efbdb0..38c01bbfe25 100644 --- a/jetty-documentation/src/main/asciidoc/administration/extras/proxy-servlet.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/extras/proxy-servlet.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/qos-filter.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/qos-filter.adoc index 93bef25415d..7b4504204b8 100644 --- a/jetty-documentation/src/main/asciidoc/administration/extras/qos-filter.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/extras/qos-filter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -110,11 +110,11 @@ The maximum number of requests to be serviced at a time. The default is 10. maxPriority:: The maximum valid priority that can be assigned to a request. A request with a high priority value is more important than a request with a low priority value. The default is 10. -waitMS:: +waitMs:: The length of time, in milliseconds, to wait while trying to accept a new request. Used when the maxRequests limit is reached. Default is 50 ms. -suspendMS:: +suspendMs:: Length of time, in milliseconds, that the request will be suspended if it is not accepted immediately. If not set, the container's default suspend period applies. Default is -1 ms. managedAttr:: diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/resource-handler.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/resource-handler.adoc index d7fdbda3925..f3aec28d3b7 100644 --- a/jetty-documentation/src/main/asciidoc/administration/extras/resource-handler.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/extras/resource-handler.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/rewrite-handler.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/rewrite-handler.adoc index 6c7e82209e3..41c8d6f3d08 100644 --- a/jetty-documentation/src/main/asciidoc/administration/extras/rewrite-handler.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/extras/rewrite-handler.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/shutdown-handler.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/shutdown-handler.adoc index 4b668cc4f3c..f2eea737872 100644 --- a/jetty-documentation/src/main/asciidoc/administration/extras/shutdown-handler.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/extras/shutdown-handler.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/statistics-handler.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/statistics-handler.adoc index 56ee9459f42..e4af9941430 100644 --- a/jetty-documentation/src/main/asciidoc/administration/extras/statistics-handler.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/extras/statistics-handler.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/fastcgi/chapter.adoc b/jetty-documentation/src/main/asciidoc/administration/fastcgi/chapter.adoc index e33be3aafe5..afe2a6861f7 100644 --- a/jetty-documentation/src/main/asciidoc/administration/fastcgi/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/fastcgi/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/fastcgi/configuring-fastcgi.adoc b/jetty-documentation/src/main/asciidoc/administration/fastcgi/configuring-fastcgi.adoc index b5c693f360c..38c3f37b73a 100644 --- a/jetty-documentation/src/main/asciidoc/administration/fastcgi/configuring-fastcgi.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/fastcgi/configuring-fastcgi.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -49,7 +49,7 @@ Copy and paste the following content as `$JETTY_BASE/webapps/jetty-wordpress.xml [source, xml, subs="{sub-order}"] ---- - + diff --git a/jetty-documentation/src/main/asciidoc/administration/fastcgi/fastcgi-intro.adoc b/jetty-documentation/src/main/asciidoc/administration/fastcgi/fastcgi-intro.adoc index e788fe1af33..e84c3ca25dd 100644 --- a/jetty-documentation/src/main/asciidoc/administration/fastcgi/fastcgi-intro.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/fastcgi/fastcgi-intro.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/http2/chapter.adoc b/jetty-documentation/src/main/asciidoc/administration/http2/chapter.adoc index d11a39ebc6f..5c8b7460c2e 100644 --- a/jetty-documentation/src/main/asciidoc/administration/http2/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/http2/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/http2/configuring-haproxy.adoc b/jetty-documentation/src/main/asciidoc/administration/http2/configuring-haproxy.adoc index bfb4d608601..ffa0b6c1463 100644 --- a/jetty-documentation/src/main/asciidoc/administration/http2/configuring-haproxy.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/http2/configuring-haproxy.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/http2/configuring-http2.adoc b/jetty-documentation/src/main/asciidoc/administration/http2/configuring-http2.adoc index 874c74a0bd1..ea676126d33 100644 --- a/jetty-documentation/src/main/asciidoc/administration/http2/configuring-http2.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/http2/configuring-http2.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/http2/configuring-push.adoc b/jetty-documentation/src/main/asciidoc/administration/http2/configuring-push.adoc index 7d7dcd6a489..24b27955274 100644 --- a/jetty-documentation/src/main/asciidoc/administration/http2/configuring-push.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/http2/configuring-push.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/http2/enabling-http2.adoc b/jetty-documentation/src/main/asciidoc/administration/http2/enabling-http2.adoc index 04e387324a9..9eaefadc53f 100644 --- a/jetty-documentation/src/main/asciidoc/administration/http2/enabling-http2.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/http2/enabling-http2.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/http2/introduction.adoc b/jetty-documentation/src/main/asciidoc/administration/http2/introduction.adoc index 98600a256b0..6f3d7b17e9c 100644 --- a/jetty-documentation/src/main/asciidoc/administration/http2/introduction.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/http2/introduction.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/jmx/chapter.adoc b/jetty-documentation/src/main/asciidoc/administration/jmx/chapter.adoc index 4f002238058..caaf3883408 100644 --- a/jetty-documentation/src/main/asciidoc/administration/jmx/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/jmx/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/jmx/jetty-jconsole.adoc b/jetty-documentation/src/main/asciidoc/administration/jmx/jetty-jconsole.adoc index d8260067976..0f7444a952b 100644 --- a/jetty-documentation/src/main/asciidoc/administration/jmx/jetty-jconsole.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/jmx/jetty-jconsole.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/jmx/jetty-jmx-annotations.adoc b/jetty-documentation/src/main/asciidoc/administration/jmx/jetty-jmx-annotations.adoc index b0b8139d9ba..7c19b124d63 100644 --- a/jetty-documentation/src/main/asciidoc/administration/jmx/jetty-jmx-annotations.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/jmx/jetty-jmx-annotations.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/jmx/using-jmx.adoc b/jetty-documentation/src/main/asciidoc/administration/jmx/using-jmx.adoc index e4760cf8450..3a6756935a9 100644 --- a/jetty-documentation/src/main/asciidoc/administration/jmx/using-jmx.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/jmx/using-jmx.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -290,8 +290,8 @@ Similarly, in code: [source, java, subs="{sub-order}"] ---- -SslContextFactory sslContextFactory = new SslContextFactory(); -sslContextFactory.setKeyStorePath(); +SslContextFactory.Server sslContextFactory = new SslContextFactory.Server(); +sslContextFactory.setKeyStorePath("/path/to/keystore"); sslContextFactory.setKeyStorePassword("secret"); JMXServiceURL jmxURL = new JMXServiceURL("rmi", null, 1099, "/jndi/rmi:///jmxrmi"); diff --git a/jetty-documentation/src/main/asciidoc/administration/jndi/chapter.adoc b/jetty-documentation/src/main/asciidoc/administration/jndi/chapter.adoc index da395aaa2a8..2f47039cd95 100644 --- a/jetty-documentation/src/main/asciidoc/administration/jndi/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/jndi/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/jndi/jndi-configuration.adoc b/jetty-documentation/src/main/asciidoc/administration/jndi/jndi-configuration.adoc index 0871ea53f69..4dd787f2d8b 100644 --- a/jetty-documentation/src/main/asciidoc/administration/jndi/jndi-configuration.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/jndi/jndi-configuration.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/jndi/jndi-datasources.adoc b/jetty-documentation/src/main/asciidoc/administration/jndi/jndi-datasources.adoc index 2eda57495ec..9b660052a36 100644 --- a/jetty-documentation/src/main/asciidoc/administration/jndi/jndi-datasources.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/jndi/jndi-datasources.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/jndi/jndi-embedded.adoc b/jetty-documentation/src/main/asciidoc/administration/jndi/jndi-embedded.adoc index ccc7f32a1eb..e77490bab82 100644 --- a/jetty-documentation/src/main/asciidoc/administration/jndi/jndi-embedded.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/jndi/jndi-embedded.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/jndi/quick-jndi-setup.adoc b/jetty-documentation/src/main/asciidoc/administration/jndi/quick-jndi-setup.adoc index ec35360fe26..dec37697215 100644 --- a/jetty-documentation/src/main/asciidoc/administration/jndi/quick-jndi-setup.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/jndi/quick-jndi-setup.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/jndi/using-jndi.adoc b/jetty-documentation/src/main/asciidoc/administration/jndi/using-jndi.adoc index 523fbed7bb9..7344090b589 100644 --- a/jetty-documentation/src/main/asciidoc/administration/jndi/using-jndi.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/jndi/using-jndi.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/chapter.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/chapter.adoc index 38b35596c1b..689537a5137 100644 --- a/jetty-documentation/src/main/asciidoc/administration/logging/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/logging/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/configuring-jetty-logging.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/configuring-jetty-logging.adoc index 9ca9f00a475..13f10c44348 100644 --- a/jetty-documentation/src/main/asciidoc/administration/logging/configuring-jetty-logging.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/logging/configuring-jetty-logging.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/configuring-jetty-request-logs.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/configuring-jetty-request-logs.adoc index dd452a02efd..bee4f26d0e4 100644 --- a/jetty-documentation/src/main/asciidoc/administration/logging/configuring-jetty-request-logs.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/logging/configuring-jetty-request-logs.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -91,7 +91,29 @@ By default, log files are kept for 90 days before being deleted. The value for `retainDays` (xml) or `setRetainDays` (Java) should be configured as _1 + n_ days. For example, if you wanted to keep the logs for the current day and the day prior you would set the `retainDays` (or `setRetainDays`) value to 2. -To examine more configuration options, see link:{JDURL}/org/eclipse/jetty/server/NCSARequestLog.html[NCSARequestLog.java]. + +[[request-log-custom-writer]] +==== Introducing RequestLog.Writer + +The concept of a `RequestLog.Writer`, introduced in Jetty 9.4.15, manages the writing to a log the string generated by the `RequestLog`. +This allows the `CustomRequestLog` to match the functionality of other `RequestLogger` implementations by plugging in any `RequestLog.Writer` and a custom format string. +Jetty currently has implementations of `RequestLog.Writer`, `RequestLogWriter`, `AsyncRequestLogWriter`, and `Slf4jRequestLogWriter`. + +So, the way to create an asynchronous `RequestLog` using the extended NCSA format has been changed from: + +`new AsyncNcsaRequestLog(filename)` + +to: + +`new CustomRequestLog(new AsyncRequestLogWriter(filename), CustomRequestLog.EXTENDED_NCSA_FORMAT)` + +Additionally, there are now two settings for the log timezone to be configured. +There is the configuration for logging the request time, which is set in the `timeZone` parameter in the `%t` format code of the string, given in the format `%{format|timeZone|locale}t`. + +The other `timeZone` parameter relates to the generation of the log file name (both at creation and roll over). +This is configured in the `requestlog` module file, or can be used as a setter on `RequestLogWriter` via XML. + +Both timezones are set to GMT by default. [[configuring-separate-request-log-for-web-application]] ==== Configuring a Separate Request Log For a Web Application diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/configuring-logging-modules.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/configuring-logging-modules.adoc index ee4fd3e0d3a..099e9aa972f 100644 --- a/jetty-documentation/src/main/asciidoc/administration/logging/configuring-logging-modules.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/logging/configuring-logging-modules.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/default-logging-with-stderrlog.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/default-logging-with-stderrlog.adoc index 755a4e6c740..ef98aa966ad 100644 --- a/jetty-documentation/src/main/asciidoc/administration/logging/default-logging-with-stderrlog.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/logging/default-logging-with-stderrlog.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/dump-tool.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/dump-tool.adoc index 5d18b7ff921..0f729e2e563 100644 --- a/jetty-documentation/src/main/asciidoc/administration/logging/dump-tool.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/logging/dump-tool.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/example-apache-log4j.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/example-apache-log4j.adoc index 3a943e7d7df..391e9728e2c 100644 --- a/jetty-documentation/src/main/asciidoc/administration/logging/example-apache-log4j.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/logging/example-apache-log4j.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/example-java-util-logging-native.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/example-java-util-logging-native.adoc index 92ff12ceefe..c59be6b6086 100644 --- a/jetty-documentation/src/main/asciidoc/administration/logging/example-java-util-logging-native.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/logging/example-java-util-logging-native.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/example-java-util-logging.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/example-java-util-logging.adoc index 124b12dae79..bf23ce9456c 100644 --- a/jetty-documentation/src/main/asciidoc/administration/logging/example-java-util-logging.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/logging/example-java-util-logging.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/example-logback-centralized-logging.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/example-logback-centralized-logging.adoc index 4d8382fa24f..648fe58c827 100644 --- a/jetty-documentation/src/main/asciidoc/administration/logging/example-logback-centralized-logging.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/logging/example-logback-centralized-logging.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -32,7 +32,8 @@ ____ This configuration is essentially the multiple logger configuration with added configuration to the deployers to force a `WebAppClassLoader` change to use the server classpath over the webapps classpath for the logger specific classes. -The technique used by this configuration is to provide an link:{JDURL}org/eclipse/jetty/deploy/AppLifeCycle.Binding.html[AppLifeCycle.Binding] against the link:{JDURL}/org/eclipse/jetty/deploy/AppLifeCycle.html[`"deploying"`node] that modifies the link:{JDURL}/org/eclipse/jetty/webapp/WebAppContext.html#addSystemClass(java.lang.String)[WebAppContext.addSystemClass(String)] for the common logging classes. +The technique used by this configuration is to provide an link:{JDURL}org/eclipse/jetty/deploy/AppLifeCycle.Binding.html[AppLifeCycle.Binding] against the link:{JDURL}/org/eclipse/jetty/deploy/AppLifeCycle.html[`"deploying"`node] that modifies the +link:{JDURL}/org/eclipse/jetty/webapp/WebAppContext.html#getSystemClasspathPattern()[WebAppContext.getSystemClasspathPattern().add(String)] for the common logging classes. See https://github.com/jetty-project/jetty-webapp-logging/blob/master/src/main/java/org/eclipse/jetty/webapp/logging/CentralizedWebAppLoggingBinding.java[org.eclipse.jetty.logging.CentralizedWebAppLoggingBinding] for actual implementation. A convenient replacement `logging` module has been created to bootstrap your `${jetty.base}` directory for capturing all Jetty server logging from multiple logging frameworks into a single logging output file managed by Logback. diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/example-logback-sifting.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/example-logback-sifting.adoc index b9c0278c498..4f58b0adf7a 100644 --- a/jetty-documentation/src/main/asciidoc/administration/logging/example-logback-sifting.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/logging/example-logback-sifting.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/example-logback.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/example-logback.adoc index b0060639fc8..51e909cbc38 100644 --- a/jetty-documentation/src/main/asciidoc/administration/logging/example-logback.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/logging/example-logback.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/example-slf4j-multiple-loggers.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/example-slf4j-multiple-loggers.adoc index 422ec9e7948..66bf99d6f6b 100644 --- a/jetty-documentation/src/main/asciidoc/administration/logging/example-slf4j-multiple-loggers.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/logging/example-slf4j-multiple-loggers.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/part.adoc b/jetty-documentation/src/main/asciidoc/administration/part.adoc index f449e6cdc67..382c90a4058 100644 --- a/jetty-documentation/src/main/asciidoc/administration/part.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/part.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/runner/chapter.adoc b/jetty-documentation/src/main/asciidoc/administration/runner/chapter.adoc index 57ae50b075d..b6a857ca7f8 100644 --- a/jetty-documentation/src/main/asciidoc/administration/runner/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/runner/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/runner/jetty-runner.adoc b/jetty-documentation/src/main/asciidoc/administration/runner/jetty-runner.adoc index b019e8c6256..26bcd73d9a6 100644 --- a/jetty-documentation/src/main/asciidoc/administration/runner/jetty-runner.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/runner/jetty-runner.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/chapter.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/chapter.adoc index f7a5657d0e9..875c8747317 100644 --- a/jetty-documentation/src/main/asciidoc/administration/sessions/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/session-clustering-gcloud-datastore.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/session-clustering-gcloud-datastore.adoc index f382cdb5a12..e67d55ea952 100644 --- a/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/session-clustering-gcloud-datastore.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/session-clustering-gcloud-datastore.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/session-clustering-infinispan.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/session-clustering-infinispan.adoc index c782941eaf1..3e9fe70d94f 100644 --- a/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/session-clustering-infinispan.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/session-clustering-infinispan.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -94,9 +94,11 @@ From a context xml file, you reference the Server instance as a Ref: [source, xml, subs="{sub-order}"] ---- - - -org.eclipse.jetty.session.infinispan. - + + + -org.eclipse.jetty.session.infinispan. + + @@ -132,10 +134,12 @@ From a `WEB-INF/jetty-web.xml` file, you can reference the Server instance direc [source, xml, subs="{sub-order}"] ---- - - + + + -org.eclipse.jetty.session.infinispan. + @@ -143,25 +147,25 @@ From a `WEB-INF/jetty-web.xml` file, you can reference the Server instance direc - - - + + + - - - - - - - - - - 600 - - + + + + + + + + + + 600 + + ---- @@ -178,7 +182,7 @@ staleIntervalSec:: ===== Using HotRod If you're using the hotrod client - where serialization will be required - you will need to ensure that the hotrod marshalling software works with Jetty classloading. -To do this, firstly ensure that you have included the lines containing the `prependServerClass` to your context xml file as shown above. +To do this, firstly ensure that you have included the lines containing the `getServerClasspathPattern().add(...)` to your context xml file as shown above. Then, create the file `${jetty.base}/resources/hotrod-client.properties`. Add the following line to this file: diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/session-clustering-jdbc.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/session-clustering-jdbc.adoc index 8470fab0a64..f154c2b7434 100644 --- a/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/session-clustering-jdbc.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/session-clustering-jdbc.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/session-clustering-mongodb.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/session-clustering-mongodb.adoc index d817d3b62f9..9f00ef6a57a 100644 --- a/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/session-clustering-mongodb.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/session-clustering-mongodb.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/setting-session-characteristics.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/setting-session-characteristics.adoc index b50c9dcc543..60a112e87d8 100644 --- a/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/setting-session-characteristics.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/setting-session-characteristics.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/using-persistent-sessions.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/using-persistent-sessions.adoc index 0ae44005dae..d68f34a2cb4 100644 --- a/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/using-persistent-sessions.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/using-persistent-sessions.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-file-system.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-file-system.adoc index e88f173f9cf..a824a8aa866 100644 --- a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-file-system.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-file-system.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-gcloud.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-gcloud.adoc index 7360d96082f..0a349212ff9 100644 --- a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-gcloud.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-gcloud.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-hazelcast.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-hazelcast.adoc index 193e7a6d9ae..ba8bfd985e5 100644 --- a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-hazelcast.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-hazelcast.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -84,6 +84,7 @@ Opening the `start.d/session-store-hazelcast-remote.ini` will show a list of all #jetty.session.hazelcast.mapName=jetty_sessions #jetty.session.hazelcast.onlyClient=true #jetty.session.hazelcast.configurationLocation= +jetty.session.hazelcast.scavengeZombies=false #jetty.session.gracePeriod.seconds=3600 #jetty.session.savePeriod.seconds=0 ---- @@ -94,6 +95,8 @@ jetty.session.hazelcast.onlyClient:: Hazelcast instance will be configured in client mode jetty.session.hazelcast.configurationLocation:: Path to an an Hazelcast xml configuration file +jetty.session.hazelcast.scavengeZombies:: +True/False. `False` by default. If `true`, jetty will use hazelcast queries to find sessions that are no longer being used on any jetty node and whose expiry time has passed. If you enable this option, and your session stores attributes that reference classes from inside your webapp, or jetty classes, you will need to ensure that these classes are available on each of your hazelcast instances. jetty.session.gracePeriod.seconds:: Amount of time, in seconds, to wait for other nodes to be checked to verify an expired session is in fact expired throughout the cluster before closing it. jetty.session.savePeriod.seconds=0:: @@ -106,6 +109,8 @@ Configuring `savePeriod` is useful if your persistence technology is very slow/c In a clustered environment, there is a risk of the last access time of the session being out-of-date in the shared store for up to `savePeriod` seconds. This allows the possibility that a node may prematurely expire the session, even though it is in use by another node. Thorough consideration of the `maxIdleTime` of the session when setting the `savePeriod` is imperative - there is no point in setting a `savePeriod` that is larger than the `maxIdleTime`. + +Be aware using the `scavengeZombies` option that if your session attributes contain classes from inside your webapp (or jetty classes) then you will need to put these classes onto the classpath of all of your hazelcast instances. ____ ==== Configuring Embedded Hazelcast Clustering @@ -165,15 +170,18 @@ Opening the `start.d/start.d/session-store-hazelcast-embedded.ini` will show a l #jetty.session.hazelcast.mapName=jetty_sessions #jetty.session.hazelcast.configurationLocation= +jetty.session.hazelcast.scavengeZombies=false #jetty.session.gracePeriod.seconds=3600 #jetty.session.savePeriod.seconds=0 ---- jetty.session.hazelcast.mapName:: Name of the Map in Hazelcast where sessions will be stored. -jetty.session.gracePeriod.seconds:: -Amount of time, in seconds, to wait for other nodes to be checked to verify an expired session is in fact expired throughout the cluster before closing it. jetty.session.hazelcast.configurationLocation:: Path to an an Hazelcast xml configuration file +jetty.session.hazelcast.scavengeZombies:: +True/False. `False` by default. If `true`, jetty will use hazelcast queries to find sessions that are no longer being used on any jetty node and whose expiry time has passed. If you enable this option, and your sessions contain attributes that reference classes from inside your webapp (or jetty classes) you will need to ensure that these classes are available on each of your hazelcast instances. +jetty.session.gracePeriod.seconds:: +Amount of time, in seconds, to wait for other nodes to be checked to verify an expired session is in fact expired throughout the cluster before closing it. jetty.session.savePeriod.seconds=0:: By default whenever the last concurrent request leaves a session, that session is always persisted via the `SessionDataStore`, even if the only thing that changed on the session is its updated last access time. A non-zero value means that the `SessionDataStore` will skip persisting the session if only the access time changed, and it has been less than `savePeriod` seconds since the last time the session was written. @@ -184,4 +192,6 @@ Configuring `savePeriod` is useful if your persistence technology is very slow/c In a clustered environment, there is a risk of the last access time of the session being out-of-date in the shared store for up to `savePeriod` seconds. This allows the possibility that a node may prematurely expire the session, even though it is in use by another node. Thorough consideration of the `maxIdleTime` of the session when setting the `savePeriod` is imperative - there is no point in setting a `savePeriod` that is larger than the `maxIdleTime`. + +Be aware using the `scavengeZombies` option that if your session attributes contain classes from inside your webapp (or jetty classes) then you will need to put these classes onto the classpath of all of your hazelcast instances. In the cast of embedded hazelcast, as it is started before your webapp, it will NOT have access to your webapp's classes - you will need to extract these classes and put them onto the jetty server's classpath. ____ diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-housekeeper.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-housekeeper.adoc index 4470b2eae13..398dd99cbac 100644 --- a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-housekeeper.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-housekeeper.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-infinispan.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-infinispan.adoc index 07528662522..e8274075591 100644 --- a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-infinispan.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-infinispan.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -24,10 +24,6 @@ When using the Jetty distribution, you will first need to enable the `session-store-infinispan-remote` link:#startup-modules[module] for your link:#startup-base-and-home[Jetty base] using the `--add-to-start` argument on the command line. -____ -[IMPORTANT] -If you are running Jetty with JDK 9 or greater, enable `session-store-infinispan-remote-910.mod` instead. -____ [source, screen, subs="{sub-order}"] ---- @@ -52,7 +48,7 @@ INFO : server transitively enabled, ini template available with --add- INFO : sessions transitively enabled, ini template available with --add-to-start=sessions INFO : session-store-infinispan-remote initialized in ${jetty.base}/start.d/session-store-infinispan-remote.ini MKDIR : ${jetty.base}/lib/infinispan -DOWNLD: https://repo1.maven.org/maven2/org/infinispan/infinispan-remote/7.1.1.Final/infinispan-remote-7.1.1.Final.jar to ${jetty.base}/lib/infinispan/infinispan-remote-7.1.1.Final.jar +DOWNLD: https://repo1.maven.org/maven2/org/infinispan/infinispan-remote-it/9.4.8.Final/infinispan-remote-it-9.4.8.Final.jar to ${jetty.base}/lib/infinispan/infinispan-remote-it-9.4.8.Final.jar MKDIR : ${jetty.base}/resources COPY : ${jetty.home}/modules/session-store-infinispan-remote/resources/hotrod-client.properties to ${jetty.base}/resources/hotrod-client.properties INFO : Base directory was modified @@ -93,13 +89,17 @@ Opening the `start.d/session-store-infinispan-remote.ini` will show a list of al jetty.session.infinispan.remoteCacheName:: Name of the cache in Infinispan where sessions will be stored. jetty.session.infinispan.idleTimeout.seconds:: -Amount of time, in seconds, that the system allows the connector to remain idle before closing the connection. +Amount of time, in seconds, that a session entry in infinispan can be idle (ie not read or written) before infinispan will delete its entry. +Usually, you do *not* want to set a value for this, as you want jetty to handle all session expiration (and call any SessionListeners). +However, if there is the possibility that sessions can be left in infinispan but no longer referenced by any jetty node (so called "zombie" or "orphan" sessions), then you might want to use this feature. +You should make sure that the number of seconds you specify is sufficiently large to avoid the situation where a session is still being referenced by jetty, but is rarely accessed and thus deleted by infinispan. +Alternatively, you can enable the `infinispan-remote-query` module, which will allow jetty to search the infinispan session cache to proactively find and properly (ie calling any SessionListeners) scavenge defunct sessions. jetty.session.gracePeriod.seconds:: Amount of time, in seconds, to wait for other nodes to be checked to verify an expired session is in fact expired throughout the cluster before closing it. jetty.session.savePeriod.seconds=0:: By default whenever the last concurrent request leaves a session, that session is always persisted via the `SessionDataStore`, even if the only thing that changed on the session is its updated last access time. A non-zero value means that the `SessionDataStore` will skip persisting the session if only the access time changed, and it has been less than `savePeriod` seconds since the last time the session was written. -+ + ____ [NOTE] Configuring `savePeriod` is useful if your persistence technology is very slow/costly for writes. @@ -108,6 +108,19 @@ This allows the possibility that a node may prematurely expire the session, even Thorough consideration of the `maxIdleTime` of the session when setting the `savePeriod` is imperative - there is no point in setting a `savePeriod` that is larger than the `maxIdleTime`. ____ +==== Configuring the Remote Infinispan Query Module + +Enabling this module allows jetty to search infinispan for expired sessions that are no longer being referenced by any jetty node. +Note that this is an *additional* module, to be used in conjuction with the `session-store-infinispan-remote` module. + +[source, screen, subs="{sub-order}"] +---- +java -jar ../start.jar --add-to-start=infinispan-remote-query +---- + +There are no configuration properties associated with this module. + + ==== Configuring Embedded Inifinspan Clustering During testing, it can be helpful to run an in-process instance of Infinispan. @@ -137,7 +150,7 @@ Proceed (y/N)? y INFO : server initialised (transitively) in ${jetty.base}/start.d/server.ini INFO : sessions initialised (transitively) in ${jetty.base}/start.d/sessions.ini INFO : session-store-infinispan-embedded initialised in ${jetty.base}/start.d/session-store-infinispan-embedded.ini -DOWNLOAD: https://repo1.maven.org/maven2/org/infinispan/infinispan-embedded/7.1.1.Final/infinispan-embedded-7.1.1.Final.jar to ${jetty.base}/lib/infinispan/infinispan-embedded-7.1.1.Final.jar +DOWNLOAD: https://repo1.maven.org/maven2/org/infinispan/infinispan-embedded-it/9.4.8.Final/infinispan-embedded-it-9.4.8.Final.jar to ${jetty.base}/lib/infinispan/infinispan-embedded-it-9.4.8.Final.jar INFO : Base directory was modified ---- @@ -179,3 +192,57 @@ In a clustered environment, there is a risk of the last access time of the sessi This allows the possibility that a node may prematurely expire the session, even though it is in use by another node. Thorough consideration of the `maxIdleTime` of the session when setting the `savePeriod` is imperative - there is no point in setting a `savePeriod` that is larger than the `maxIdleTime`. ____ + + +==== Configuring Inifinspan Embedded Query + +Similarly to the `session-store-infinispan-remote` module, the `session-store-infinispan-embedded` module has an adjunct module `infinispan-embedded-query`, which when enabled, will allow jetty to detect and properly scavenge defunct sessions stranded in infinispan. + +[source, screen, subs="{sub-order}"] +---- +java -jar ../start.jar --add-to-start=infinispan-embedded-query +---- + +There are no configuration properties associated with this module. + + +==== Converting session format for jetty-9.4.13 + +From jetty-9.4.13 onwards, we have changed the format of the serialized session when using a remote cache (ie using hotrod). +Prior to release 9.4.13 we used the default Infinispan serialization, however this was not able to store sufficient information to allow jetty to properly deserialize session attributes in all circumstances. +See issue https://github.com/eclipse/jetty.project/issues/2919 for more background. + +We have provided a conversion program which will convert any sessions stored in Infinispan to the new format. +____ +[IMPORTANT] +We recommend that you backup your stored sessions before running the conversion program. +____ + +How to use the converter: + +[source, screen, subs="{sub-order}"] +---- +java -cp servlet-api-3.1.jar:jetty-util-9.4.13.jar:jetty-server-9.4.13.jar:infinispan-remote-9.1.0.Final.jar:jetty-infinispan-9.4.13.jar:[other classpath] org.eclipse.jetty.session.infinispan.InfinispanSessionLegacyConverter + +Usage: InfinispanSessionLegacyConverter [-Dhost=127.0.0.1] [-Dverbose=true|false] [check] +---- + +The classpath:: +Must contain the servlet-api, jetty-util, jetty-server, jetty-infinispan and infinispan-remote jars. If your sessions contain attributes that use application classes, you will also need to also put those classes onto the classpath. If your session has been authenticated, you may also need to include the jetty-security and jetty-http jars on the classpath. +Parameters:: +When used with no arguments the usage message is printed. When used with the `cache-name` parameter the conversion is performed. When used with both `cache-name` and `check` parameters, sessions are checked for whether or not they are converted. + + -Dhost::: you can optionally provide a system property with the address of your remote Infinispan server. Defaults to the localhost. + -Dverbose::: defaults to false. If true, prints more comprehensive stacktrace information about failures. Useful to diagnose why a session is not converted. + cache-name::: the name of the remote cache containing your sessions. This is mandatory. + check::: the optional check command will verify sessions have been converted. Use it _after_ doing the conversion. + +To perform the conversion, run the InfinispanSessionLegacyConverter with just the `cache-name`, and optionally the `host` system property. +The following command will attempt to convert all sessions in the cached named `my-remote-cache` on the machine `myhost`, ensuring that application classes in the `/my/custom/classes` directory are on the classpath: + +[source, screen, subs="{sub-order}"] +---- +java -cp servlet-api-3.1.jar:jetty-util-9.4.13.jar:jetty-server-9.4.13.jar:infinispan-remote-9.1.0.Final.jar:jetty-infinispan-9.4.13.jar:/my/custom/classes org.eclipse.jetty.session.infinispan.InfinispanSessionLegacyConverter -Dhost=myhost my-remote-cache +---- + +If the converter fails to convert a session, an error message and stacktrace will be printed and the conversion will abort. The failed session should be untouched, however _it is prudent to take a backup of your cache before attempting the conversion_. diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-jdbc.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-jdbc.adoc index 85cc4658518..7fd85eb66b3 100644 --- a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-jdbc.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-jdbc.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-memcachedsessiondatastore.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-memcachedsessiondatastore.adoc index 7e5772db601..e03141b40b4 100644 --- a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-memcachedsessiondatastore.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-memcachedsessiondatastore.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-memory.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-memory.adoc index 7d59cb57790..0c854251e81 100644 --- a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-memory.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-memory.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-mongodb.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-mongodb.adoc index 35c2525cfb2..418328c0760 100644 --- a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-mongodb.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-mongodb.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-sessioncache.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-sessioncache.adoc index b9775a258af..d06c0f74f28 100644 --- a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-sessioncache.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-sessioncache.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/session-hierarchy.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/session-hierarchy.adoc index 4734dc90301..f8a760e7510 100644 --- a/jetty-documentation/src/main/asciidoc/administration/sessions/session-hierarchy.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/session-hierarchy.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/sessions-details.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/sessions-details.adoc index e87f382f7bb..7e89e729039 100644 --- a/jetty-documentation/src/main/asciidoc/administration/sessions/sessions-details.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/sessions-details.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/sessions-usecases.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/sessions-usecases.adoc index 87cb3ba6e65..9e6c43e8047 100644 --- a/jetty-documentation/src/main/asciidoc/administration/sessions/sessions-usecases.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/sessions-usecases.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/startup/chapter.adoc b/jetty-documentation/src/main/asciidoc/administration/startup/chapter.adoc index 441d8d47d87..50a635f1544 100644 --- a/jetty-documentation/src/main/asciidoc/administration/startup/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/startup/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -28,3 +28,4 @@ include::custom-modules.adoc[] include::startup-xml-config.adoc[] include::startup-unix-service.adoc[] include::startup-windows-service.adoc[] +include::startup-jpms.adoc[] diff --git a/jetty-documentation/src/main/asciidoc/administration/startup/custom-modules.adoc b/jetty-documentation/src/main/asciidoc/administration/startup/custom-modules.adoc index e070669d1be..8664c8dcc92 100644 --- a/jetty-documentation/src/main/asciidoc/administration/startup/custom-modules.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/startup/custom-modules.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -79,6 +79,8 @@ If a user does not accept the license agreement, the module will not be activate Additional Startup Commands - `[exec]`:: The `[exec]` section is used to define additional parameters specific to the module. These commands are added to the server startup. +JPMS Module-Path Definitions - `[jpms]`:: +The `[jpms]` section is used to add link:#startup-jpms[JPMS modules] to the module-path for startup when using the `--jpms` command. [[custom-module-properties]] ==== Module Properties diff --git a/jetty-documentation/src/main/asciidoc/administration/startup/screen-empty-base-listconfig.adoc b/jetty-documentation/src/main/asciidoc/administration/startup/screen-empty-base-listconfig.adoc index 712487db306..1ed43bfbfd1 100644 --- a/jetty-documentation/src/main/asciidoc/administration/startup/screen-empty-base-listconfig.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/startup/screen-empty-base-listconfig.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/startup/screen-empty-base.adoc b/jetty-documentation/src/main/asciidoc/administration/startup/screen-empty-base.adoc index 260c86a487b..d22e0bf36ff 100644 --- a/jetty-documentation/src/main/asciidoc/administration/startup/screen-empty-base.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/startup/screen-empty-base.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/startup/screen-http-webapp-deploy-listconfig.adoc b/jetty-documentation/src/main/asciidoc/administration/startup/screen-http-webapp-deploy-listconfig.adoc index b63440dda76..f56b90a72a7 100644 --- a/jetty-documentation/src/main/asciidoc/administration/startup/screen-http-webapp-deploy-listconfig.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/startup/screen-http-webapp-deploy-listconfig.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/startup/screen-http-webapp-deploy.adoc b/jetty-documentation/src/main/asciidoc/administration/startup/screen-http-webapp-deploy.adoc index 7698aada319..7594413b7c1 100644 --- a/jetty-documentation/src/main/asciidoc/administration/startup/screen-http-webapp-deploy.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/startup/screen-http-webapp-deploy.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/startup/screen-list-logging-modules.adoc b/jetty-documentation/src/main/asciidoc/administration/startup/screen-list-logging-modules.adoc index e4cc6d88542..ca175842225 100644 --- a/jetty-documentation/src/main/asciidoc/administration/startup/screen-list-logging-modules.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/startup/screen-list-logging-modules.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/startup/screen-list-modules.adoc b/jetty-documentation/src/main/asciidoc/administration/startup/screen-list-modules.adoc index 8093141ecb8..fce1982a38e 100644 --- a/jetty-documentation/src/main/asciidoc/administration/startup/screen-list-modules.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/startup/screen-list-modules.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -56,19 +56,6 @@ Modules for tag '*': LIB: lib/apache-jstl/*.jar Enabled: transitive provider of apache-jstl for jstl - Module: cdi - : Experimental CDI/Weld integration - Depend: cdi1 - - Module: cdi1 - : Experimental CDI/Weld integration - : Deprecated in favour of cdi2 module. - Depend: deploy, annotations, plus, jsp - LIB: lib/cdi/*.jar - LIB: lib/cdi-core-${jetty.version}.jar - LIB: lib/cdi-servlet-${jetty.version}.jar - XML: etc/jetty-cdi.xml - Module: cdi2 : Jetty setup to support Weld/CDI2 with WELD inside the webapp Depend: deploy diff --git a/jetty-documentation/src/main/asciidoc/administration/startup/start-jar.adoc b/jetty-documentation/src/main/asciidoc/administration/startup/start-jar.adoc index 2a713497958..2dbd3be34e3 100644 --- a/jetty-documentation/src/main/asciidoc/administration/startup/start-jar.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/startup/start-jar.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/startup/start-matrix.adoc b/jetty-documentation/src/main/asciidoc/administration/startup/start-matrix.adoc index 051749fba36..013d80a8b64 100644 --- a/jetty-documentation/src/main/asciidoc/administration/startup/start-matrix.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/startup/start-matrix.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/startup/startup-base-vs-home.adoc b/jetty-documentation/src/main/asciidoc/administration/startup/startup-base-vs-home.adoc index e5c347a8a00..6e3f8b6a959 100644 --- a/jetty-documentation/src/main/asciidoc/administration/startup/startup-base-vs-home.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/startup/startup-base-vs-home.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,6 +20,7 @@ === Managing Jetty Base and Jetty Home Instead of managing multiple Jetty implementations out of several different distribution locations, it is possible to maintain a separation between the binary installation of the standalone Jetty (known as `${jetty.home}`), and the customizations for your specific environment(s) (known as `${jetty.base}`). +In addition to easy management of multiple server instances, is allows for quick, drop-in upgrades of Jetty. There should always only be *one* Jetty Home (per version of Jetty), but there can be multiple Jetty Base directories that reference it. Jetty Base:: @@ -170,7 +171,7 @@ Note: order presented here is how they would appear on the classpath. 13: {VERSION} | ${jetty.home}/lib/jetty-jndi-{VERSION}.jar 14: 1.1.0.v201105071233 | ${jetty.home}/lib/jndi/javax.activation-1.1.0.v201105071233.jar 15: 1.4.1.v201005082020 | ${jetty.home}/lib/jndi/javax.mail.glassfish-1.4.1.v201005082020.jar -16: 1.2 | ${jetty.home}/lib/jndi/javax.transaction-api-1.2.jar +16: 1.3 | ${jetty.home}/lib/jndi/javax.transaction-api-1.3.jar 17: {VERSION} | ${jetty.home}/lib/jetty-rewrite-{VERSION}.jar 18: {VERSION} | ${jetty.home}/lib/jetty-security-{VERSION}.jar 19: {VERSION} | ${jetty.home}/lib/jetty-servlet-{VERSION}.jar diff --git a/jetty-documentation/src/main/asciidoc/administration/startup/startup-classpath.adoc b/jetty-documentation/src/main/asciidoc/administration/startup/startup-classpath.adoc index 4a51bc158bb..6394d918527 100644 --- a/jetty-documentation/src/main/asciidoc/administration/startup/startup-classpath.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/startup/startup-classpath.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -80,7 +80,7 @@ Note: order presented here is how they would appear on the classpath. 13: {VERSION} | ${jetty.home}/lib/jetty-jndi-{VERSION}.jar 14: 1.1.0.v201105071233 | ${jetty.home}/lib/jndi/javax.activation-1.1.0.v201105071233.jar 15: 1.4.1.v201005082020 | ${jetty.home}/lib/jndi/javax.mail.glassfish-1.4.1.v201005082020.jar -16: 1.2 | ${jetty.home}/lib/jndi/javax.transaction-api-1.2.jar +16: 1.3 | ${jetty.home}/lib/jndi/javax.transaction-api-1.3.jar 17: {VERSION} | ${jetty.home}/lib/jetty-rewrite-{VERSION}.jar 18: {VERSION} | ${jetty.home}/lib/jetty-security-{VERSION}.jar 19: {VERSION} | ${jetty.home}/lib/jetty-servlet-{VERSION}.jar diff --git a/jetty-documentation/src/main/asciidoc/administration/startup/startup-jpms.adoc b/jetty-documentation/src/main/asciidoc/administration/startup/startup-jpms.adoc new file mode 100644 index 00000000000..7d149169c2f --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/startup/startup-jpms.adoc @@ -0,0 +1,192 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ======================================================================== +// 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. +// ======================================================================== +// + +[[startup-jpms]] +=== Startup using the Java Platform Module System (JPMS) + +Jetty modules also act as automatic https://en.wikipedia.org/wiki/Java_Platform_Module_System[JPMS] modules via the `Automatic-Module-Name` attribute in the jar's `MANIFEST.MF` file. + +This makes possible to run Jetty from the module-path, rather than the class-path. + +We recommend using JDK 11 or greater due to the fact that JDK 11 removed all the "enterprise" modules from the JDK, +and therefore it guarantees a more stable platform to base your application's dependencies on. +The classes in these "enterprise" modules were bundled with JDK 8, and present in "enterprise" modules in JDK 9 and JDK 10. +With JDK 11, these "enterprise" classes are either not available in the JDK (because their corresponding module was removed), or they are present in a different module. + +Because some of these "enterprise" classes are required by Jetty or by applications running in Jetty, it is better to use a stable source for those classes - in this case by using JDK 11 +or greater, and explicitly referencing the "enterprise" classes as dependencies, rather than assuming they are bundled with the JDK. + +[[jpms-module-path]] +==== Starting Jetty on the module-path + +To start Jetty on the module-path rather than the class-path, it is enough to add the `--jpms` option to the command line, for example: + +[source, screen, subs="{sub-order}"] +.... +$ mkdir my-jetty-base +$ cd my-jetty-base +$ java -jar $JETTY_HOME/start.jar --add-to-start=http +INFO : server transitively enabled, ini template available with --add-to-start=server +INFO : http initialized in ${jetty.base}/start.ini +INFO : threadpool transitively enabled, ini template available with --add-to-start=threadpool +INFO : Base directory was modified +$ java -jar $JETTY_HOME/start.jar --jpms +.... + +The example above creates a link:#startup-base-and-home[Jetty base directory] and enables the `http` module using the `--add-to-start` command. +The server then starts Jetty on the module-path using the `--jpms` option. + +---- +[NOTE] +When running on the module-path using the `--jpms` option, the Jetty start mechanism will fork a second JVM passing it the right JVM options to run on the module-path. +You will have two JVMs running: one that runs `start.jar` and one that runs Jetty on the module-path. +---- + +If you are interested in the details of how the command line to run Jetty on the module-path looks like, you can add the `--dry-run` option: + +[source, screen, subs="{sub-order}"] +.... +$ java -jar $JETTY_HOME/start.jar --jpms --dry-run +.... + +This will give an output looking something like this (broken in sections for clarity): + +[source, screen, subs="{sub-order}"] +.... +/opt/openjdk-11+28/bin/java +--module-path /opt/jetty/lib/servlet-api-3.1.jar:/opt/jetty/lib/jetty-schemas-3.1.jar:/opt/jetty/lib/jetty-http-9.4.13-SNAPSHOT.jar:... +--patch-module servlet.api=/opt/jetty/lib/jetty-schemas-3.1.jar +--module org.eclipse.jetty.xml/org.eclipse.jetty.xml.XmlConfiguration /opt/jetty/etc/jetty-threadpool.xml /opt/jetty/etc/jetty.xml ... +.... + +The `--module-path` option specifies the list of Jetty jars. +This list depends on the Jetty modules that have been enabled via the link:#startup-modules[`--add-to-start`] command. + +The `--patch-module` option is necessary for Servlet and JSP Containers to find XML DTDs and XML Schemas required to validate the various XML files present in web applications (such as `web.xml` and others). + +The `--module` option tells the JVM to run main class `XmlConfiguration` from the `org.eclipse.jetty.xml` module, with the given XML files as program arguments. + +When the JVM starts, module `org.eclipse.jetty.xml` is added to the set of JPMS _root modules_; all other Jetty modules, being automatic, will be resolved and added to the module graph. +JAR files that are not modules, such as `servlet-api-3.1.jar`, are on the module-path and therefore will be made automatic modules by the JVM (hence the derived module name `servlet.api` for this jar, referenced by the `--patch-module` command line option above). + +[[jpms-advanced-config]] +==== Advanced JPMS Configuration + +Web applications may need additional services from the Servlet Container, such as JDBC `DataSource` references or JTA `UserTransaction` references. + +For example, for JDBC it is typical to store, in JNDI, a reference to the connection pool's `DataSource` (such as `com.zaxxer.hikari.HikariDataSource`) or a reference directly to the JDBC driver's `DataSource` (`com.mysql.jdbc.jdbc2.optional.MysqlDataSource`). +Jetty needs to be able to instantiate those classes and therefore needs to be able to load those classes and all their super-classes, among which includes `javax.sql.DataSource`. + +When Jetty runs on the class-path, this is easily achieved by using a link:#custom-modules[custom module]: + +[source, screen, subs="{sub-order}"] +.mysql.mod +.... +[description] +MySQL module + +[lib] +lib/mysql/mysql-connector-java-*.jar +.... + +However, when running on the module-path, things are quite different. + +Class `javax.sql.DataSource` is in a JDK bundled module named `java.sql`, which is not automatic (it's a proper JPMS module) and it is not in the _root modules_ set. +Because it is not an automatic module, it is not added to the module graph, and therefore needs to be added explicitly using the JVM command line `--add-modules`. + +To add the JPMS module `java.sql` to the module graph, you need to modify your custom module in the following way, using our `mysql.mod` as an example: + +[source, screen, subs="{sub-order}"] +.mysql.mod +.... +[description] +MySQL module + +[lib] +lib/mysql/mysql-connector-java-*.jar + +[jpms] +add-modules: java.sql +.... + +The new `[jpms]` section is only used when Jetty is started on the module-path via the `--jpms` command line option. + +Assuming that `mysql-connector-java-*.jar` is a non JPMS modular jar, or an automatic JPMS modular jar, the Jetty start mechanism will add `mysql-connector-java-*.jar` to the module-path, and will add the JVM command line option `--add-modules java.sql`. + +If `mysql-connector-java-*.jar` were a proper JPMS modular jar with name (for example) `com.mysql.jdbc`, then it would need to be explicitly added to the module graph, in this way: + +[source, screen, subs="{sub-order}"] +.mysql.mod +.... +[description] +MySQL module + +[lib] +lib/mysql/mysql-connector-java-*.jar + +[jpms] +add-modules: com.mysql.jdbc +.... + +The JPMS module `java.sql` does not need to be explicitly added because it would be a dependency of the `com.mysql.jdbc` module and therefore automatically added to the module graph. + +The `[jpms]` section has the following format: + +[source, screen, subs="{sub-order}"] +.... +[jpms] +add-modules: (,)* +patch-module: =(:)* +add-opens: /=(,)* +add-exports: /=(,)* +add-reads: =(,)* +.... + +[[jpms-module-path-alternative]] +==== Alternative way to start Jetty on the module-path + +The section above uses the `--jpms` command line option to start Jetty on the module-path. +An alternative way of achieving the same result is to use a Jetty module, `$JETTY_BASE/modules/jpms.mod`, +that specifies that you want to run using JPMS (and possibly add some JPMS specific configuration). + +[source, screen, subs="{sub-order}"] +.jpms.mod +.... +[ini] +--jpms + +[jpms] +# Additional JPMS configuration. +.... + +The `[ini]` section is equivalent to passing the `--jpms` option to the command line. +The `[jpms]` section (see also the link:#jpms-advanced-config[advanced JPMS configuration section]) +allows you specify additional JPMS configuration. + +[source, screen, subs="{sub-order}"] +.... +$ mkdir jetty-base-jpms +$ cd jetty-base-jpms +$ mkdir modules +# Copy the jpms.mod file above into the $JETTY_BASE/modules/ directory. +$ cp /tmp/jpms.mod modules/ +# Add both the http and the jpms modules. +$ java -jar $JETTY_HOME/start.jar --add-to-start=http,jpms +# Jetty will start on the module-path. +$ java -jar $JETTY_HOME/start.jar +.... diff --git a/jetty-documentation/src/main/asciidoc/administration/startup/startup-modules.adoc b/jetty-documentation/src/main/asciidoc/administration/startup/startup-modules.adoc index ee2ff06ebe3..014546eea6d 100644 --- a/jetty-documentation/src/main/asciidoc/administration/startup/startup-modules.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/startup/startup-modules.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/startup/startup-overview.adoc b/jetty-documentation/src/main/asciidoc/administration/startup/startup-overview.adoc index 6193508a076..400d36d14f9 100644 --- a/jetty-documentation/src/main/asciidoc/administration/startup/startup-overview.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/startup/startup-overview.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/startup/startup-troubleshooting.adoc b/jetty-documentation/src/main/asciidoc/administration/startup/startup-troubleshooting.adoc index 72058630181..58f8027c2a5 100644 --- a/jetty-documentation/src/main/asciidoc/administration/startup/startup-troubleshooting.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/startup/startup-troubleshooting.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/startup/startup-unix-service.adoc b/jetty-documentation/src/main/asciidoc/administration/startup/startup-unix-service.adoc index a7d704e3d30..c8b381b9eff 100644 --- a/jetty-documentation/src/main/asciidoc/administration/startup/startup-unix-service.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/startup/startup-unix-service.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/startup/startup-windows-service.adoc b/jetty-documentation/src/main/asciidoc/administration/startup/startup-windows-service.adoc index aceb9a325ff..2bc40090b31 100644 --- a/jetty-documentation/src/main/asciidoc/administration/startup/startup-windows-service.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/startup/startup-windows-service.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -147,7 +147,7 @@ We'll start by specifying which modules we want to use (this will create a start [source, screen, subs="{sub-order}"] .... -C:\opt\myappbase>java -jar ..\jetty\start.jar --add-to-start=deploy,http,logging +C:\opt\myappbase>java -jar ..\jetty\start.jar --add-to-start=deploy,http,console-capture WARNING: deploy initialised in ${jetty.base}\start.ini (appended) WARNING: deploy enabled in ${jetty.base}\start.ini @@ -260,7 +260,7 @@ set PR_STOPPARAMS=--stop;STOP.KEY="%STOPKEY%";STOP.PORT=%STOPPORT%;STOP.WAIT=10 --JvmMs="%PR_JVMMS%" ^ --JvmMx="%PR_JVMMX%" ^ --JvmSs="%PR_JVMSS%" ^ - --JvmOptions="%PR_JVMOPTIONS%" ^ + --JvmOptions=%PR_JVMOPTIONS% ^ --Classpath="%PR_CLASSPATH%" ^ --StartMode="%PR_STARTMODE%" ^ --StartClass="%JETTY_START_CLASS%" ^ diff --git a/jetty-documentation/src/main/asciidoc/administration/startup/startup-xml-config.adoc b/jetty-documentation/src/main/asciidoc/administration/startup/startup-xml-config.adoc index f8bc6dfda0a..1f83416b3cc 100644 --- a/jetty-documentation/src/main/asciidoc/administration/startup/startup-xml-config.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/startup/startup-xml-config.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/tuning/chapter.adoc b/jetty-documentation/src/main/asciidoc/administration/tuning/chapter.adoc index d534a8a1692..be0a01ae936 100644 --- a/jetty-documentation/src/main/asciidoc/administration/tuning/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/tuning/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/tuning/garbage-collection.adoc b/jetty-documentation/src/main/asciidoc/administration/tuning/garbage-collection.adoc index cd34d0a8761..d774428c9b3 100644 --- a/jetty-documentation/src/main/asciidoc/administration/tuning/garbage-collection.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/tuning/garbage-collection.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/tuning/high-load.adoc b/jetty-documentation/src/main/asciidoc/administration/tuning/high-load.adoc index 8e536c0077f..145ff5e6bad 100644 --- a/jetty-documentation/src/main/asciidoc/administration/tuning/high-load.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/tuning/high-load.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/administration/tuning/limit-load.adoc b/jetty-documentation/src/main/asciidoc/administration/tuning/limit-load.adoc index 537e0bfe1e4..e93f7156844 100644 --- a/jetty-documentation/src/main/asciidoc/administration/tuning/limit-load.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/tuning/limit-load.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/configuring/connectors/chapter.adoc b/jetty-documentation/src/main/asciidoc/configuring/connectors/chapter.adoc index e1b48a8f6a9..61d75a6e0f9 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/connectors/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/connectors/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/configuring/connectors/configuring-connectors.adoc b/jetty-documentation/src/main/asciidoc/configuring/connectors/configuring-connectors.adoc index 1822811b293..f0adcb24ecd 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/connectors/configuring-connectors.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/connectors/configuring-connectors.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -472,7 +472,7 @@ This adds a `SecureRequestCustomizer` which adds SSL Session IDs and certificate ==== SSL Context Configuration The SSL/TLS connectors for HTTPS and HTTP/2 require a certificate to establish a secure connection. -Jetty holds certificates in standard JVM keystores and are configured as keystore and truststores on a link:{JDURL}/org/eclipse/jetty/util/ssl/SslContextFactory.html[`SslContextFactory`] instance that is injected into an link:{JDURL}/org/eclipse/jetty/server/SslConnectionFactory.html[`SslConnectionFactory`] instance. +Jetty holds certificates in standard JVM keystores and are configured as keystore and truststores on a link:{JDURL}/org/eclipse/jetty/util/ssl/SslContextFactory.Server.html[`SslContextFactory.Server`] instance that is injected into an link:{JDURL}/org/eclipse/jetty/server/SslConnectionFactory.html[`SslConnectionFactory`] instance. An example using the keystore distributed with Jetty (containing a self signed test certificate) is in link:{GITBROWSEURL}/jetty-server/src/main/config/etc/jetty-https.xml[`jetty-https.xml`]. Read more about SSL keystores in link:#configuring-ssl[Configuring SSL]. diff --git a/jetty-documentation/src/main/asciidoc/configuring/connectors/configuring-ssl-distribution.adoc b/jetty-documentation/src/main/asciidoc/configuring/connectors/configuring-ssl-distribution.adoc index 2f482785b0b..d2725e63756 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/connectors/configuring-ssl-distribution.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/connectors/configuring-ssl-distribution.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/configuring/connectors/configuring-ssl.adoc b/jetty-documentation/src/main/asciidoc/configuring/connectors/configuring-ssl.adoc index 41408190c55..8b4cba0acd5 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/connectors/configuring-ssl.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/connectors/configuring-ssl.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -55,9 +55,8 @@ You can re-enable these by re-declaring the ciphers you want excluded in code: [source, java, subs="{sub-order}"] ---- -SslContextFactory sslContextFactory = new SslContextFactory(); -sslContextFactory.setExcludeCipherSuites( - "^.*_(MD5|SHA|SHA1)$"); +SslContextFactory.Server sslContextFactory = new SslContextFactory.Server(); +sslContextFactory.setExcludeCipherSuites("^.*_(MD5|SHA|SHA1)$"); ---- If, after making these changes, you still have issues using these ciphers they are likely being blocked at the JVM level. @@ -664,7 +663,7 @@ the other is `$JETTY/etc/truststore` which contains intermediary CA and root CA. [[configuring-sslcontextfactory]] ==== Configuring the Jetty SslContextFactory -The generated SSL certificates from above are held in the key store are configured in an instance of link:{JDURL}/org/eclipse/jetty/util/ssl/SslContextFactory.html[SslContextFactory] object. +The generated SSL certificates from above are held in the key store are configured in an instance of link:{JDURL}/org/eclipse/jetty/util/ssl/SslContextFactory.Server.html[SslContextFactory.Server] object. The `SslContextFactory` is responsible for: @@ -679,9 +678,9 @@ The `SslContextFactory` is responsible for: * https://en.wikipedia.org/wiki/Online_Certificate_Status_Protocol[OCSP] Support * Client Authentication Support -For Jetty Connectors, the configured `SslContextFactory` is injected into a specific ServerConnector `SslConnectionFactory`. +For Jetty Connectors, the configured `SslContextFactory.Server` is injected into a specific ServerConnector `SslConnectionFactory`. -For Jetty Clients, the various constructors support using a configured `SslContextFactory`. +For Jetty Clients, the various constructors support using a configured `SslContextFactory.Client`. While the `SslContextFactory` can operate without a keystore (this mode is most suitable for the various Jetty Clients) it is best practice to at least configure the keystore being used. @@ -729,7 +728,7 @@ Implementing Conscrypt for the link:{GITBROWSEURL}/jetty-alpn/jetty-alpn-conscry ... Security.addProvider(new OpenSSLProvider()); ... -SslContextFactory sslContextFactory = new SslContextFactory(); +SslContextFactory.Server sslContextFactory = new SslContextFactory.Server(); sslContextFactory.setKeyStorePath("path/to/keystore"); sslContextFactory.setKeyStorePassword("CleverKeyStorePassword"); sslContextFactory.setKeyManagerPassword("OBF:VerySecretManagerPassword"); @@ -739,9 +738,12 @@ sslContextFactory.setProvider("Conscrypt"); If you are using the Jetty Distribution, please see the section on enabling the link:#jetty-conscrypt-distribution[Conscrypt SSL module.] +If you are using Conscrypt with Java 8, you must exclude `TLSv1.3` protocol as it is now enabled per default with Conscrypt 2.0.0 but not supported by Java 8. + + ==== Configuring SNI -From Java 8, the JVM contains support for the http://en.wikipedia.org/wiki/Server_Name_Indication[Server Name Indicator (SNI)] extension, which allows a SSL connection handshake to indicate one or more DNS names that it applies to. +From Java 8, the JVM contains support for the http://en.wikipedia.org/wiki/Server_Name_Indication[Server Name Indicator (SNI)] extension, which allows an SSL connection handshake to indicate one or more DNS names that it applies to. To support this, the `SslContextFactory` is used. The `SslContextFactory` will look for multiple X509 certificates within the keystore, each of which may have multiple DNS names (including wildcards) associated with the http://en.wikipedia.org/wiki/SubjectAltName[Subject Alternate Name] extension. @@ -754,11 +756,14 @@ New cipher suites are always being developed to stay ahead of attacks. It's only a matter of time before the best of suites is exploited though, and making sure your server is up-to-date in this regard is paramount for any implementation. As an example, to avoid the BEAST attack it is necessary to configure a specific set of cipher suites. This can either be done via link:{JDURL}/org/eclipse/jetty/util/ssl/SslContextFactory.html#setIncludeCipherSuites(java.lang.String...)[SslContext.setIncludeCipherSuites(java.lang.String...)] or vialink:{JDURL}/org/eclipse/jetty/util/ssl/SslContextFactory.html#setExcludeCipherSuites(java.lang.String...)[SslContext.setExcludeCipherSuites(java.lang.String...)]. -____ -[NOTE] It's crucial that you use the _exact_ names of the cipher suites as used/known by the JDK. You can get them by obtaining an instance of SSLEngine and call `getSupportedCipherSuites()`. Tools like https://www.ssllabs.com/[ssllabs.com] might report slightly different names which will be ignored. + +____ +[IMPORTANT] +It is important to stay up-to-date with the latest supported cipher suites. +Be sure to consult Oracle's link:https://java.com/en/jre-jdk-cryptoroadmap.html[JRE and JDK Cryptographic Roadmap] frequently for recent and upcoming changes to supported ciphers. ____ ____ @@ -769,9 +774,14 @@ Just overwrite the two present JAR files in `/lib/security/`. ____ Both `setIncludeCipherSuites` and `setExcludeCipherSuites` can be fed by the exact cipher suite name used in the JDK or by using regular expressions. - If you have a need to adjust the Includes or Excludes, then this is best done with a custom XML that configures the `SslContextFactory` to suit your needs. +____ +[NOTE] +Jetty *does* allow users to enable weak/deprecated cipher suites (or even no cipher suites at all). +By default, if you have these suites enabled warning messages will appear in the server logs. +____ + To do this, first create a new `${jetty.base}/etc/tweak-ssl.xml` file (this can be any name, just avoid prefixing it with "jetty-"). [source, xml, subs="{sub-order}"] @@ -779,7 +789,7 @@ To do this, first create a new `${jetty.base}/etc/tweak-ssl.xml` file (this can - + @@ -814,13 +824,13 @@ $ ____ [NOTE] The default `SslContextFactory` implementation applies the latest SSL/TLS recommendations surrounding vulnerabilities in SSL/TLS. -Check the release notes (the `VERSION.txt` found in the root of the Jetty Distribution, or the http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.eclipse.jetty%22%20AND%20a%3A%22jetty-project%22[alternate (classified 'version') artifacts for the `jetty-project` component]on Maven Central) for updates. +Check the release notes (the `VERSION.txt` found in the root of the Jetty Distribution, or the http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.eclipse.jetty%22%20AND%20a%3A%22jetty-project%22[alternate (classified 'version') artifacts for the `jetty-project` component] on Maven Central) for updates. The Java JVM also applies exclusions at the JVM level and, as such, if you have a need to enable something that is generally accepted by the industry as being insecure or vulnerable you will likely have to enable it in *both* the Java JVM and your Jetty configuration. ____ ____ [TIP] -You can enable the `org.eclipse.jetty.util.ssl` named logger at DEBUG level to see what the list of selected Protocols and Cipher suites are at startup of Jetty. +You can enable the `org.eclipse.jetty.util.ssl` named logger at `DEBUG` level to see what the list of selected Protocols and Cipher suites are at startup of Jetty. ____ Additional Include / Exclude examples: @@ -973,7 +983,7 @@ Specifically, you will want to look for the `SslConnectionFactory` portion of th ... ---- -In the example above you can see both the enabled/disabled protocols and included/excluded ciper suites. +In the example above you can see both the enabled/disabled protocols and included/excluded cipher suites. For disabled or excluded protocols and ciphers, the reason they are disabled is given - either due to JVM restrictions, configuration or both. As a reminder, when configuring your includes/excludes, *excludes always win*. diff --git a/jetty-documentation/src/main/asciidoc/configuring/contexts/chapter.adoc b/jetty-documentation/src/main/asciidoc/configuring/contexts/chapter.adoc index 3c12094eb8a..4b7d276ce13 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/contexts/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/contexts/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/configuring/contexts/configuring-virtual-hosts.adoc b/jetty-documentation/src/main/asciidoc/configuring/contexts/configuring-virtual-hosts.adoc index b6f4456692e..451c589f046 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/contexts/configuring-virtual-hosts.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/contexts/configuring-virtual-hosts.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/configuring/contexts/custom-error-pages.adoc b/jetty-documentation/src/main/asciidoc/configuring/contexts/custom-error-pages.adoc index a41bb03fe73..4d5f492b930 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/contexts/custom-error-pages.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/contexts/custom-error-pages.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -77,7 +77,7 @@ Context files are normally located in `${jetty.base}/webapps/` (see `DeployerMan [source, xml, subs="{sub-order}"] ---- - + /test diff --git a/jetty-documentation/src/main/asciidoc/configuring/contexts/serving-webapp-from-particular-port.adoc b/jetty-documentation/src/main/asciidoc/configuring/contexts/serving-webapp-from-particular-port.adoc index c826102e639..2551e96fb04 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/contexts/serving-webapp-from-particular-port.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/contexts/serving-webapp-from-particular-port.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/configuring/contexts/setting-context-path.adoc b/jetty-documentation/src/main/asciidoc/configuring/contexts/setting-context-path.adoc index 0a51afeee41..74606e81494 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/contexts/setting-context-path.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/contexts/setting-context-path.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/configuring/contexts/setting-form-size.adoc b/jetty-documentation/src/main/asciidoc/configuring/contexts/setting-form-size.adoc index 0304e9d0d72..9ffc5f8ce3f 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/contexts/setting-form-size.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/contexts/setting-form-size.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -44,7 +44,7 @@ In either case the syntax of the XML file is the same: ==== For All Apps on a Server -Set an attribute on the Server instance for which you want to modify the maximum form content size: +Set an attribute in `jetty.xml` on the Server instance for which you want to modify the maximum form content size: [source, xml, subs="{sub-order}"] ---- @@ -56,7 +56,32 @@ Set an attribute on the Server instance for which you want to modify the maximum ---- +____ +[IMPORTANT] +It is important to remember that you should *not* modify the XML files in your `$JETTY_HOME`. +If you do for some reason feel you want to change the way an XML file operates, it is best to make a copy of it in your `$JETTY_BASE` in an `/etc` directory. +Jetty will always look first to the `$JETTY_BASE` for configuration. +____ + ==== For All Apps in the JVM Use the system property `org.eclipse.jetty.server.Request.maxFormContentSize`. -This can be set on the command line or in the `start.ini` or `start.d\server.ini` file. +This can be set on the command line or in the `$JETTY_BASE\start.ini` or any `$JETTY_BASE\start.d\*.ini` link:#startup-modules[module ini file.] +Using `$JETTY_BASE\start.d\server.ini` as an example: + +[source, console, subs="{sub-order}"] +---- +# --------------------------------------- +# Module: server +# Enables the core Jetty server on the classpath. +# --------------------------------------- +--module=server + +### Common HTTP configuration +## Scheme to use to build URIs for secure redirects +# jetty.httpConfig.secureScheme=https + +... + +-Dorg.eclipse.jetty.server.Request.maxFormContentSize=200000 +---- diff --git a/jetty-documentation/src/main/asciidoc/configuring/contexts/temporary-directories.adoc b/jetty-documentation/src/main/asciidoc/configuring/contexts/temporary-directories.adoc index f9851d47ce5..671109941f4 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/contexts/temporary-directories.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/contexts/temporary-directories.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/configuring/deploying/anatomy-of-a-webapp.adoc b/jetty-documentation/src/main/asciidoc/configuring/deploying/anatomy-of-a-webapp.adoc index 4c9e2ab7dd2..77b86f49d1b 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/deploying/anatomy-of-a-webapp.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/deploying/anatomy-of-a-webapp.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/configuring/deploying/automatic-webapp-deployment.adoc b/jetty-documentation/src/main/asciidoc/configuring/deploying/automatic-webapp-deployment.adoc index 0ea7ad79ca4..f639d619a98 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/deploying/automatic-webapp-deployment.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/deploying/automatic-webapp-deployment.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/configuring/deploying/chapter.adoc b/jetty-documentation/src/main/asciidoc/configuring/deploying/chapter.adoc index 2155226c762..7bdd70ab2d5 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/deploying/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/deploying/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/configuring/deploying/configuring-specific-webapp-deployment.adoc b/jetty-documentation/src/main/asciidoc/configuring/deploying/configuring-specific-webapp-deployment.adoc index a4491b2554b..66370f0a4bb 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/deploying/configuring-specific-webapp-deployment.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/deploying/configuring-specific-webapp-deployment.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/configuring/deploying/deployment-architecture.adoc b/jetty-documentation/src/main/asciidoc/configuring/deploying/deployment-architecture.adoc index 55000f4fe6c..b7a203c5ab1 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/deploying/deployment-architecture.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/deploying/deployment-architecture.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/configuring/deploying/deployment-processing-webapps.adoc b/jetty-documentation/src/main/asciidoc/configuring/deploying/deployment-processing-webapps.adoc index 9b43ef3a998..2f5d52f2a94 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/deploying/deployment-processing-webapps.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/deploying/deployment-processing-webapps.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/configuring/deploying/hot-deployment.adoc b/jetty-documentation/src/main/asciidoc/configuring/deploying/hot-deployment.adoc index 406a3a1b821..664e5f1f398 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/deploying/hot-deployment.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/deploying/hot-deployment.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/configuring/deploying/overlay-deployer.adoc b/jetty-documentation/src/main/asciidoc/configuring/deploying/overlay-deployer.adoc index 5f5fea6c485..739c7b3b0e1 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/deploying/overlay-deployer.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/deploying/overlay-deployer.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/configuring/deploying/quickstart-webapp.adoc b/jetty-documentation/src/main/asciidoc/configuring/deploying/quickstart-webapp.adoc index f01eeab6d58..cbbc71e40f3 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/deploying/quickstart-webapp.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/deploying/quickstart-webapp.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/configuring/deploying/static-content-deployment.adoc b/jetty-documentation/src/main/asciidoc/configuring/deploying/static-content-deployment.adoc index 275bae8f056..a2cfe410bb5 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/deploying/static-content-deployment.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/deploying/static-content-deployment.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/configuring/jsp/chapter.adoc b/jetty-documentation/src/main/asciidoc/configuring/jsp/chapter.adoc index 5ed19c2d1d6..c9476bf21bd 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/jsp/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/jsp/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/configuring/jsp/configuring-jsp.adoc b/jetty-documentation/src/main/asciidoc/configuring/jsp/configuring-jsp.adoc index 068e3404831..705a03ec1e8 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/jsp/configuring-jsp.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/jsp/configuring-jsp.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -171,7 +171,7 @@ The JSP engine has many configuration parameters. Some parameters affect only precompilation, and some affect runtime recompilation checking. Parameters also differ among the various versions of the JSP engine. This page lists the configuration parameters, their meanings, and their default settings. -Set all parameters on the `org.apache.jasper.JspServlet` instance defined in the link:#webdefault-xml[`webdefault.xml`] file. +Set all parameters on the `org.apache.jasper.servlet.JspServlet` instance defined in the link:#webdefault-xml[`webdefault.xml`] file. ____ [NOTE] diff --git a/jetty-documentation/src/main/asciidoc/configuring/part.adoc b/jetty-documentation/src/main/asciidoc/configuring/part.adoc index cc36301813b..620243d697e 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/part.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/part.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/configuring/security/authentication.adoc b/jetty-documentation/src/main/asciidoc/configuring/security/authentication.adoc index 5dbe28ebe21..3e7ab4917ef 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/security/authentication.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/security/authentication.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/configuring/security/chapter.adoc b/jetty-documentation/src/main/asciidoc/configuring/security/chapter.adoc index 6aa4fd54653..1c28d1535ce 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/security/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/security/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/configuring/security/configuring-form-size.adoc b/jetty-documentation/src/main/asciidoc/configuring/security/configuring-form-size.adoc index aabda82c15b..066aa482385 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/security/configuring-form-size.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/security/configuring-form-size.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/configuring/security/jaas-support.adoc b/jetty-documentation/src/main/asciidoc/configuring/security/jaas-support.adoc index be22d3b5298..37f8f7f95ca 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/security/jaas-support.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/security/jaas-support.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -52,13 +52,13 @@ Let's look at an example. ===== Step 1 -Configure a Jetty `org.eclipse.jetty.jaas.JAASLoginService` to match the `` in your `web.xml` file. For example, if the `web.xml` contains a realm called "xyz" like so: +Configure a Jetty `org.eclipse.jetty.jaas.JAASLoginService` to match the `` in your `web.xml` file. For example, if the `web.xml` contains a realm called "Test JAAS Realm" like so: [source, xml, subs="{sub-order}"] ---- FORM - xyz + Test JAAS Realm /login/login /login/error @@ -66,7 +66,7 @@ Configure a Jetty `org.eclipse.jetty.jaas.JAASLoginService` to match the ` ---- -Then you need to create a `JAASLoginService` with the matching name of "xyz": +then you need to create a `JAASLoginService` with the matching realm name of "Test JAAS Realm": [source, xml, subs="{sub-order}"] ---- @@ -76,9 +76,10 @@ Then you need to create a `JAASLoginService` with the matching name of "xyz": ---- +The `LoginModuleName` must match the name of your LoginModule as declared in your login module configuration file (see <>). ____ [CAUTION] -The name of the realm-name that you declare in `web.xml` must match exactly the name of your `JAASLoginService`. +The name of the realm-name that you declare in `web.xml` must match *exactly* the `Name` field of your `JAASLoginService`. ____ You can declare your `JAASLoginService` in a couple of different ways: @@ -135,7 +136,7 @@ xyz { ____ [CAUTION] -It is imperative that the application name on the first line is exactly the same as the `LoginModuleName` of your `JAASLoginService`. +It is imperative that the application name on the first line is *exactly* the same as the `LoginModuleName` of your `JAASLoginService`. ____ You may find it convenient to name this configuration file as `etc/login.conf` because, as we will see below, some of the wiring up for JAAS has been done for you. @@ -179,7 +180,6 @@ To allow the greatest degree of flexibility in using JAAS with web applications, Note that you don't ordinarily need to set these explicitly, as Jetty has defaults which will work in 99% of cases. However, should you need to, you can configure: -* a policy for role-based authorization (Default: `org.eclipse.jetty.jaas.StrictRoleCheckPolicy`) * a CallbackHandler (Default: `org.eclipse.jetty.jaas.callback.DefaultCallbackHandler`) * a list of classnames for the Principal implementation that equate to a user role (Default: `org.eclipse.jetty.jaas.JAASRole`) @@ -190,9 +190,6 @@ Here's an example of setting each of these (to their default values): Test JAAS Realm xyz - - - org.eclipse.jetty.jaas.callback.DefaultCallbackHandler @@ -204,16 +201,6 @@ Here's an example of setting each of these (to their default values): ---- -===== RoleCheckPolicy - -The `RoleCheckPolicy` must be an implementation of the `org.eclipse.jetty.jaas.RoleCheckPolicy` interface and its purpose is to help answer the question "is User X in Role Y" for role-based authorization requests. -The default implementation distributed with Jetty is the `org.eclipse.jetty.jaas.StrictRoleCheckPolicy`, which will assess a user as having a particular role if that role is at the top of the stack of roles that have been temporarily pushed onto the user. -If the user has no temporarily assigned roles, the role is amongst those configured for the user. - -Roles can be temporarily assigned to a user programmatically by using the `pushRole(String rolename)` method of the `org.eclipse.jetty.jaas.JAASUserPrincipal` class. - -For the majority of webapps, the default `StrictRoleCheckPolicy` will be quite adequate, however you may provide your own implementation and set it on your `JAASLoginService` instance. - ===== CallbackHandler A CallbackHandler is responsible for interfacing with the user to obtain usernames and credentials to be authenticated. diff --git a/jetty-documentation/src/main/asciidoc/configuring/security/jetty-home-and-jetty-base.adoc b/jetty-documentation/src/main/asciidoc/configuring/security/jetty-home-and-jetty-base.adoc index 2aeb1174b03..91cfee53a4d 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/security/jetty-home-and-jetty-base.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/security/jetty-home-and-jetty-base.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/configuring/security/secure-passwords.adoc b/jetty-documentation/src/main/asciidoc/configuring/security/secure-passwords.adoc index b44c0d7d0ac..8bbf9b85f90 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/security/secure-passwords.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/security/secure-passwords.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/configuring/security/serving-aliased-files.adoc b/jetty-documentation/src/main/asciidoc/configuring/security/serving-aliased-files.adoc index 85e0fe0c43c..290cad1e31d 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/security/serving-aliased-files.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/security/serving-aliased-files.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/configuring/security/setting-port80-access-for-non-root-user.adoc b/jetty-documentation/src/main/asciidoc/configuring/security/setting-port80-access-for-non-root-user.adoc index 9a17614cf04..6f64faf2748 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/security/setting-port80-access-for-non-root-user.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/security/setting-port80-access-for-non-root-user.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/configuring/security/spnego-support.adoc b/jetty-documentation/src/main/asciidoc/configuring/security/spnego-support.adoc index 47f565af6a4..6902e599093 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/security/spnego-support.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/security/spnego-support.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/ant/chapter.adoc b/jetty-documentation/src/main/asciidoc/development/ant/chapter.adoc index edc282ab98c..b006e7a5877 100644 --- a/jetty-documentation/src/main/asciidoc/development/ant/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/development/ant/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -21,4 +21,4 @@ This chapter explains how to use Jetty with Ant and the Jetty Ant tasks. -include::jetty-ant.adoc[] \ No newline at end of file +include::jetty-ant.adoc[] diff --git a/jetty-documentation/src/main/asciidoc/development/ant/jetty-ant.adoc b/jetty-documentation/src/main/asciidoc/development/ant/jetty-ant.adoc index 5d00fd04109..01b0b77df54 100644 --- a/jetty-documentation/src/main/asciidoc/development/ant/jetty-ant.adoc +++ b/jetty-documentation/src/main/asciidoc/development/ant/jetty-ant.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/clients/http/chapter.adoc b/jetty-documentation/src/main/asciidoc/development/clients/http/chapter.adoc index 0915e901061..1c53cdfcaf3 100644 --- a/jetty-documentation/src/main/asciidoc/development/clients/http/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/development/clients/http/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/clients/http/http-client-api.adoc b/jetty-documentation/src/main/asciidoc/development/clients/http/http-client-api.adoc index 882108cdd5c..8792a6ccdcf 100644 --- a/jetty-documentation/src/main/asciidoc/development/clients/http/http-client-api.adoc +++ b/jetty-documentation/src/main/asciidoc/development/clients/http/http-client-api.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/clients/http/http-client-authentication.adoc b/jetty-documentation/src/main/asciidoc/development/clients/http/http-client-authentication.adoc index fa954e06721..7f23e976c20 100644 --- a/jetty-documentation/src/main/asciidoc/development/clients/http/http-client-authentication.adoc +++ b/jetty-documentation/src/main/asciidoc/development/clients/http/http-client-authentication.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/clients/http/http-client-cookie.adoc b/jetty-documentation/src/main/asciidoc/development/clients/http/http-client-cookie.adoc index 3cfd92f5601..4e3e113ac46 100644 --- a/jetty-documentation/src/main/asciidoc/development/clients/http/http-client-cookie.adoc +++ b/jetty-documentation/src/main/asciidoc/development/clients/http/http-client-cookie.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/clients/http/http-client-intro.adoc b/jetty-documentation/src/main/asciidoc/development/clients/http/http-client-intro.adoc index 8ff722ff739..429f0444763 100644 --- a/jetty-documentation/src/main/asciidoc/development/clients/http/http-client-intro.adoc +++ b/jetty-documentation/src/main/asciidoc/development/clients/http/http-client-intro.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -75,13 +75,13 @@ There are several reasons for having multiple `HttpClient` instances including, When you create a `HttpClient` instance using the parameterless constructor, you will only be able to perform plain HTTP requests and you will not be able to perform HTTPS requests. -In order to perform HTTPS requests, you should create first a link:{JDURL}/org/eclipse/jetty/util/ssl/SslContextFactory.html[`SslContextFactory`], configure it, and pass it to the `HttpClient` constructor. +In order to perform HTTPS requests, you should create first a link:{JDURL}/org/eclipse/jetty/util/ssl/SslContextFactory.Client.html[`SslContextFactory.Client`], configure it, and pass it to the `HttpClient` constructor. When created with a `SslContextFactory`, the `HttpClient` will be able to perform both HTTP and HTTPS requests to any domain. [source, java, subs="{sub-order}"] ---- // Instantiate and configure the SslContextFactory -SslContextFactory sslContextFactory = new SslContextFactory(); +SslContextFactory.Client sslContextFactory = new SslContextFactory.Client(); // Instantiate HttpClient with the SslContextFactory HttpClient httpClient = new HttpClient(sslContextFactory); diff --git a/jetty-documentation/src/main/asciidoc/development/clients/http/http-client-proxy.adoc b/jetty-documentation/src/main/asciidoc/development/clients/http/http-client-proxy.adoc index 808a6d277c0..f5f0659510e 100644 --- a/jetty-documentation/src/main/asciidoc/development/clients/http/http-client-proxy.adoc +++ b/jetty-documentation/src/main/asciidoc/development/clients/http/http-client-proxy.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/clients/http/http-client-transport.adoc b/jetty-documentation/src/main/asciidoc/development/clients/http/http-client-transport.adoc index 62cea88312f..ae566236c33 100644 --- a/jetty-documentation/src/main/asciidoc/development/clients/http/http-client-transport.adoc +++ b/jetty-documentation/src/main/asciidoc/development/clients/http/http-client-transport.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/continuations/chapter.adoc b/jetty-documentation/src/main/asciidoc/development/continuations/chapter.adoc index 8eafe8a67d6..0dca58b6ce6 100644 --- a/jetty-documentation/src/main/asciidoc/development/continuations/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/development/continuations/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/continuations/continuations-intro.adoc b/jetty-documentation/src/main/asciidoc/development/continuations/continuations-intro.adoc index af982ac8617..277977bde6a 100644 --- a/jetty-documentation/src/main/asciidoc/development/continuations/continuations-intro.adoc +++ b/jetty-documentation/src/main/asciidoc/development/continuations/continuations-intro.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/continuations/continuations-patterns.adoc b/jetty-documentation/src/main/asciidoc/development/continuations/continuations-patterns.adoc index e0ebcaf1389..bc96488c566 100644 --- a/jetty-documentation/src/main/asciidoc/development/continuations/continuations-patterns.adoc +++ b/jetty-documentation/src/main/asciidoc/development/continuations/continuations-patterns.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/continuations/continuations-using.adoc b/jetty-documentation/src/main/asciidoc/development/continuations/continuations-using.adoc index 7e806c7ab0c..2e50c27185a 100644 --- a/jetty-documentation/src/main/asciidoc/development/continuations/continuations-using.adoc +++ b/jetty-documentation/src/main/asciidoc/development/continuations/continuations-using.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/embedding/chapter.adoc b/jetty-documentation/src/main/asciidoc/development/embedding/chapter.adoc index c316fa9b8d2..56350930eef 100644 --- a/jetty-documentation/src/main/asciidoc/development/embedding/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/development/embedding/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -21,4 +21,4 @@ include::jetty-helloworld.adoc[] include::embedding-jetty.adoc[] -include::embedded-examples.adoc[] \ No newline at end of file +include::embedded-examples.adoc[] diff --git a/jetty-documentation/src/main/asciidoc/development/embedding/embedded-examples.adoc b/jetty-documentation/src/main/asciidoc/development/embedding/embedded-examples.adoc index 42e6e6ab061..8a7507f5307 100644 --- a/jetty-documentation/src/main/asciidoc/development/embedding/embedded-examples.adoc +++ b/jetty-documentation/src/main/asciidoc/development/embedding/embedded-examples.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/embedding/embedding-jetty.adoc b/jetty-documentation/src/main/asciidoc/development/embedding/embedding-jetty.adoc index 3d973562ce8..8790ef996fa 100644 --- a/jetty-documentation/src/main/asciidoc/development/embedding/embedding-jetty.adoc +++ b/jetty-documentation/src/main/asciidoc/development/embedding/embedding-jetty.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/embedding/examples/embedded-file-server.adoc b/jetty-documentation/src/main/asciidoc/development/embedding/examples/embedded-file-server.adoc index bee9783e6ef..d4a6d5c2f2c 100644 --- a/jetty-documentation/src/main/asciidoc/development/embedding/examples/embedded-file-server.adoc +++ b/jetty-documentation/src/main/asciidoc/development/embedding/examples/embedded-file-server.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/embedding/examples/embedded-many-connectors.adoc b/jetty-documentation/src/main/asciidoc/development/embedding/examples/embedded-many-connectors.adoc index 7fdbd1b13d9..8ee42831a4c 100644 --- a/jetty-documentation/src/main/asciidoc/development/embedding/examples/embedded-many-connectors.adoc +++ b/jetty-documentation/src/main/asciidoc/development/embedding/examples/embedded-many-connectors.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/embedding/examples/embedded-minimal-servlet.adoc b/jetty-documentation/src/main/asciidoc/development/embedding/examples/embedded-minimal-servlet.adoc index a965701ac79..a799bf5c3e5 100644 --- a/jetty-documentation/src/main/asciidoc/development/embedding/examples/embedded-minimal-servlet.adoc +++ b/jetty-documentation/src/main/asciidoc/development/embedding/examples/embedded-minimal-servlet.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/embedding/examples/embedded-one-webapp.adoc b/jetty-documentation/src/main/asciidoc/development/embedding/examples/embedded-one-webapp.adoc index 3c0e6a6f90e..f81651079e0 100644 --- a/jetty-documentation/src/main/asciidoc/development/embedding/examples/embedded-one-webapp.adoc +++ b/jetty-documentation/src/main/asciidoc/development/embedding/examples/embedded-one-webapp.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/embedding/examples/embedded-secured-hello-handler.adoc b/jetty-documentation/src/main/asciidoc/development/embedding/examples/embedded-secured-hello-handler.adoc index be663c1b4e6..8171e5c5219 100644 --- a/jetty-documentation/src/main/asciidoc/development/embedding/examples/embedded-secured-hello-handler.adoc +++ b/jetty-documentation/src/main/asciidoc/development/embedding/examples/embedded-secured-hello-handler.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/embedding/examples/embedded-split-file-server.adoc b/jetty-documentation/src/main/asciidoc/development/embedding/examples/embedded-split-file-server.adoc index 615b45d09be..ee7a6e29009 100644 --- a/jetty-documentation/src/main/asciidoc/development/embedding/examples/embedded-split-file-server.adoc +++ b/jetty-documentation/src/main/asciidoc/development/embedding/examples/embedded-split-file-server.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/embedding/jetty-helloworld.adoc b/jetty-documentation/src/main/asciidoc/development/embedding/jetty-helloworld.adoc index 66f9983b52c..4acd12f6ac5 100644 --- a/jetty-documentation/src/main/asciidoc/development/embedding/jetty-helloworld.adoc +++ b/jetty-documentation/src/main/asciidoc/development/embedding/jetty-helloworld.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/frameworks/chapter.adoc b/jetty-documentation/src/main/asciidoc/development/frameworks/chapter.adoc index 7ed447e189e..3acc2011a22 100644 --- a/jetty-documentation/src/main/asciidoc/development/frameworks/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/development/frameworks/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -22,4 +22,4 @@ include::spring-usage.adoc[] include::osgi.adoc[] include::weld.adoc[] -include::metro.adoc[] \ No newline at end of file +include::metro.adoc[] diff --git a/jetty-documentation/src/main/asciidoc/development/frameworks/metro.adoc b/jetty-documentation/src/main/asciidoc/development/frameworks/metro.adoc index 8dcd06fedf4..e4fd98e0ce1 100644 --- a/jetty-documentation/src/main/asciidoc/development/frameworks/metro.adoc +++ b/jetty-documentation/src/main/asciidoc/development/frameworks/metro.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/frameworks/osgi.adoc b/jetty-documentation/src/main/asciidoc/development/frameworks/osgi.adoc index da23e5dc9e2..18d246be242 100644 --- a/jetty-documentation/src/main/asciidoc/development/frameworks/osgi.adoc +++ b/jetty-documentation/src/main/asciidoc/development/frameworks/osgi.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -55,11 +55,8 @@ You *must also install the Apache Aries SPI Fly bundles* as many parts of Jetty [cols=",,",options="header",] |======================================================================= |Jar |Bundle Symbolic Name |Location -|org.apache.aries.spifly:org.apache.aries.spifly.dynamic.bundle-1.0.1.jar |org.apache.aries.spifly.dynamic.bundle +|org.apache.aries.spifly:org.apache.aries.spifly.dynamic.bundle-1.2.jar |org.apache.aries.spifly.dynamic.bundle |https://repo1.maven.org/maven2/org/apache/aries/spifly/org.apache.aries.spifly.dynamic.bundle/[Maven central] -|org.apache.aries:org.apache.aries.util-1.0.1.jar |org.apache.aries.util -|https://repo1.maven.org/maven2/org/apache/aries/org.apache.aries.util/[Maven -central] |======================================================================= ____ @@ -835,13 +832,13 @@ In order to use them with Jetty in OSGi, you will need to deploy some extra jars |======================================================================= |Jar |Bundle Symbolic Name |Location |The link:#spifly[spifly jars] | | -|org.ow2.asm:asm-5.0.1.jar |org.objectweb.asm +|org.ow2.asm:asm-7.0.jar |org.objectweb.asm |https://repo1.maven.org/maven2/org/ow2/asm/asm[Maven central] -|org.ow2.asm:asm-commons-5.0.1.jar |org.objectweb.asm.commons +|org.ow2.asm:asm-commons-7.0.jar |org.objectweb.asm.commons |https://repo1.maven.org/maven2/org/ow2/asm/asm-commons[Maven central] -|org.ow2.asm:asm-tree-5.0.1.jar |org.objectweb.asm.tree +|org.ow2.asm:asm-tree-7.0.jar |org.objectweb.asm.tree |https://repo1.maven.org/maven2/org/ow2/asm/asm-tree[Maven central] |javax.annotation:javax.annotation-api-1.2.jar |javax.annotation-api @@ -1099,32 +1096,31 @@ You should see output similar to this on the console, using the `felix:lb` comma .... ID|State |Level|Name 0|Active | 0|System Bundle (4.4.1) - 1|Active | 1|ASM (5.0.1) - 2|Active | 1|ASM commons classes (5.0.1) - 3|Active | 1|ASM Tree class visitor (5.0.1) + 1|Active | 1|ASM (7.0) + 2|Active | 1|ASM commons classes (7.0) + 3|Active | 1|ASM Tree class visitor (7.0) 4|Active | 1|geronimo-jta_1.1_spec (1.1.1) 5|Active | 1|javax.annotation API (1.2.0) 6|Active | 1|javax.mail bundle from Glassfish (1.4.1.v201005082020) 7|Active | 1|Java Server Pages Standard Tag Library API Bundle (1.2.0.v201105211821) 8|Active | 1|JavaServer Pages (TM) TagLib Implementation (1.2.2) - 9|Active | 1|Jetty :: Servlet Annotations (9.2.4.SNAPSHOT) - 10|Active | 1|Jetty :: Deployers (9.2.4.SNAPSHOT) - 11|Active | 1|Jetty :: Http Utility (9.2.4.SNAPSHOT) - 12|Active | 1|Jetty :: IO Utility (9.2.4.SNAPSHOT) - 13|Active | 1|Jetty :: JNDI Naming (9.2.4.SNAPSHOT) - 14|Active | 1|Jetty :: OSGi :: Boot (9.2.4.SNAPSHOT) - 15|Resolved | 1|Jetty-OSGi-Jasper Integration (9.2.4.SNAPSHOT) - 16|Active | 1|Jetty Servlet API and Schemas for OSGi (3.1.0.SNAPSHOT) - 17|Active | 1|Jetty :: Plus (9.2.4.SNAPSHOT) - 18|Active | 1|Jetty :: Security (9.2.4.SNAPSHOT) - 19|Active | 1|Jetty :: Server Core (9.2.4.SNAPSHOT) - 20|Active | 1|Jetty :: Servlet Handling (9.2.4.SNAPSHOT) - 21|Active | 1|Jetty :: Utility Servlets and Filters (9.2.4.SNAPSHOT) - 22|Active | 1|Jetty :: Utilities (9.2.4.SNAPSHOT) - 23|Active | 1|Jetty :: Webapp Application Support (9.2.4.SNAPSHOT) - 24|Active | 1|Jetty :: XML utilities (9.2.4.SNAPSHOT) - 25|Active | 1|Apache Aries SPI Fly Dynamic Weaving Bundle (1.0.1) - 26|Active | 1|Apache Aries Util (1.0.0) + 9|Active | 1|Jetty :: Servlet Annotations (9.4.14) + 10|Active | 1|Jetty :: Deployers (9.4.14) + 11|Active | 1|Jetty :: Http Utility (9.4.14) + 12|Active | 1|Jetty :: IO Utility (9.4.14) + 13|Active | 1|Jetty :: JNDI Naming (9.4.14) + 14|Active | 1|Jetty :: OSGi :: Boot (9.4.14) + 15|Resolved | 1|Jetty-OSGi-Jasper Integration (9.4.14) + 16|Active | 1|Jetty Servlet API and Schemas for OSGi (3.1.0) + 17|Active | 1|Jetty :: Plus (9.4.14) + 18|Active | 1|Jetty :: Security (9.4.14) + 19|Active | 1|Jetty :: Server Core (9.4.14) + 20|Active | 1|Jetty :: Servlet Handling (9.4.14) + 21|Active | 1|Jetty :: Utility Servlets and Filters (9.4.14) + 22|Active | 1|Jetty :: Utilities (9.4.14) + 23|Active | 1|Jetty :: Webapp Application Support (9.4.14) + 24|Active | 1|Jetty :: XML utilities (9.4.14) + 25|Active | 1|Apache Aries SPI Fly Dynamic Weaving Bundle (1.2) 27|Active | 1|Apache Felix Bundle Repository (2.0.2) 28|Active | 1|Apache Felix Configuration Admin Service (1.8.0) 29|Active | 1|Apache Felix EventAdmin (1.3.2) @@ -1132,10 +1128,10 @@ You should see output similar to this on the console, using the `felix:lb` comma 31|Active | 1|Apache Felix Gogo Runtime (0.12.1) 32|Active | 1|Apache Felix Gogo Shell (0.10.0) 33|Active | 1|Apache Felix Log Service (1.0.1) - 34|Active | 1|Jetty :: Apache JSP (9.2.4.SNAPSHOT) + 34|Active | 1|Jetty :: Apache JSP (9.4.14) 35|Active | 1|Eclipse Compiler for Java(TM) (3.8.2.v20130121-145325) - 36|Active | 1|Mortbay EL API and Implementation (8.0.9) - 37|Active | 1|Mortbay Jasper (8.0.9) + 36|Active | 1|Mortbay EL API and Implementation (8.5.33.1) + 37|Active | 1|Mortbay Jasper (8.5.33.1) .... ===== Eclipse diff --git a/jetty-documentation/src/main/asciidoc/development/frameworks/spring-usage.adoc b/jetty-documentation/src/main/asciidoc/development/frameworks/spring-usage.adoc index c2e5c0c994b..2139690edf8 100644 --- a/jetty-documentation/src/main/asciidoc/development/frameworks/spring-usage.adoc +++ b/jetty-documentation/src/main/asciidoc/development/frameworks/spring-usage.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/frameworks/weld.adoc b/jetty-documentation/src/main/asciidoc/development/frameworks/weld.adoc index fa98f604664..7c42e138663 100644 --- a/jetty-documentation/src/main/asciidoc/development/frameworks/weld.adoc +++ b/jetty-documentation/src/main/asciidoc/development/frameworks/weld.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/handlers/chapter.adoc b/jetty-documentation/src/main/asciidoc/development/handlers/chapter.adoc index d47427effe7..c44a65977ff 100644 --- a/jetty-documentation/src/main/asciidoc/development/handlers/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/development/handlers/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,4 +19,4 @@ [[jetty-handlers]] == Handlers -include::writing-custom-handlers.adoc[] \ No newline at end of file +include::writing-custom-handlers.adoc[] diff --git a/jetty-documentation/src/main/asciidoc/development/handlers/writing-custom-handlers.adoc b/jetty-documentation/src/main/asciidoc/development/handlers/writing-custom-handlers.adoc index a8bfd46b9af..21730437c2b 100644 --- a/jetty-documentation/src/main/asciidoc/development/handlers/writing-custom-handlers.adoc +++ b/jetty-documentation/src/main/asciidoc/development/handlers/writing-custom-handlers.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/maven/chapter.adoc b/jetty-documentation/src/main/asciidoc/development/maven/chapter.adoc index 34b458ce2b4..42925cd1c5b 100644 --- a/jetty-documentation/src/main/asciidoc/development/maven/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/development/maven/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -24,4 +24,4 @@ This chapter explains how to use Jetty with Maven and the Jetty Maven plugin. include::jetty-maven-helloworld.adoc[] include::jetty-maven-plugin.adoc[] include::jetty-maven-scanning.adoc[] -include::jetty-jspc-maven-plugin.adoc[] \ No newline at end of file +include::jetty-jspc-maven-plugin.adoc[] diff --git a/jetty-documentation/src/main/asciidoc/development/maven/jetty-jspc-maven-plugin.adoc b/jetty-documentation/src/main/asciidoc/development/maven/jetty-jspc-maven-plugin.adoc index c387792349d..c715177cc18 100644 --- a/jetty-documentation/src/main/asciidoc/development/maven/jetty-jspc-maven-plugin.adoc +++ b/jetty-documentation/src/main/asciidoc/development/maven/jetty-jspc-maven-plugin.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/maven/jetty-maven-helloworld.adoc b/jetty-documentation/src/main/asciidoc/development/maven/jetty-maven-helloworld.adoc index c700cf1a3e2..90cbe9e14ed 100644 --- a/jetty-documentation/src/main/asciidoc/development/maven/jetty-maven-helloworld.adoc +++ b/jetty-documentation/src/main/asciidoc/development/maven/jetty-maven-helloworld.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/maven/jetty-maven-plugin.adoc b/jetty-documentation/src/main/asciidoc/development/maven/jetty-maven-plugin.adoc index 93e404d0258..fb090f72801 100644 --- a/jetty-documentation/src/main/asciidoc/development/maven/jetty-maven-plugin.adoc +++ b/jetty-documentation/src/main/asciidoc/development/maven/jetty-maven-plugin.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -624,6 +624,9 @@ Only relevant if `waitForChild` is `false`. forkWebXml:: Default is `target/fork-web.xml`. This is the name of the file into which jetty generates the effective web.xml for use by the child process. +javaPath:: +Default will be your `${java.home}/bin/java` +This the java executable used to start the child process The following `jetty:run` parameters are NOT applicable: @@ -715,6 +718,9 @@ maxChildCheckInterval:: Default value 100. This is the interval in milliseconds between checks to see if the child started correctly. Only applicable if `waitForChild` is `false`. +javaPath:: +Default will be your `${java.home}/bin/java` +This the java executable used to start the child process ____ [NOTE] diff --git a/jetty-documentation/src/main/asciidoc/development/maven/jetty-maven-scanning.adoc b/jetty-documentation/src/main/asciidoc/development/maven/jetty-maven-scanning.adoc index 27e068b24de..6d36dd9d497 100644 --- a/jetty-documentation/src/main/asciidoc/development/maven/jetty-maven-scanning.adoc +++ b/jetty-documentation/src/main/asciidoc/development/maven/jetty-maven-scanning.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/part.adoc b/jetty-documentation/src/main/asciidoc/development/part.adoc index c97a3bf6ff1..1ef5a9d996f 100644 --- a/jetty-documentation/src/main/asciidoc/development/part.adoc +++ b/jetty-documentation/src/main/asciidoc/development/part.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/websockets/intro/chapter.adoc b/jetty-documentation/src/main/asciidoc/development/websockets/intro/chapter.adoc index fab182278a7..f5783ef1c3b 100644 --- a/jetty-documentation/src/main/asciidoc/development/websockets/intro/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/development/websockets/intro/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,14 +19,11 @@ [[websocket-intro]] == WebSocket Introduction -WebSocket is a new protocol for bidirectional communications over HTTP. - -It is based on a low level framing protocol that delivers messages in either UTF-8 TEXT or BINARY format. - -A single message in WebSocket can be of any size (the underlying framing however does have a single frame limit of http://en.wikipedia.org/wiki/9223372036854775807[63-bits]) +WebSocket is a new protocol for bidirectional communications initiated via HTTP/1.1 upgrade and providing basic message framing, layered over TCP. +It is based on a low-level framing protocol that delivers messages in either UTF-8 TEXT or BINARY format. +A single message in WebSocket can be of any size (the underlying framing however does have a single frame limit of http://en.wikipedia.org/wiki/9223372036854775807[63-bits]). There can be an unlimited number of messages sent. - Messages are sent sequentially, the base protocol does not support interleaved messages. A WebSocket connection goes through some basic state changes: @@ -78,11 +75,9 @@ https://datatracker.ietf.org/doc/draft-ietf-hybi-websocket-perframe-compression/ Per Frame Compression Extension. + An early extension draft from the Google/Chromium team that would provide WebSocket frame compression. -+ perframe-compression using deflate algorithm is present on many versions of Chrome/Chromium. + Jetty's support for perframe-compression is based on the draft-04 spec. -+ This standard is being replaced with permessage-compression. https://datatracker.ietf.org/doc/draft-tyoshino-hybi-permessage-compression/[permessage-compression]:: @@ -108,12 +103,11 @@ Java WebSocket Server API:: === Enabling WebSocket -To enable websocket, you need to link:#enabling-modules[enable] the `websocket` link:#enabling-modules[module]. +To enable Websocket, you need to enable the `websocket` link:#enabling-modules[module]. -Once this module is enabled for your jetty base, it will apply to all webapps deployed to that base. -If you want to be more selective about which webapps use websocket, then you can: +Once this module is enabled for your Jetty base, it will apply to all webapps deployed to that base. If you want to be more selective about which webapps use Websocket, then you can: -Disable jsr-356 for a particular webapp::: +Disable JSR-356 for a particular webapp::: You can disable jsr-356 for a particular webapp by setting the link:#context_attributes[context attribute] `org.eclipse.jetty.websocket.jsr356` to `false`. This will mean that websockets are not available to your webapp, however deployment time scanning for websocket-related classes such as endpoints will still occur. This can be a significant impost if your webapp contains a lot of classes and/or jar files. diff --git a/jetty-documentation/src/main/asciidoc/development/websockets/java/chapter.adoc b/jetty-documentation/src/main/asciidoc/development/websockets/java/chapter.adoc index cb625b6a1d0..d9c99b3f54d 100644 --- a/jetty-documentation/src/main/asciidoc/development/websockets/java/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/development/websockets/java/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/websockets/java/java-websocket-client-api.adoc b/jetty-documentation/src/main/asciidoc/development/websockets/java/java-websocket-client-api.adoc index fa9dca17c21..169ca4eb8b1 100644 --- a/jetty-documentation/src/main/asciidoc/development/websockets/java/java-websocket-client-api.adoc +++ b/jetty-documentation/src/main/asciidoc/development/websockets/java/java-websocket-client-api.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/websockets/java/java-websocket-server-api.adoc b/jetty-documentation/src/main/asciidoc/development/websockets/java/java-websocket-server-api.adoc index 9ed83f02571..6890f3997d4 100644 --- a/jetty-documentation/src/main/asciidoc/development/websockets/java/java-websocket-server-api.adoc +++ b/jetty-documentation/src/main/asciidoc/development/websockets/java/java-websocket-server-api.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/websockets/jetty/chapter.adoc b/jetty-documentation/src/main/asciidoc/development/websockets/jetty/chapter.adoc index 56ce1cb9b37..177c3564d37 100644 --- a/jetty-documentation/src/main/asciidoc/development/websockets/jetty/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/development/websockets/jetty/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -29,4 +29,4 @@ include::jetty-websocket-api-annotations.adoc[] include::jetty-websocket-api-listener.adoc[] include::jetty-websocket-api-adapter.adoc[] include::jetty-websocket-server-api.adoc[] -include::jetty-websocket-client-api.adoc[] \ No newline at end of file +include::jetty-websocket-client-api.adoc[] diff --git a/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-adapter.adoc b/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-adapter.adoc index f845dc3e3a3..cfe096302e1 100644 --- a/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-adapter.adoc +++ b/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-adapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-annotations.adoc b/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-annotations.adoc index 55c161745bb..429e590bdd3 100644 --- a/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-annotations.adoc +++ b/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-annotations.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-events.adoc b/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-events.adoc index 319c7bf2d5c..0352059229b 100644 --- a/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-events.adoc +++ b/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-events.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-listener.adoc b/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-listener.adoc index 25bcb8f799a..292c23ca4c9 100644 --- a/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-listener.adoc +++ b/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-listener.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-send-message.adoc b/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-send-message.adoc index f9dcbae27fb..a8b6e11957f 100644 --- a/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-send-message.adoc +++ b/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-send-message.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-session.adoc b/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-session.adoc index 83b8227ec23..67c34790b40 100644 --- a/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-session.adoc +++ b/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api-session.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api.adoc b/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api.adoc index 63f5235a5ed..861d11a96dc 100644 --- a/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api.adoc +++ b/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-api.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-client-api.adoc b/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-client-api.adoc index 0f69d81cfef..13c7ddaa132 100644 --- a/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-client-api.adoc +++ b/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-client-api.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-server-api.adoc b/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-server-api.adoc index 99d582a8883..3b478f19ef3 100644 --- a/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-server-api.adoc +++ b/jetty-documentation/src/main/asciidoc/development/websockets/jetty/jetty-websocket-server-api.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/index.adoc b/jetty-documentation/src/main/asciidoc/index.adoc index 9595398c802..a1bbda81c88 100644 --- a/jetty-documentation/src/main/asciidoc/index.adoc +++ b/jetty-documentation/src/main/asciidoc/index.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/quick-start/configuring/chapter.adoc b/jetty-documentation/src/main/asciidoc/quick-start/configuring/chapter.adoc index 4650b2ee173..d38647dbef3 100644 --- a/jetty-documentation/src/main/asciidoc/quick-start/configuring/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/quick-start/configuring/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/quick-start/configuring/how-to-configure.adoc b/jetty-documentation/src/main/asciidoc/quick-start/configuring/how-to-configure.adoc index c63aa91959c..2ca4cf98321 100644 --- a/jetty-documentation/src/main/asciidoc/quick-start/configuring/how-to-configure.adoc +++ b/jetty-documentation/src/main/asciidoc/quick-start/configuring/how-to-configure.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/quick-start/configuring/what-to-configure.adoc b/jetty-documentation/src/main/asciidoc/quick-start/configuring/what-to-configure.adoc index 2eb0cb90038..ad125fb47c3 100644 --- a/jetty-documentation/src/main/asciidoc/quick-start/configuring/what-to-configure.adoc +++ b/jetty-documentation/src/main/asciidoc/quick-start/configuring/what-to-configure.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/quick-start/getting-started/chapter.adoc b/jetty-documentation/src/main/asciidoc/quick-start/getting-started/chapter.adoc index b5358ba24a1..bf2fbfbcaa7 100644 --- a/jetty-documentation/src/main/asciidoc/quick-start/getting-started/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/quick-start/getting-started/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/quick-start/getting-started/jetty-common-configuration.adoc b/jetty-documentation/src/main/asciidoc/quick-start/getting-started/jetty-common-configuration.adoc index 607d452694c..ce07076f907 100644 --- a/jetty-documentation/src/main/asciidoc/quick-start/getting-started/jetty-common-configuration.adoc +++ b/jetty-documentation/src/main/asciidoc/quick-start/getting-started/jetty-common-configuration.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/quick-start/getting-started/jetty-deploying.adoc b/jetty-documentation/src/main/asciidoc/quick-start/getting-started/jetty-deploying.adoc index 598954ef9c4..12cd942a998 100644 --- a/jetty-documentation/src/main/asciidoc/quick-start/getting-started/jetty-deploying.adoc +++ b/jetty-documentation/src/main/asciidoc/quick-start/getting-started/jetty-deploying.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/quick-start/getting-started/jetty-installing.adoc b/jetty-documentation/src/main/asciidoc/quick-start/getting-started/jetty-installing.adoc index 9ce7f41ffab..ecc102733b5 100644 --- a/jetty-documentation/src/main/asciidoc/quick-start/getting-started/jetty-installing.adoc +++ b/jetty-documentation/src/main/asciidoc/quick-start/getting-started/jetty-installing.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/quick-start/getting-started/jetty-running.adoc b/jetty-documentation/src/main/asciidoc/quick-start/getting-started/jetty-running.adoc index 4e497fe43fc..5230dc29edc 100644 --- a/jetty-documentation/src/main/asciidoc/quick-start/getting-started/jetty-running.adoc +++ b/jetty-documentation/src/main/asciidoc/quick-start/getting-started/jetty-running.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -38,6 +38,8 @@ $ java -jar start.jar You can point a browser at this server at link:http://localhost:8080[]. However, as there are no webapps deployed in the `$JETTY_HOME` directory, you will see a 404 error page served by Jetty. +To stop the server, press `CTRL` + `c` or `CTRL` + `z` in your terminal. + *Note* the `HomeBaseWarning` - it is *not* recommended to run Jetty from the `$JETTY_HOME` directory. Instead, see how to link:#creating-jetty-base[create a Jetty Base] below. diff --git a/jetty-documentation/src/main/asciidoc/quick-start/introduction/chapter.adoc b/jetty-documentation/src/main/asciidoc/quick-start/introduction/chapter.adoc index 542be3715c9..c69837a1a69 100644 --- a/jetty-documentation/src/main/asciidoc/quick-start/introduction/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/quick-start/introduction/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/quick-start/introduction/jetty-coordinates.adoc b/jetty-documentation/src/main/asciidoc/quick-start/introduction/jetty-coordinates.adoc index d64ca85d5bd..9385883e9e3 100644 --- a/jetty-documentation/src/main/asciidoc/quick-start/introduction/jetty-coordinates.adoc +++ b/jetty-documentation/src/main/asciidoc/quick-start/introduction/jetty-coordinates.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/quick-start/introduction/jetty-javaee.adoc b/jetty-documentation/src/main/asciidoc/quick-start/introduction/jetty-javaee.adoc index f37ec16cebf..6fa929d8f05 100644 --- a/jetty-documentation/src/main/asciidoc/quick-start/introduction/jetty-javaee.adoc +++ b/jetty-documentation/src/main/asciidoc/quick-start/introduction/jetty-javaee.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/quick-start/introduction/what-is-jetty.adoc b/jetty-documentation/src/main/asciidoc/quick-start/introduction/what-is-jetty.adoc index 55bd747a6f1..93c858f560a 100644 --- a/jetty-documentation/src/main/asciidoc/quick-start/introduction/what-is-jetty.adoc +++ b/jetty-documentation/src/main/asciidoc/quick-start/introduction/what-is-jetty.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/quick-start/introduction/what-version.adoc b/jetty-documentation/src/main/asciidoc/quick-start/introduction/what-version.adoc index 52902ec03c8..a9a35434445 100644 --- a/jetty-documentation/src/main/asciidoc/quick-start/introduction/what-version.adoc +++ b/jetty-documentation/src/main/asciidoc/quick-start/introduction/what-version.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -32,11 +32,14 @@ _____ .Jetty Versions [width="100%",cols="12%,9%,15%,6%,21%,10%,6%,21%",options="header",] |======================================================================= -|Version |Year |Home |JVM |Protocols |Servlet |JSP |Status +|Version |Year |Home |Min JVM |Protocols |Servlet |JSP |Status +|10 |2019- |Eclipse |11 ^(1)^ |HTTP/1.1 (RFC 7230), HTTP/2 (RFC 7540), WebSocket (RFC 6455, JSR 356), FastCGI |4.0.2 |2.3 |*UNSTABLE / Alpha* |9.4 |2016- |Eclipse |1.8 |HTTP/1.1 (RFC 7230), HTTP/2 (RFC 7540), WebSocket (RFC 6455, JSR 356), FastCGI |3.1 |2.3 |Stable -|9.3 |2015- |Eclipse |1.8 |HTTP/1.1 (RFC 7230), HTTP/2 (RFC 7540), WebSocket (RFC 6455, JSR 356), FastCGI |3.1 |2.3 |Stable -|9.2 |2014-2018 |Eclipse |1.7 |HTTP/1.1 RFC2616, javax.websocket, SPDY v3 |3.1 |2.3 |Deprecated / *End of Life January 2018* -|8 |2009-2014 |Eclipse/Codehaus |1.6 |HTTP/1.1 RFC2616, WebSocket RFC 6455, SPDY v3 |3.0 |2.2 |Deprecated / *End of Life November 2014* +|9.3 |2015- |Eclipse |1.8 ^(2)^ |HTTP/1.1 (RFC 7230), HTTP/2 (RFC 7540), WebSocket (RFC 6455, JSR 356), FastCGI |3.1 |2.3 |Stable +|9.2 |2014-2018 |Eclipse |1.7 ^(2)^ |HTTP/1.1 RFC2616, javax.websocket, SPDY v3 |3.1 |2.3 |Deprecated / *End of Life January 2018* +|9.1 |2013-2014 |Eclipse |1.7 ^(2)^ |HTTP/1.1 RFC2616 |3.1 |2.3 |Deprecated / *End of Life May 2014* +|9.0 |2013-2013 |Eclipse |1.7 ^(2)^ |HTTP/1.1 RFC2616 |3.1-beta |2.3 |Deprecated / *End of Life November 2013* +|8 |2009-2014 |Eclipse/Codehaus |1.6 ^(2)^ |HTTP/1.1 RFC2616, WebSocket RFC 6455, SPDY v3 |3.0 |2.2 |Deprecated / *End of Life November 2014* |7 |2008-2014 |Eclipse/Codehaus |1.5 |HTTP/1.1 RFC2616, WebSocket RFC 6455, SPDY v3 |2.5 |2.1 |Deprecated / *End of Life November 2014* |6 |2006-2010 |Codehaus |1.4-1.5 |HTTP/1.1 RFC2616 |2.5 |2.0 |Deprecated / *End of Life November 2010* |5 |2003-2009 |Sourceforge |1.2-1.5 |HTTP/1.1 RFC2616 |2.4 |2.0 |Antique @@ -45,3 +48,6 @@ _____ |2 |1998-2000 |Mortbay |1.1 |HTTP/1.0 RFC1945 |2.1 |1.0 |Legendary |1 |1995-1998 |Mortbay |1.0 |HTTP/1.0 RFC1945 |- |- |Mythical |======================================================================= + + 1. JPMS module support is optional + 2. JDK9 and newer is not supported if using MultiRelease JAR Files, or Bytecode / Annotation scanning. \ No newline at end of file diff --git a/jetty-documentation/src/main/asciidoc/quick-start/part.adoc b/jetty-documentation/src/main/asciidoc/quick-start/part.adoc index c577d4afafd..b445cbc3d64 100644 --- a/jetty-documentation/src/main/asciidoc/quick-start/part.adoc +++ b/jetty-documentation/src/main/asciidoc/quick-start/part.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/reference/architecture/1xx-responses.adoc b/jetty-documentation/src/main/asciidoc/reference/architecture/1xx-responses.adoc index 7b00a2194f0..a4aaf9c4974 100644 --- a/jetty-documentation/src/main/asciidoc/reference/architecture/1xx-responses.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/architecture/1xx-responses.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/reference/architecture/basic-architecture.adoc b/jetty-documentation/src/main/asciidoc/reference/architecture/basic-architecture.adoc index 5416bb089fb..0c5e8b173e2 100644 --- a/jetty-documentation/src/main/asciidoc/reference/architecture/basic-architecture.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/architecture/basic-architecture.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/reference/architecture/chapter.adoc b/jetty-documentation/src/main/asciidoc/reference/architecture/chapter.adoc index a0795fa490f..ace8703b3fb 100644 --- a/jetty-documentation/src/main/asciidoc/reference/architecture/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/architecture/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -24,4 +24,4 @@ General items related to the architecture of jetty and how it deals with certain include::basic-architecture.adoc[] include::jetty-classloading.adoc[] include::1xx-responses.adoc[] -include::server-side-architecture.adoc[] \ No newline at end of file +include::server-side-architecture.adoc[] diff --git a/jetty-documentation/src/main/asciidoc/reference/architecture/jetty-classloading.adoc b/jetty-documentation/src/main/asciidoc/reference/architecture/jetty-classloading.adoc index 071f15314c7..0f351429183 100644 --- a/jetty-documentation/src/main/asciidoc/reference/architecture/jetty-classloading.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/architecture/jetty-classloading.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -79,7 +79,11 @@ Below is an example of implementing this feature using Jetty IoC XML format: [[classloading-setting-system-classes]] ===== Setting System Classes -You can call the methods link:{JDURL}/org/eclipse/jetty/webapp/WebAppContext.html#setSystemClasses%28java.lang.String%5B%5D%29[org.eclipse.jetty.webapp.WebAppContext.setSystemClasses(String Array)] or link:{JDURL}/org/eclipse/jetty/webapp/WebAppContext.html#addSystemClass(java.lang.String)[org.eclipse.jetty.webapp.WebAppContext.addSystemClass(String)] to allow fine control over which classes are considered System classes. +You can call the methods +link:{JDURL}/org/eclipse/jetty/webapp/WebAppContext.html#setSystemClasses%28java.lang.String%5B%5D%29[WebAppContext.setSystemClasses(String[\])] +or +link:{JDURL}/org/eclipse/jetty/webapp/WebAppContext.html#getSystemClasspathPattern()[WebAppContext.getSystemClasspathPattern().add(String)] +to allow fine control over which classes are considered system classes. * A web application can see a System class. * A WEB-INF class cannot replace a System class. @@ -162,6 +166,10 @@ You can do so directly to the API via a context XML file such as the following: If none of the alternatives already described meet your needs, you can always provide a custom classloader for your webapp. We recommend, but do not require, that your custom loader subclasses link:{JDURL}/org/eclipse/jetty/webapp/WebAppClassLoader.html[WebAppClassLoader]. + +If you do not subclass WebAppClassLoader, we recommend that you implement the link:{JDURL}/org/eclipse/jetty/util/ClassVisibilityChecker.html[ClassVisibilityChecker] interface. +Without this interface, session persistence will be slower. + You configure the classloader for the webapp like so: [source, java, subs="{sub-order}"] diff --git a/jetty-documentation/src/main/asciidoc/reference/architecture/server-side-architecture.adoc b/jetty-documentation/src/main/asciidoc/reference/architecture/server-side-architecture.adoc index 9550b35fb1e..62df993188f 100644 --- a/jetty-documentation/src/main/asciidoc/reference/architecture/server-side-architecture.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/architecture/server-side-architecture.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/reference/contributing/bugs.adoc b/jetty-documentation/src/main/asciidoc/reference/contributing/bugs.adoc index 86e743f74d0..cfe3477bbc9 100644 --- a/jetty-documentation/src/main/asciidoc/reference/contributing/bugs.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/contributing/bugs.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/reference/contributing/chapter.adoc b/jetty-documentation/src/main/asciidoc/reference/contributing/chapter.adoc index 797d59b5411..fcf4ca49e92 100644 --- a/jetty-documentation/src/main/asciidoc/reference/contributing/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/contributing/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -30,4 +30,4 @@ include::bugs.adoc[] include::patches.adoc[] include::security.adoc[] include::releasing-jetty.adoc[] -include::release-testing.adoc[] \ No newline at end of file +include::release-testing.adoc[] diff --git a/jetty-documentation/src/main/asciidoc/reference/contributing/coding-standards.adoc b/jetty-documentation/src/main/asciidoc/reference/contributing/coding-standards.adoc index 59007e0b9bb..ae2c7271e31 100644 --- a/jetty-documentation/src/main/asciidoc/reference/contributing/coding-standards.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/contributing/coding-standards.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/reference/contributing/community.adoc b/jetty-documentation/src/main/asciidoc/reference/contributing/community.adoc index e73a038e53f..f6213ceb156 100644 --- a/jetty-documentation/src/main/asciidoc/reference/contributing/community.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/contributing/community.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/reference/contributing/documentation.adoc b/jetty-documentation/src/main/asciidoc/reference/contributing/documentation.adoc index 33f780e4550..bd295c93a44 100644 --- a/jetty-documentation/src/main/asciidoc/reference/contributing/documentation.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/contributing/documentation.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -193,7 +193,7 @@ license blocks:: .... // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/reference/contributing/patches.adoc b/jetty-documentation/src/main/asciidoc/reference/contributing/patches.adoc index b32cf4e78ae..cee213520bf 100644 --- a/jetty-documentation/src/main/asciidoc/reference/contributing/patches.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/contributing/patches.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/reference/contributing/release-testing.adoc b/jetty-documentation/src/main/asciidoc/reference/contributing/release-testing.adoc index 7b5b70acf9d..60516d75be1 100644 --- a/jetty-documentation/src/main/asciidoc/reference/contributing/release-testing.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/contributing/release-testing.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/reference/contributing/releasing-jetty.adoc b/jetty-documentation/src/main/asciidoc/reference/contributing/releasing-jetty.adoc index 495629798cb..bbdecffd8ce 100644 --- a/jetty-documentation/src/main/asciidoc/reference/contributing/releasing-jetty.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/contributing/releasing-jetty.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/reference/contributing/security.adoc b/jetty-documentation/src/main/asciidoc/reference/contributing/security.adoc index 6760f809eeb..87634a2e2cd 100644 --- a/jetty-documentation/src/main/asciidoc/reference/contributing/security.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/contributing/security.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -29,4 +29,4 @@ If the issue is related to Eclipse or its Jetty integration then we encourage yo If the issue is related to integrations with Jetty we are happy to work with you to identify the proper entity and either of the approaches above is fine. -We prefer that security issues are reported directly to Jetty developers as opposed through GitHub Issues since it has no facility to tag issues as _private_. \ No newline at end of file +We prefer that security issues are reported directly to Jetty developers as opposed through GitHub Issues since it has no facility to tag issues as _private_. diff --git a/jetty-documentation/src/main/asciidoc/reference/contributing/source-build.adoc b/jetty-documentation/src/main/asciidoc/reference/contributing/source-build.adoc index d9f9c22c480..dd3179a9f64 100644 --- a/jetty-documentation/src/main/asciidoc/reference/contributing/source-build.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/contributing/source-build.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/reference/debugging/chapter.adoc b/jetty-documentation/src/main/asciidoc/reference/debugging/chapter.adoc index a501c7ce0ab..2fde923a99a 100644 --- a/jetty-documentation/src/main/asciidoc/reference/debugging/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/debugging/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -27,4 +27,4 @@ If you would like to contribute to this section simply fork the repository and c include::enable-remote-debugging.adoc[] include::debugging-with-intellij.adoc[] -include::debugging-with-eclipse.adoc[] \ No newline at end of file +include::debugging-with-eclipse.adoc[] diff --git a/jetty-documentation/src/main/asciidoc/reference/debugging/debugging-with-eclipse.adoc b/jetty-documentation/src/main/asciidoc/reference/debugging/debugging-with-eclipse.adoc index 6ce95ae1df8..82f90aab1cf 100644 --- a/jetty-documentation/src/main/asciidoc/reference/debugging/debugging-with-eclipse.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/debugging/debugging-with-eclipse.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -56,4 +56,4 @@ file. If this file is on your classpath then Jetty will use it for configuring logging, we use this approach extensively throughout Jetty development and it makes life ever so much easier. You can see this in action in the xref:configuring-jetty-stderrlog[] section. -____ \ No newline at end of file +____ diff --git a/jetty-documentation/src/main/asciidoc/reference/debugging/debugging-with-intellij.adoc b/jetty-documentation/src/main/asciidoc/reference/debugging/debugging-with-intellij.adoc index b5519dc92d6..2872f8793a2 100644 --- a/jetty-documentation/src/main/asciidoc/reference/debugging/debugging-with-intellij.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/debugging/debugging-with-intellij.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -66,4 +66,4 @@ ____ You can easily configure logging through a `jetty-logging.properties` file. If this file is on your classpath then Jetty will use it for configuring logging, we use this approach extensively throughout Jetty development and it makes life ever so much easier. You can see this in action in the xref:configuring-jetty-stderrlog[] section. -____ \ No newline at end of file +____ diff --git a/jetty-documentation/src/main/asciidoc/reference/debugging/enable-remote-debugging.adoc b/jetty-documentation/src/main/asciidoc/reference/debugging/enable-remote-debugging.adoc index f153874f51a..9edcb39bf63 100644 --- a/jetty-documentation/src/main/asciidoc/reference/debugging/enable-remote-debugging.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/debugging/enable-remote-debugging.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/reference/faq/chapter.adoc b/jetty-documentation/src/main/asciidoc/reference/faq/chapter.adoc index 1fcdd2cdc54..fb7d8c6a8a6 100644 --- a/jetty-documentation/src/main/asciidoc/reference/faq/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/faq/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/reference/jetty-xml/chapter.adoc b/jetty-documentation/src/main/asciidoc/reference/jetty-xml/chapter.adoc index 156c820f515..81e05bea2a5 100644 --- a/jetty-documentation/src/main/asciidoc/reference/jetty-xml/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/jetty-xml/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-env-xml.adoc b/jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-env-xml.adoc index f9a042c624a..090d8d8a8ab 100644 --- a/jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-env-xml.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-env-xml.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -34,7 +34,7 @@ Jetty applies `jetty-env.xml` on a per-webapp basis, and configures an instance ---- - + .. @@ -57,7 +57,7 @@ Place the `jetty-env.xml` file in your web application's WEB-INF folder. ---- - + diff --git a/jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-web-xml-config.adoc b/jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-web-xml-config.adoc index 283e9ea8e3c..5fb4f5bbad7 100644 --- a/jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-web-xml-config.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-web-xml-config.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -33,7 +33,7 @@ For a more in-depth look at the syntax, see xref:jetty-xml-syntax[]. [source, xml, subs="{sub-order}"] ---- - + .. diff --git a/jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-xml-config.adoc b/jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-xml-config.adoc index 36f7041ee99..8540eb435c2 100644 --- a/jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-xml-config.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-xml-config.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -43,7 +43,7 @@ The selection of which configuration files to use is controlled by `start.jar` a ---- - + ... diff --git a/jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-xml-syntax.adoc b/jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-xml-syntax.adoc index b0b646bf7e1..a32c99a6818 100644 --- a/jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-xml-syntax.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-xml-syntax.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -34,7 +34,7 @@ The following XML configuration file creates some Java objects and sets some att [source, xml, subs="{sub-order}"] ---- - + demo @@ -89,13 +89,13 @@ The first two lines of an XML must reference the DTD to be used to validate the [source, xml, subs="{sub-order}"] ---- - + ... ---- Typcically a good XML editor will fetch the DTD from the URL and use it to give syntax highlighting and validation while a configuration file is being edited. Some editors also allows DTD files to be locally cached. -The URL may point to configure.dtd if you want the latest current version, or to a specific version like configure_9_0.dtd if you want a particular validation feature set. +The URL may point to configure.dtd if you want the latest current version, or to a specific version like configure_9_3.dtd if you want a particular validation feature set. Files that conform to the configure.dtd format are processed in Jetty by the `XmlConfiguration` class which may also validate the XML (using a version of the DTD from the classes jar file), but is by default run in a forgiving mode that tries to work around validation failures. diff --git a/jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-xml-usage.adoc b/jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-xml-usage.adoc index 1bbaaf0eec9..93e0947c96b 100644 --- a/jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-xml-usage.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-xml-usage.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/reference/jetty-xml/override-web-xml.adoc b/jetty-documentation/src/main/asciidoc/reference/jetty-xml/override-web-xml.adoc index f4909a7b8c4..e77435c6ad3 100644 --- a/jetty-documentation/src/main/asciidoc/reference/jetty-xml/override-web-xml.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/jetty-xml/override-web-xml.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/reference/jetty-xml/webdefault-xml.adoc b/jetty-documentation/src/main/asciidoc/reference/jetty-xml/webdefault-xml.adoc index 59ed488bae3..f2f83c7e8e4 100644 --- a/jetty-documentation/src/main/asciidoc/reference/jetty-xml/webdefault-xml.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/jetty-xml/webdefault-xml.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/reference/part.adoc b/jetty-documentation/src/main/asciidoc/reference/part.adoc index 7d3d8e4331e..29b9b87567d 100644 --- a/jetty-documentation/src/main/asciidoc/reference/part.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/part.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/reference/platforms/chapter.adoc b/jetty-documentation/src/main/asciidoc/reference/platforms/chapter.adoc index e36e6ac5662..2e72902f7f8 100644 --- a/jetty-documentation/src/main/asciidoc/reference/platforms/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/platforms/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/reference/platforms/cloudfoundry.adoc b/jetty-documentation/src/main/asciidoc/reference/platforms/cloudfoundry.adoc index 224da63a01a..cb6f02928f8 100644 --- a/jetty-documentation/src/main/asciidoc/reference/platforms/cloudfoundry.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/platforms/cloudfoundry.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/reference/platforms/elastic-beanstalk.adoc b/jetty-documentation/src/main/asciidoc/reference/platforms/elastic-beanstalk.adoc index fed2d082f51..ed9031146ef 100644 --- a/jetty-documentation/src/main/asciidoc/reference/platforms/elastic-beanstalk.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/platforms/elastic-beanstalk.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -85,4 +85,4 @@ Bluepill is used to manage the start and stop process of the app server. This seems to be a problematic bit of software with a colored history and the version in use at the time of this writing is old. When starting and stopping (or restarting) the appserver you may see error messages show up that the Server timed out getting a response or things like that. These are red herrings and my experience is that jetty has started and stopped just fine, the pid file required shows up in a very timely fashion (under `/var/run/jetty.pid`) so do check that the app server has started, but please be aware there is a strangeness here that hasn't been sorted out yet. -____ \ No newline at end of file +____ diff --git a/jetty-documentation/src/main/asciidoc/reference/platforms/fedora.adoc b/jetty-documentation/src/main/asciidoc/reference/platforms/fedora.adoc index f307b1f8127..a0385fd9221 100644 --- a/jetty-documentation/src/main/asciidoc/reference/platforms/fedora.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/platforms/fedora.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/reference/platforms/jelastic.adoc b/jetty-documentation/src/main/asciidoc/reference/platforms/jelastic.adoc index 52f7a5e245e..b02da5f090a 100644 --- a/jetty-documentation/src/main/asciidoc/reference/platforms/jelastic.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/platforms/jelastic.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/reference/platforms/ubuntu.adoc b/jetty-documentation/src/main/asciidoc/reference/platforms/ubuntu.adoc index 42d04b03ed2..abbe0937599 100644 --- a/jetty-documentation/src/main/asciidoc/reference/platforms/ubuntu.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/platforms/ubuntu.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/reference/troubleshooting/chapter.adoc b/jetty-documentation/src/main/asciidoc/reference/troubleshooting/chapter.adoc index bf865bbabd2..62f78a632d2 100644 --- a/jetty-documentation/src/main/asciidoc/reference/troubleshooting/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/troubleshooting/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/reference/troubleshooting/preventing-memory-leaks.adoc b/jetty-documentation/src/main/asciidoc/reference/troubleshooting/preventing-memory-leaks.adoc index 5c4d643d81d..c9169ba4840 100644 --- a/jetty-documentation/src/main/asciidoc/reference/troubleshooting/preventing-memory-leaks.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/troubleshooting/preventing-memory-leaks.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/reference/troubleshooting/security-reports.adoc b/jetty-documentation/src/main/asciidoc/reference/troubleshooting/security-reports.adoc index e4f9bc9c812..598ee199f19 100644 --- a/jetty-documentation/src/main/asciidoc/reference/troubleshooting/security-reports.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/troubleshooting/security-reports.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -28,6 +28,18 @@ If you would like to report a security issue please follow these link:#security- |======================================================================= |yyyy/mm/dd |ID |Exploitable |Severity |Affects |Fixed Version |Comment +|2019/08/13 |CVE-2019-9515 |Med |Med |< = 9.4.20 |9.4.21 +|https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-9515[Some HTTP/2 implementations are vulnerable to a settings flood, potentially leading to a denial of service when an attacker sent a stream of SETTINGS frames to the peer.] + +|2019/04/11 |CVE-2019-10247 |Med |Med |< = 9.4.16 |9.2.28, 9.3.27, 9.4.17 +|https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-10247[If no webapp was mounted to the root namespace and a 404 was encountered, an HTML page would be generated displaying the fully qualified base resource location for each context.] + +|2019/04/11 |CVE-2019-10246 |High |High |< = 9.4.16 |9.2.28, 9.3.27, 9.4.17 +|https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-10246[Use of `DefaultServlet` or `ResourceHandler` with indexing was vulnerable to XSS behaviors to expose the directory listing on Windows operating systems.] + +|2019/04/11 |CVE-2019-10241 |High |High |< = 9.4.15 |9.2.27, 9.3.26, 9.4.16 +|https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-10241[Use of `DefaultServlet` or `ResourceHandler` with indexing was vulnerable to XSS behaviors to expose the directory listing.] + |2018/06/25 |CVE-2018-12538 |High |High |>= 9.4.0, < = 9.4.8 |9.4.9 |https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-12538[`HttpSessions` present specifically in the FileSystem’s storage could be hijacked/accessed by an unauthorized user.] diff --git a/jetty-documentation/src/main/asciidoc/reference/troubleshooting/slow-deployment.adoc b/jetty-documentation/src/main/asciidoc/reference/troubleshooting/slow-deployment.adoc index 11e935d422a..7f230c33c2b 100644 --- a/jetty-documentation/src/main/asciidoc/reference/troubleshooting/slow-deployment.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/troubleshooting/slow-deployment.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/reference/troubleshooting/troubleshooting-locked-files.adoc b/jetty-documentation/src/main/asciidoc/reference/troubleshooting/troubleshooting-locked-files.adoc index 14b8fadbcb1..a1adf7988c4 100644 --- a/jetty-documentation/src/main/asciidoc/reference/troubleshooting/troubleshooting-locked-files.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/troubleshooting/troubleshooting-locked-files.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -26,86 +26,58 @@ Effectively this means that you have to stop Jetty to update a file. ==== Remedy -Jetty provides a configuration switch in the `webdefault.xml` file for the DefaultServlet that enables or disables the use of memory-mapped files. +Jetty provides a configuration switch for the `DefaultServlet` that enables or disables the use of memory-mapped files. If you are running on Windows and are having file-locking problems, you should set this switch to disable memory-mapped file buffers. +Use one of the following options to configure the switch. -The default `webdefault.xml` file is found in the jetty distribution under the `etc/` directory or in the `jetty-webapp-${VERSION}.jar` artifact at `org/eclipse/jetty/webapp/webdefault.xml`. -Edit the file in the distribution or extract it to a convenient disk location and edit it to change `useFileMappedBuffer` to false. -The easiest option is to simply edit the default file contained in the jetty distribution itself. +===== Using override-web.xml + +An <> file can be placed in your webapp's `WEB-INF` directory to change the default setting of the `DefaultServlet` for memory-mapped file buffers. +Create an `override-web.xml` file with appropriate headers for your version of the servlet specification, and place the following inside the `` element: [source, xml, subs="{sub-order}"] ---- - - useFileMappedBuffer - true - - - ----- - -Make sure to apply your custom `webdefault.xml` file to all of your webapps. -You can do that by changing the configuration of the Deployment Manager in `etc/jetty-deploy.xml`. - -[source, xml, subs="{sub-order}"] ----- - - - - . - . - - /etc/webdefault.xml - 1 - true - . - . - - - - - ----- - -Alternatively, if you have individually configured your webapps with context xml files, you need to call the `WebAppContext.setDefaultsDescriptor(String path)` method: - -[source, xml, subs="{sub-order}"] ----- - - / - ./webapps/fredapp - /home/fred/jetty/mywebdefaults.xml - . - . - - - ----- - -Instead, you could redefine the DefaultServlet in your web.xml file, making sure to set useFileMappedBuffer to false: - -[source, xml, subs="{sub-order}"] ----- - - ... - Default - org.eclipse.jetty.servlet.DefaultServlet - - useFileMappedBuffer - false - - 0 - - ... - - - + default + + useFileMappedBuffer + false + + ---- +===== Using a Context XML File + +You can create or update a context xml file that configures your webapp to apply the setting to disable memory-mapped file buffers. +Add the following to your context xml file: + +[source, xml, subs="{sub-order}"] +---- + + org.eclipse.jetty.servlet.Default.useFileMappedBuffer + false + +---- + + +===== Using the Jetty Maven Plugin + +If you don't want to use either of the other two solutions, you can configure the plugin directly to disable memory-mapped file buffers. +Add the following to the plugin's configuration under the `` element: + +[source, xml, subs="{sub-order}"] +---- + <_initParams> + false + +---- + + + ==== Alternate Remedy You can force a `WebAppContext` to always copy a web app directory on deployment. -The base directory of your web app (ie the root directory where your static content exists) will be copied to the link:#ref-temporary-directories[temp directory]. +The base directory of your web app (i.e. the root directory where your static content exists) will be copied to the link:#ref-temporary-directories[temp directory]. Configure this in an xml file like so: [source, xml, subs="{sub-order}"] @@ -117,10 +89,9 @@ Configure this in an xml file like so: . . - ---- ____ [NOTE] Be careful with this option when using an explicitly setlink:#ref-temp-directories[temp directory] name - as the name of the temp directory will not unique across redeployments, copying the static content into the same directory name each time may not avoid the locking problem. -____ \ No newline at end of file +____ diff --git a/jetty-documentation/src/main/asciidoc/reference/troubleshooting/troubleshooting-zip-exceptions.adoc b/jetty-documentation/src/main/asciidoc/reference/troubleshooting/troubleshooting-zip-exceptions.adoc index 925ada439fe..8e6acf07062 100644 --- a/jetty-documentation/src/main/asciidoc/reference/troubleshooting/troubleshooting-zip-exceptions.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/troubleshooting/troubleshooting-zip-exceptions.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/reference/troubleshooting/watchservice.adoc b/jetty-documentation/src/main/asciidoc/reference/troubleshooting/watchservice.adoc index 45720a81ad0..369c361ab79 100644 --- a/jetty-documentation/src/main/asciidoc/reference/troubleshooting/watchservice.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/troubleshooting/watchservice.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/reference/upgrading/chapter.adoc b/jetty-documentation/src/main/asciidoc/reference/upgrading/chapter.adoc index 99ece4508ec..fa4eb328814 100644 --- a/jetty-documentation/src/main/asciidoc/reference/upgrading/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/upgrading/chapter.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/reference/upgrading/sample.adoc b/jetty-documentation/src/main/asciidoc/reference/upgrading/sample.adoc index 247897b7ea0..d11b705f235 100644 --- a/jetty-documentation/src/main/asciidoc/reference/upgrading/sample.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/upgrading/sample.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-documentation/src/main/asciidoc/reference/upgrading/upgrading-9.3-to-9.4.adoc b/jetty-documentation/src/main/asciidoc/reference/upgrading/upgrading-9.3-to-9.4.adoc index 9a02b58bcb6..b06571a38f8 100644 --- a/jetty-documentation/src/main/asciidoc/reference/upgrading/upgrading-9.3-to-9.4.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/upgrading/upgrading-9.3-to-9.4.adoc @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ======================================================================== // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -254,4 +254,11 @@ Enable the `session-store-gcloud` and `session-store-cache` modules. *Compatibility* -Sessions stored into Memcached by earlier versions of jetty are incompatible with Jetty 9.4. Previous versions of jetty stored `org.eclipse.jetty.gcloud.memcached.session.SerializableSessionData` whereas Jetty 9.4 stores `org.eclipse.jetty.server.session.SessionData`. +Sessions stored into Memcached by earlier versions of jetty are incompatible with Jetty 9.4. +Previous versions of jetty stored `org.eclipse.jetty.gcloud.memcached.session.SerializableSessionData` whereas Jetty 9.4 stores `org.eclipse.jetty.server.session.SessionData`. + +==== ServletContainerInitializers + +As of Jetty-9.4.4, unless the `web.xml` is version 3.0 or greater, only `ServletContainerInitializers` that are on the container classpath will be discovered. +Users wishing to use `ServletContainerInitializers` from within the webapp with older versions of `web.xml` must either upgrade their `web.xml` version, or call `WebAppContext.setConfigurationDiscovered(true)` either programmatically or in xml. +Upgrading the `web.xml` version is preferable. diff --git a/jetty-fcgi/fcgi-client/pom.xml b/jetty-fcgi/fcgi-client/pom.xml index 3fef8abe2ed..4ca0188a503 100644 --- a/jetty-fcgi/fcgi-client/pom.xml +++ b/jetty-fcgi/fcgi-client/pom.xml @@ -1,40 +1,40 @@ - - org.eclipse.jetty.fcgi - fcgi-parent - 9.4.13-SNAPSHOT - + + org.eclipse.jetty.fcgi + fcgi-parent + 9.4.21-SNAPSHOT + - 4.0.0 - fcgi-client - Jetty :: FastCGI :: Client + 4.0.0 + fcgi-client + Jetty :: FastCGI :: Client - - ${project.groupId}.client - + + ${project.groupId}.client + - - - org.eclipse.jetty - jetty-util - ${project.version} - - - org.eclipse.jetty - jetty-io - ${project.version} - - - org.eclipse.jetty - jetty-http - ${project.version} - - - org.eclipse.jetty - jetty-client - ${project.version} - - + + + org.eclipse.jetty + jetty-util + ${project.version} + + + org.eclipse.jetty + jetty-io + ${project.version} + + + org.eclipse.jetty + jetty-http + ${project.version} + + + org.eclipse.jetty + jetty-client + ${project.version} + + diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/FCGI.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/FCGI.java index ff52c443fa6..b2fbe6b96a6 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/FCGI.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/FCGI.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -45,7 +45,7 @@ public class FCGI public final int code; - private Role(int code) + Role(int code) { this.code = code; } @@ -95,7 +95,7 @@ public class FCGI public final int code; - private FrameType(int code) + FrameType(int code) { this.code = code; } diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpChannelOverFCGI.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpChannelOverFCGI.java index 520375ab16f..d2d3370dead 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpChannelOverFCGI.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpChannelOverFCGI.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -113,7 +113,7 @@ public class HttpChannelOverFCGI extends HttpChannel protected boolean responseHeaders() { - idle.notIdle(); + idle.notIdle(); HttpExchange exchange = getHttpExchange(); return exchange != null && receiver.responseHeaders(exchange); } @@ -166,7 +166,7 @@ public class HttpChannelOverFCGI extends HttpChannel { super(connection.getHttpDestination().getHttpClient().getScheduler()); this.connection = connection; - setIdleTimeout(idleTimeout); + setIdleTimeout(idleTimeout >= 0 ? idleTimeout : connection.getEndPoint().getIdleTimeout()); } @Override diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpClientTransportOverFCGI.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpClientTransportOverFCGI.java index 90aafa519eb..143ff6bc48e 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpClientTransportOverFCGI.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpClientTransportOverFCGI.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -45,7 +45,7 @@ public class HttpClientTransportOverFCGI extends AbstractConnectorHttpClientTran public HttpClientTransportOverFCGI(String scriptRoot) { - this( Math.max( 1, ProcessorUtils.availableProcessors() / 2), false, scriptRoot); + this(Math.max(1, ProcessorUtils.availableProcessors() / 2), false, scriptRoot); } public HttpClientTransportOverFCGI(int selectors, boolean multiplexed, String scriptRoot) @@ -57,9 +57,9 @@ public class HttpClientTransportOverFCGI extends AbstractConnectorHttpClientTran { HttpClient httpClient = getHttpClient(); int maxConnections = httpClient.getMaxConnectionsPerDestination(); - return isMultiplexed() ? - new MultiplexConnectionPool(destination, maxConnections, destination, httpClient.getMaxRequestsQueuedPerDestination()) : - new DuplexConnectionPool(destination, maxConnections, destination); + return isMultiplexed() + ? new MultiplexConnectionPool(destination, maxConnections, destination, httpClient.getMaxRequestsQueuedPerDestination()) + : new DuplexConnectionPool(destination, maxConnections, destination); }); } @@ -79,7 +79,7 @@ public class HttpClientTransportOverFCGI extends AbstractConnectorHttpClientTran public HttpDestination newHttpDestination(Origin origin) { return isMultiplexed() ? new MultiplexHttpDestinationOverFCGI(getHttpClient(), origin) - : new HttpDestinationOverFCGI(getHttpClient(), origin); + : new HttpDestinationOverFCGI(getHttpClient(), origin); } @Override diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpConnectionOverFCGI.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpConnectionOverFCGI.java index d72762f2d63..faa571f295d 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpConnectionOverFCGI.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpConnectionOverFCGI.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -129,7 +129,7 @@ public class HttpConnectionOverFCGI extends AbstractConnection implements Connec { @SuppressWarnings("ReferenceEquality") boolean isCurrentBuffer = (this.buffer == buffer); - assert(isCurrentBuffer); + assert (isCurrentBuffer); HttpClient client = destination.getHttpClient(); ByteBufferPool bufferPool = client.getByteBufferPool(); bufferPool.release(buffer); @@ -275,9 +275,9 @@ public class HttpConnectionOverFCGI extends AbstractConnection implements Connec channel.destroy(); } activeChannels.clear(); - + HttpChannel channel = idleChannels.poll(); - while (channel!=null) + while (channel != null) { channel.destroy(); channel = idleChannels.poll(); @@ -292,7 +292,7 @@ public class HttpConnectionOverFCGI extends AbstractConnection implements Connec result |= channel.responseFailure(failure); channel.destroy(); } - + if (result) close(failure); } @@ -339,7 +339,7 @@ public class HttpConnectionOverFCGI extends AbstractConnection implements Connec getEndPoint().getLocalAddress(), getEndPoint().getRemoteAddress()); } - + private class Delegate extends HttpConnection { private Delegate(HttpDestination destination) diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpDestinationOverFCGI.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpDestinationOverFCGI.java index 9295139fc96..9a296c1bf13 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpDestinationOverFCGI.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpDestinationOverFCGI.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpReceiverOverFCGI.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpReceiverOverFCGI.java index cf7fb56cb39..4f99ea24bb1 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpReceiverOverFCGI.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpReceiverOverFCGI.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpSenderOverFCGI.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpSenderOverFCGI.java index 02ca68dfd0f..e3e65d4e431 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpSenderOverFCGI.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpSenderOverFCGI.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -35,6 +35,7 @@ import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Jetty; +import org.eclipse.jetty.util.StringUtil; public class HttpSenderOverFCGI extends HttpSender { @@ -59,7 +60,9 @@ public class HttpSenderOverFCGI extends HttpSender // Copy the request headers to be able to convert them properly HttpFields headers = new HttpFields(); for (HttpField field : request.getHeaders()) + { headers.put(field); + } HttpFields fcgiHeaders = new HttpFields(); // FastCGI headers based on the URI @@ -88,7 +91,7 @@ public class HttpSenderOverFCGI extends HttpSender for (HttpField field : headers) { String name = field.getName(); - String fcgiName = "HTTP_" + name.replaceAll("-", "_").toUpperCase(Locale.ENGLISH); + String fcgiName = "HTTP_" + StringUtil.replace(name, '-', '_').toUpperCase(Locale.ENGLISH); fcgiHeaders.add(fcgiName, field.getValue()); } @@ -99,7 +102,7 @@ public class HttpSenderOverFCGI extends HttpSender int id = getHttpChannel().getRequest(); boolean hasContent = content.hasContent(); Generator.Result headersResult = generator.generateRequestHeaders(id, fcgiHeaders, - hasContent ? callback : Callback.NOOP); + hasContent ? callback : Callback.NOOP); if (hasContent) { getHttpChannel().flush(headersResult); @@ -125,10 +128,4 @@ public class HttpSenderOverFCGI extends HttpSender getHttpChannel().flush(result); } } - - @Override - protected void sendTrailers(HttpExchange exchange, Callback callback) - { - callback.succeeded(); - } } diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/MultiplexHttpDestinationOverFCGI.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/MultiplexHttpDestinationOverFCGI.java index dddb30cd9d7..dcf7d2fc605 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/MultiplexHttpDestinationOverFCGI.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/MultiplexHttpDestinationOverFCGI.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/ClientGenerator.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/ClientGenerator.java index 96f2cd5626a..4d79147d467 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/ClientGenerator.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/ClientGenerator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -132,7 +132,6 @@ public class ClientGenerator extends Generator BufferUtil.flipToFlush(buffer, 0); } - ByteBuffer lastParamsBuffer = byteBufferPool.acquire(8, false); BufferUtil.clearToFill(lastParamsBuffer); result = result.append(lastParamsBuffer, true); diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/Flusher.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/Flusher.java index 0661b18c5e9..a8006a5df55 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/Flusher.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/Flusher.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -43,7 +43,9 @@ public class Flusher public void flush(Generator.Result... results) { for (Generator.Result result : results) + { offer(result); + } flushCallback.iterate(); } diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/Generator.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/Generator.java index ac3b137daee..aaceab03673 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/Generator.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/Generator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/ServerGenerator.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/ServerGenerator.java index 12eb6bd5962..25f2138b455 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/ServerGenerator.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/ServerGenerator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -92,7 +92,9 @@ public class ServerGenerator extends Generator BufferUtil.clearToFill(buffer); for (int i = 0; i < bytes.size(); i += 2) + { buffer.put(bytes.get(i)).put(COLON).put(bytes.get(i + 1)).put(EOL); + } buffer.put(EOL); BufferUtil.flipToFlush(buffer, 0); diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/BeginRequestContentParser.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/BeginRequestContentParser.java index f318395fcff..6fe19cd44b3 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/BeginRequestContentParser.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/BeginRequestContentParser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ClientParser.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ClientParser.java index 2fe8eb9f147..3e070a4bd10 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ClientParser.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ClientParser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -45,9 +45,9 @@ public class ClientParser extends Parser public interface Listener extends Parser.Listener { - public void onBegin(int request, int code, String reason); + void onBegin(int request, int code, String reason); - public static class Adapter extends Parser.Listener.Adapter implements Listener + class Adapter extends Parser.Listener.Adapter implements Listener { @Override public void onBegin(int request, int code, String reason) @@ -96,7 +96,9 @@ public class ClientParser extends Parser { listener.onEnd(request); for (StreamContentParser streamParser : streamParsers) + { streamParser.end(request); + } } @Override @@ -104,7 +106,9 @@ public class ClientParser extends Parser { listener.onFailure(request, failure); for (StreamContentParser streamParser : streamParsers) + { streamParser.end(request); + } } } } diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ContentParser.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ContentParser.java index 2407c8dd32f..54521faeb24 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ContentParser.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ContentParser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/EndRequestContentParser.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/EndRequestContentParser.java index e76edd437a6..9116159c70f 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/EndRequestContentParser.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/EndRequestContentParser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/HeaderParser.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/HeaderParser.java index e4d7564f258..c02ddb655f3 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/HeaderParser.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/HeaderParser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ParamsContentParser.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ParamsContentParser.java index 0000dd33b31..888f12a1863 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ParamsContentParser.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ParamsContentParser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/Parser.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/Parser.java index cc217f82c27..22aae4f6e3a 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/Parser.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/Parser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -133,9 +133,9 @@ public abstract class Parser public interface Listener { - public void onHeader(int request, HttpField field); + void onHeader(int request, HttpField field); - public void onHeaders(int request); + void onHeaders(int request); /** * @param request the request id @@ -144,13 +144,13 @@ public abstract class Parser * @return true to signal to the parser to stop parsing, false to continue parsing * @see Parser#parse(java.nio.ByteBuffer) */ - public boolean onContent(int request, FCGI.StreamType stream, ByteBuffer buffer); + boolean onContent(int request, FCGI.StreamType stream, ByteBuffer buffer); - public void onEnd(int request); + void onEnd(int request); - public void onFailure(int request, Throwable failure); + void onFailure(int request, Throwable failure); - public static class Adapter implements Listener + class Adapter implements Listener { @Override public void onHeader(int request, HttpField field) diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ResponseContentParser.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ResponseContentParser.java index af908cdf1cb..0a225bb12f0 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ResponseContentParser.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ResponseContentParser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -121,8 +121,8 @@ public class ResponseContentParser extends StreamContentParser // and will not parse it even if it is provided, // so we have to parse it raw ourselves here. boolean rawContent = fields.size() == 0 || - (fields.get(HttpHeader.CONTENT_LENGTH) == null && - fields.get(HttpHeader.TRANSFER_ENCODING) == null); + (fields.get(HttpHeader.CONTENT_LENGTH) == null && + fields.get(HttpHeader.TRANSFER_ENCODING) == null); state = rawContent ? State.RAW_CONTENT : State.HTTP_CONTENT; break; } @@ -233,7 +233,9 @@ public class ResponseContentParser extends StreamContentParser if (fields != null) { for (HttpField field : fields) + { notifyHeader(field); + } } } @@ -289,7 +291,7 @@ public class ResponseContentParser extends StreamContentParser { return false; } - + @Override public boolean messageComplete() { diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ServerParser.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ServerParser.java index c01f0104cbc..6054b631fe8 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ServerParser.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ServerParser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -41,9 +41,9 @@ public class ServerParser extends Parser public interface Listener extends Parser.Listener { - public void onStart(int request, FCGI.Role role, int flags); + void onStart(int request, FCGI.Role role, int flags); - public static class Adapter extends Parser.Listener.Adapter implements Listener + class Adapter extends Parser.Listener.Adapter implements Listener { @Override public void onStart(int request, FCGI.Role role, int flags) diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/StreamContentParser.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/StreamContentParser.java index 682b826978b..8e53ea67b5f 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/StreamContentParser.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/StreamContentParser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-fcgi/fcgi-client/src/test/java/org/eclipse/jetty/fcgi/generator/ClientGeneratorTest.java b/jetty-fcgi/fcgi-client/src/test/java/org/eclipse/jetty/fcgi/generator/ClientGeneratorTest.java index 02fa56926ca..67e6fe9761b 100644 --- a/jetty-fcgi/fcgi-client/src/test/java/org/eclipse/jetty/fcgi/generator/ClientGeneratorTest.java +++ b/jetty-fcgi/fcgi-client/src/test/java/org/eclipse/jetty/fcgi/generator/ClientGeneratorTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,9 +18,6 @@ package org.eclipse.jetty.fcgi.generator; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; - import java.nio.ByteBuffer; import java.util.Arrays; import java.util.concurrent.atomic.AtomicInteger; @@ -31,9 +28,11 @@ import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.MappedByteBufferPool; - import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; + public class ClientGeneratorTest { @Test @@ -76,7 +75,9 @@ public class ClientGeneratorTest final int[] primes = new int[]{2, 3, 5, 7, 11}; int value = 1; for (int prime : primes) + { value *= prime; + } final AtomicInteger params = new AtomicInteger(1); ServerParser parser = new ServerParser(new ServerParser.Listener.Adapter() @@ -129,7 +130,9 @@ public class ClientGeneratorTest { buffer.flip(); while (buffer.hasRemaining()) + { parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()})); + } assertFalse(buffer.hasRemaining()); } @@ -187,7 +190,9 @@ public class ClientGeneratorTest { buffer.flip(); while (buffer.hasRemaining()) + { parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()})); + } assertFalse(buffer.hasRemaining()); } } diff --git a/jetty-fcgi/fcgi-client/src/test/java/org/eclipse/jetty/fcgi/parser/ClientParserTest.java b/jetty-fcgi/fcgi-client/src/test/java/org/eclipse/jetty/fcgi/parser/ClientParserTest.java index 65f4b32f4c3..9d908767238 100644 --- a/jetty-fcgi/fcgi-client/src/test/java/org/eclipse/jetty/fcgi/parser/ClientParserTest.java +++ b/jetty-fcgi/fcgi-client/src/test/java/org/eclipse/jetty/fcgi/parser/ClientParserTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,10 +18,6 @@ package org.eclipse.jetty.fcgi.parser; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.nio.ByteBuffer; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; @@ -33,9 +29,12 @@ import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.MappedByteBufferPool; - 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 ClientParserTest { @Test @@ -60,7 +59,9 @@ public class ClientParserTest final int[] primes = new int[]{2, 3, 5}; int value = 1; for (int prime : primes) + { value *= prime; + } final AtomicInteger params = new AtomicInteger(1); ClientParser parser = new ClientParser(new ClientParser.Listener.Adapter() diff --git a/jetty-fcgi/fcgi-server/pom.xml b/jetty-fcgi/fcgi-server/pom.xml index 3d065b8a36d..04d667347fa 100644 --- a/jetty-fcgi/fcgi-server/pom.xml +++ b/jetty-fcgi/fcgi-server/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.fcgi fcgi-parent - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 @@ -15,8 +15,7 @@ - - + diff --git a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpChannelOverFCGI.java b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpChannelOverFCGI.java index 60f904995ce..1ba90e21ce2 100644 --- a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpChannelOverFCGI.java +++ b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpChannelOverFCGI.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -35,6 +35,7 @@ import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.HttpChannel; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpTransport; +import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -87,10 +88,10 @@ public class HttpChannelOverFCGI extends HttpChannel public void onRequest() { String uri = path; - if (query != null && query.length() > 0) + if (!StringUtil.isEmpty(query)) uri += "?" + query; // TODO https? - onRequest(new MetaData.Request(method, HttpScheme.HTTP.asString(), hostPort, uri, HttpVersion.fromString(version), fields,Long.MIN_VALUE)); + onRequest(new MetaData.Request(method, HttpScheme.HTTP.asString(), hostPort, uri, HttpVersion.fromString(version), fields, Long.MIN_VALUE)); } private HttpField convertHeader(HttpField field) diff --git a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpTransportOverFCGI.java b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpTransportOverFCGI.java index cf6e4a1cc24..09d9b2dbb51 100644 --- a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpTransportOverFCGI.java +++ b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpTransportOverFCGI.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -58,8 +58,8 @@ public class HttpTransportOverFCGI implements HttpTransport @Override public void send(MetaData.Response info, boolean head, ByteBuffer content, boolean lastContent, Callback callback) { - if (info!=null) - commit(info,head,content,lastContent,callback); + if (info != null) + commit(info, head, content, lastContent, callback); else { if (head) @@ -101,7 +101,7 @@ public class HttpTransportOverFCGI implements HttpTransport private void commit(MetaData.Response info, boolean head, ByteBuffer content, boolean lastContent, Callback callback) { if (LOG.isDebugEnabled()) - LOG.debug("commit {} {} l={}",this,info,lastContent); + LOG.debug("commit {} {} l={}", this, info, lastContent); boolean shutdown = this.shutdown = info.getFields().contains(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString()); if (head) @@ -143,7 +143,7 @@ public class HttpTransportOverFCGI implements HttpTransport public void abort(Throwable failure) { if (LOG.isDebugEnabled()) - LOG.debug("abort {} {}",this,failure); + LOG.debug("abort {} {}", this, failure); aborted = true; flusher.shutdown(); } diff --git a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/ServerFCGIConnection.java b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/ServerFCGIConnection.java index a9e7d4fc329..dc9547d7119 100644 --- a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/ServerFCGIConnection.java +++ b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/ServerFCGIConnection.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -108,7 +108,9 @@ public class ServerFCGIConnection extends AbstractConnection private void parse(ByteBuffer buffer) { while (buffer.hasRemaining()) + { parser.parse(buffer); + } } private void shutdown() @@ -123,7 +125,7 @@ public class ServerFCGIConnection extends AbstractConnection { // TODO: handle flags HttpChannelOverFCGI channel = new HttpChannelOverFCGI(connector, configuration, getEndPoint(), - new HttpTransportOverFCGI(connector.getByteBufferPool(), flusher, request, sendStatus200)); + new HttpTransportOverFCGI(connector.getByteBufferPool(), flusher, request, sendStatus200)); HttpChannelOverFCGI existing = channels.putIfAbsent(request, channel); if (existing != null) throw new IllegalStateException(); diff --git a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/ServerFCGIConnectionFactory.java b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/ServerFCGIConnectionFactory.java index 02fb9e0a21f..57da66914fe 100644 --- a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/ServerFCGIConnectionFactory.java +++ b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/ServerFCGIConnectionFactory.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServlet.java b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServlet.java index 15b769f8f3d..42f82635caf 100644 --- a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServlet.java +++ b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServlet.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -24,7 +24,6 @@ import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; - import javax.servlet.RequestDispatcher; import javax.servlet.ServletConfig; import javax.servlet.ServletException; @@ -45,24 +44,24 @@ import org.eclipse.jetty.util.ProcessorUtils; /** * Specific implementation of {@link org.eclipse.jetty.proxy.AsyncProxyServlet.Transparent} for FastCGI. *

      - * This servlet accepts a HTTP request and transforms it into a FastCGI request + * This servlet accepts an HTTP request and transforms it into a FastCGI request * that is sent to the FastCGI server specified in the {@code proxyTo} * init-param. *

      * This servlet accepts two additional init-params: *

        - *
      • {@code scriptRoot}, mandatory, that must be set to the directory where - * the application that must be served via FastCGI is installed and corresponds to - * the FastCGI DOCUMENT_ROOT parameter
      • - *
      • {@code scriptPattern}, optional, defaults to {@code (.+?\.php)}, - * that specifies a regular expression with at least 1 and at most 2 groups that specify - * respectively: - *
          - *
        • the FastCGI SCRIPT_NAME parameter
        • - *
        • the FastCGI PATH_INFO parameter
        • - *
      • - *
      • {@code fastCGI.HTTPS}, optional, defaults to false, that specifies whether - * to force the FastCGI {@code HTTPS} parameter to the value {@code on}
      • + *
      • {@code scriptRoot}, mandatory, that must be set to the directory where + * the application that must be served via FastCGI is installed and corresponds to + * the FastCGI DOCUMENT_ROOT parameter
      • + *
      • {@code scriptPattern}, optional, defaults to {@code (.+?\.php)}, + * that specifies a regular expression with at least 1 and at most 2 groups that specify + * respectively: + *
          + *
        • the FastCGI SCRIPT_NAME parameter
        • + *
        • the FastCGI PATH_INFO parameter
        • + *
      • + *
      • {@code fastCGI.HTTPS}, optional, defaults to false, that specifies whether + * to force the FastCGI {@code HTTPS} parameter to the value {@code on}
      • *
      * * @see TryFilesFilter @@ -112,7 +111,7 @@ public class FastCGIProxyServlet extends AsyncProxyServlet.Transparent String scriptRoot = config.getInitParameter(SCRIPT_ROOT_INIT_PARAM); if (scriptRoot == null) throw new IllegalArgumentException("Mandatory parameter '" + SCRIPT_ROOT_INIT_PARAM + "' not configured"); - int selectors = Math.max( 1, ProcessorUtils.availableProcessors() / 2); + int selectors = Math.max(1, ProcessorUtils.availableProcessors() / 2); String value = config.getInitParameter("selectors"); if (value != null) selectors = Integer.parseInt(value); @@ -257,11 +256,13 @@ public class FastCGIProxyServlet extends AsyncProxyServlet.Transparent { TreeMap fcgi = new TreeMap<>(); for (HttpField field : fastCGIHeaders) + { fcgi.put(field.getName(), field.getValue()); + } String eol = System.lineSeparator(); _log.debug("FastCGI variables{}{}", eol, fcgi.entrySet().stream() - .map(entry -> String.format("%s: %s", entry.getKey(), entry.getValue())) - .collect(Collectors.joining(eol))); + .map(entry -> String.format("%s: %s", entry.getKey(), entry.getValue())) + .collect(Collectors.joining(eol))); } } } diff --git a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/TryFilesFilter.java b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/TryFilesFilter.java index a158e307773..7a047c6c1cc 100644 --- a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/TryFilesFilter.java +++ b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/TryFilesFilter.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -24,7 +24,6 @@ import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; - import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; @@ -35,6 +34,8 @@ import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.util.StringUtil; + /** * Inspired by nginx's try_files functionality. *

      @@ -132,7 +133,7 @@ public class TryFilesFilter implements Filter path += info; if (!path.startsWith("/")) path = "/" + path; - return value.replaceAll("\\$path", path); + return StringUtil.replace(value, "$path", path); } @Override diff --git a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/AbstractHttpClientServerTest.java b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/AbstractHttpClientServerTest.java index ab0162991ad..03dc3bceed8 100644 --- a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/AbstractHttpClientServerTest.java +++ b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/AbstractHttpClientServerTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,8 +18,6 @@ package org.eclipse.jetty.fcgi.server; -import static org.hamcrest.MatcherAssert.assertThat; - import java.util.concurrent.atomic.AtomicLong; import org.eclipse.jetty.client.HttpClient; @@ -40,6 +38,8 @@ import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.hamcrest.Matchers; import org.junit.jupiter.api.AfterEach; +import static org.hamcrest.MatcherAssert.assertThat; + public abstract class AbstractHttpClientServerTest { private LeakTrackingByteBufferPool serverBufferPool; @@ -56,8 +56,8 @@ public abstract class AbstractHttpClientServerTest ServerFCGIConnectionFactory fcgiConnectionFactory = new ServerFCGIConnectionFactory(new HttpConfiguration()); serverBufferPool = new LeakTrackingByteBufferPool(new MappedByteBufferPool.Tagged()); - connector = new ServerConnector( server, null, null, serverBufferPool, - 1, Math.max( 1, ProcessorUtils.availableProcessors() / 2), fcgiConnectionFactory); + connector = new ServerConnector(server, null, null, serverBufferPool, + 1, Math.max(1, ProcessorUtils.availableProcessors() / 2), fcgiConnectionFactory); // connector.setPort(9000); server.addConnector(connector); @@ -89,11 +89,14 @@ public abstract class AbstractHttpClientServerTest { System.gc(); - assertThat("Server BufferPool - leaked acquires", serverBufferPool.getLeakedAcquires(), Matchers.is(0L)); - assertThat("Server BufferPool - leaked releases", serverBufferPool.getLeakedReleases(), Matchers.is(0L)); - assertThat("Server BufferPool - unreleased", serverBufferPool.getLeakedResources(), Matchers.is(0L)); + if (serverBufferPool != null) + { + assertThat("Server BufferPool - leaked acquires", serverBufferPool.getLeakedAcquires(), Matchers.is(0L)); + assertThat("Server BufferPool - leaked releases", serverBufferPool.getLeakedReleases(), Matchers.is(0L)); + assertThat("Server BufferPool - unreleased", serverBufferPool.getLeakedResources(), Matchers.is(0L)); + } - if (clientBufferPool instanceof LeakTrackingByteBufferPool) + if ((clientBufferPool != null) && (clientBufferPool instanceof LeakTrackingByteBufferPool)) { LeakTrackingByteBufferPool pool = (LeakTrackingByteBufferPool)clientBufferPool; assertThat("Client BufferPool - leaked acquires", pool.getLeakedAcquires(), Matchers.is(0L)); diff --git a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/EmptyServerHandler.java b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/EmptyServerHandler.java index 696c27ec02b..708231649b1 100644 --- a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/EmptyServerHandler.java +++ b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/EmptyServerHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,7 +19,6 @@ package org.eclipse.jetty.fcgi.server; import java.io.IOException; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; diff --git a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/ExternalFastCGIServerTest.java b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/ExternalFastCGIServerTest.java index dd1a680eebc..663c2d66643 100644 --- a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/ExternalFastCGIServerTest.java +++ b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/ExternalFastCGIServerTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,8 +18,6 @@ package org.eclipse.jetty.fcgi.server; -import static org.junit.jupiter.api.Assertions.assertEquals; - import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -32,6 +30,8 @@ import org.eclipse.jetty.fcgi.client.http.HttpClientTransportOverFCGI; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class ExternalFastCGIServerTest { @Test @@ -44,9 +44,9 @@ public class ExternalFastCGIServerTest client.start(); ContentResponse response = client.newRequest("localhost", 9000) - .path("/index.php") - .timeout(5, TimeUnit.SECONDS) - .send(); + .path("/index.php") + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(200, response.getStatus()); diff --git a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/HttpClientTest.java b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/HttpClientTest.java index bd661438d38..f151f7ccce9 100644 --- a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/HttpClientTest.java +++ b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/HttpClientTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,14 +18,6 @@ package org.eclipse.jetty.fcgi.server; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.instanceOf; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.EOFException; import java.io.IOException; import java.net.URI; @@ -40,7 +32,6 @@ import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.zip.GZIPOutputStream; - import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; @@ -57,12 +48,21 @@ import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.io.MappedByteBufferPool; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.toolchain.test.IO; +import org.eclipse.jetty.toolchain.test.Net; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.log.StacklessLogging; - +import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledIfSystemProperty; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.instanceOf; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class HttpClientTest extends AbstractHttpClientServerTest { @Test @@ -180,7 +180,9 @@ public class HttpClientTest extends AbstractHttpClientServerTest ServletOutputStream output = response.getOutputStream(); String[] paramValues1 = request.getParameterValues(paramName1); for (String paramValue : paramValues1) + { output.write(paramValue.getBytes("UTF-8")); + } String paramValue2 = request.getParameter(paramName2); output.write(paramValue2.getBytes("UTF-8")); baseRequest.setHandled(true); @@ -224,9 +226,9 @@ public class HttpClientTest extends AbstractHttpClientServerTest }); ContentResponse response = client.POST(scheme + "://localhost:" + connector.getLocalPort()) - .param(paramName, paramValue) - .timeout(5, TimeUnit.SECONDS) - .send(); + .param(paramName, paramValue) + .timeout(5, TimeUnit.SECONDS) + .send(); assertNotNull(response); assertEquals(200, response.getStatus()); @@ -255,10 +257,10 @@ public class HttpClientTest extends AbstractHttpClientServerTest }); String uri = scheme + "://localhost:" + connector.getLocalPort() + - "/?" + paramName + "=" + URLEncoder.encode(paramValue, "UTF-8"); + "/?" + paramName + "=" + URLEncoder.encode(paramValue, "UTF-8"); ContentResponse response = client.POST(uri) - .timeout(5, TimeUnit.SECONDS) - .send(); + .timeout(5, TimeUnit.SECONDS) + .send(); assertNotNull(response); assertEquals(200, response.getStatus()); @@ -288,9 +290,9 @@ public class HttpClientTest extends AbstractHttpClientServerTest URI uri = URI.create(scheme + "://localhost:" + connector.getLocalPort() + "/path?" + paramName + "=" + paramValue); ContentResponse response = client.newRequest(uri) - .method(HttpMethod.PUT) - .timeout(5, TimeUnit.SECONDS) - .send(); + .method(HttpMethod.PUT) + .timeout(5, TimeUnit.SECONDS) + .send(); assertNotNull(response); assertEquals(200, response.getStatus()); @@ -322,10 +324,10 @@ public class HttpClientTest extends AbstractHttpClientServerTest for (int i = 0; i < 256; ++i) { ContentResponse response = client.POST(scheme + "://localhost:" + connector.getLocalPort() + "/?b=1") - .param(paramName, paramValue) - .content(new BytesContentProvider(content)) - .timeout(5, TimeUnit.SECONDS) - .send(); + .param(paramName, paramValue) + .content(new BytesContentProvider(content)) + .timeout(5, TimeUnit.SECONDS) + .send(); assertNotNull(response); assertEquals(200, response.getStatus()); @@ -340,20 +342,20 @@ public class HttpClientTest extends AbstractHttpClientServerTest start(new EmptyServerHandler()); ContentResponse response = client.POST(scheme + "://localhost:" + connector.getLocalPort()) - .onRequestContent(new Request.ContentListener() + .onRequestContent(new Request.ContentListener() + { + @Override + public void onContent(Request request, ByteBuffer buffer) { - @Override - public void onContent(Request request, ByteBuffer buffer) - { - byte[] bytes = new byte[buffer.remaining()]; - buffer.get(bytes); - if (!Arrays.equals(content, bytes)) - request.abort(new Exception()); - } - }) - .content(new BytesContentProvider(content)) - .timeout(5, TimeUnit.SECONDS) - .send(); + byte[] bytes = new byte[buffer.remaining()]; + buffer.get(bytes); + if (!Arrays.equals(content, bytes)) + request.abort(new Exception()); + } + }) + .content(new BytesContentProvider(content)) + .timeout(5, TimeUnit.SECONDS) + .send(); assertNotNull(response); assertEquals(200, response.getStatus()); @@ -366,20 +368,20 @@ public class HttpClientTest extends AbstractHttpClientServerTest final AtomicInteger progress = new AtomicInteger(); ContentResponse response = client.POST(scheme + "://localhost:" + connector.getLocalPort()) - .onRequestContent(new Request.ContentListener() + .onRequestContent(new Request.ContentListener() + { + @Override + public void onContent(Request request, ByteBuffer buffer) { - @Override - public void onContent(Request request, ByteBuffer buffer) - { - byte[] bytes = new byte[buffer.remaining()]; - assertEquals(1, bytes.length); - buffer.get(bytes); - assertEquals(bytes[0], progress.getAndIncrement()); - } - }) - .content(new BytesContentProvider(new byte[]{0}, new byte[]{1}, new byte[]{2}, new byte[]{3}, new byte[]{4})) - .timeout(5, TimeUnit.SECONDS) - .send(); + byte[] bytes = new byte[buffer.remaining()]; + assertEquals(1, bytes.length); + buffer.get(bytes); + assertEquals(bytes[0], progress.getAndIncrement()); + } + }) + .content(new BytesContentProvider(new byte[]{0}, new byte[]{1}, new byte[]{2}, new byte[]{3}, new byte[]{4})) + .timeout(5, TimeUnit.SECONDS) + .send(); assertNotNull(response); assertEquals(200, response.getStatus()); @@ -409,9 +411,9 @@ public class HttpClientTest extends AbstractHttpClientServerTest }); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scheme) - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scheme) + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(200, response.getStatus()); assertArrayEquals(data, response.getContent()); @@ -441,19 +443,20 @@ public class HttpClientTest extends AbstractHttpClientServerTest final String host = "localhost"; final int port = connector.getLocalPort(); - assertThrows(TimeoutException.class, ()->{ + assertThrows(TimeoutException.class, () -> + { client.newRequest(host, port) - .scheme(scheme) - .idleTimeout(idleTimeout, TimeUnit.MILLISECONDS) - .timeout(3 * idleTimeout, TimeUnit.MILLISECONDS) - .send(); + .scheme(scheme) + .idleTimeout(idleTimeout, TimeUnit.MILLISECONDS) + .timeout(3 * idleTimeout, TimeUnit.MILLISECONDS) + .send(); }); // Make another request without specifying the idle timeout, should not fail ContentResponse response = client.newRequest(host, port) - .scheme(scheme) - .timeout(3 * idleTimeout, TimeUnit.MILLISECONDS) - .send(); + .scheme(scheme) + .timeout(3 * idleTimeout, TimeUnit.MILLISECONDS) + .send(); assertNotNull(response); assertEquals(200, response.getStatus()); @@ -482,12 +485,13 @@ public class HttpClientTest extends AbstractHttpClientServerTest connector.setIdleTimeout(idleTimeout); - ExecutionException x = assertThrows(ExecutionException.class, ()->{ + ExecutionException x = assertThrows(ExecutionException.class, () -> + { client.newRequest("localhost", connector.getLocalPort()) - .scheme(scheme) - .idleTimeout(4 * idleTimeout, TimeUnit.MILLISECONDS) - .timeout(3 * idleTimeout, TimeUnit.MILLISECONDS) - .send(); + .scheme(scheme) + .idleTimeout(4 * idleTimeout, TimeUnit.MILLISECONDS) + .timeout(3 * idleTimeout, TimeUnit.MILLISECONDS) + .send(); }); assertThat(x.getCause(), instanceOf(EOFException.class)); @@ -495,10 +499,10 @@ public class HttpClientTest extends AbstractHttpClientServerTest // Make another request to be sure the connection is recreated ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scheme) - .idleTimeout(4 * idleTimeout, TimeUnit.MILLISECONDS) - .timeout(3 * idleTimeout, TimeUnit.MILLISECONDS) - .send(); + .scheme(scheme) + .idleTimeout(4 * idleTimeout, TimeUnit.MILLISECONDS) + .timeout(3 * idleTimeout, TimeUnit.MILLISECONDS) + .send(); assertNotNull(response); assertEquals(200, response.getStatus()); @@ -507,12 +511,13 @@ public class HttpClientTest extends AbstractHttpClientServerTest @Test public void testSendToIPv6Address() throws Exception { + Assumptions.assumeTrue(Net.isIpv6InterfaceAvailable()); start(new EmptyServerHandler()); ContentResponse response = client.newRequest("[::1]", connector.getLocalPort()) - .scheme(scheme) - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scheme) + .timeout(5, TimeUnit.SECONDS) + .send(); assertNotNull(response); assertEquals(200, response.getStatus()); @@ -535,10 +540,10 @@ public class HttpClientTest extends AbstractHttpClientServerTest // HEAD requests receive a Content-Length header, but do not // receive the content so they must handle this case properly ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scheme) - .method(HttpMethod.HEAD) - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scheme) + .method(HttpMethod.HEAD) + .timeout(5, TimeUnit.SECONDS) + .send(); assertNotNull(response); assertEquals(200, response.getStatus()); @@ -546,9 +551,9 @@ public class HttpClientTest extends AbstractHttpClientServerTest // Perform a normal GET request to be sure the content is now read response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scheme) - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(scheme) + .timeout(5, TimeUnit.SECONDS) + .send(); assertNotNull(response); assertEquals(200, response.getStatus()); @@ -572,16 +577,16 @@ public class HttpClientTest extends AbstractHttpClientServerTest final CountDownLatch completeLatch = new CountDownLatch(1); client.newRequest("localhost", connector.getLocalPort()) - .scheme(scheme) - .send(new Response.CompleteListener() + .scheme(scheme) + .send(new Response.CompleteListener() + { + @Override + public void onComplete(Result result) { - @Override - public void onComplete(Result result) - { - if (result.isFailed()) - completeLatch.countDown(); - } - }); + if (result.isFailed()) + completeLatch.countDown(); + } + }); assertTrue(latch.await(5, TimeUnit.SECONDS)); @@ -609,11 +614,12 @@ public class HttpClientTest extends AbstractHttpClientServerTest try (StacklessLogging ignore = new StacklessLogging(org.eclipse.jetty.server.HttpChannel.class)) { - assertThrows(ExecutionException.class, () -> { + assertThrows(ExecutionException.class, () -> + { client.newRequest("localhost", connector.getLocalPort()) - .scheme(scheme) - .timeout(60, TimeUnit.SECONDS) - .send(); + .scheme(scheme) + .timeout(60, TimeUnit.SECONDS) + .send(); }); } } @@ -647,8 +653,8 @@ public class HttpClientTest extends AbstractHttpClientServerTest DeferredContentProvider content = new DeferredContentProvider(ByteBuffer.wrap(new byte[]{0})); Request request = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scheme) - .content(content); + .scheme(scheme) + .content(content); FutureResponseListener listener = new FutureResponseListener(request); request.send(listener); // Wait some time to simulate a slow request. @@ -681,25 +687,25 @@ public class HttpClientTest extends AbstractHttpClientServerTest final AtomicReference contentLatch = new AtomicReference<>(new CountDownLatch(1)); final CountDownLatch completeLatch = new CountDownLatch(1); client.newRequest("localhost", connector.getLocalPort()) - .scheme(scheme) - .onResponseContentAsync(new Response.AsyncContentListener() + .scheme(scheme) + .onResponseContentAsync(new Response.AsyncContentListener() + { + @Override + public void onContent(Response response, ByteBuffer content, Callback callback) { - @Override - public void onContent(Response response, ByteBuffer content, Callback callback) - { - contentCount.incrementAndGet(); - callbackRef.set(callback); - contentLatch.get().countDown(); - } - }) - .send(new Response.CompleteListener() + contentCount.incrementAndGet(); + callbackRef.set(callback); + contentLatch.get().countDown(); + } + }) + .send(new Response.CompleteListener() + { + @Override + public void onComplete(Result result) { - @Override - public void onComplete(Result result) - { - completeLatch.countDown(); - } - }); + completeLatch.countDown(); + } + }); assertTrue(contentLatch.get().await(5, TimeUnit.SECONDS)); Callback callback = callbackRef.get(); diff --git a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/DrupalHTTP2FastCGIProxyServer.java b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/DrupalHTTP2FastCGIProxyServer.java index c8bf2f0a57c..fac3eeb3416 100644 --- a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/DrupalHTTP2FastCGIProxyServer.java +++ b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/DrupalHTTP2FastCGIProxyServer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -36,8 +36,7 @@ public class DrupalHTTP2FastCGIProxyServer { public static void main(String[] args) throws Exception { - SslContextFactory sslContextFactory = new SslContextFactory(); - sslContextFactory.setEndpointIdentificationAlgorithm(""); + SslContextFactory sslContextFactory = new SslContextFactory.Server(); sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks"); sslContextFactory.setKeyStorePassword("storepwd"); sslContextFactory.setTrustStorePath("src/test/resources/truststore.jks"); @@ -50,18 +49,18 @@ public class DrupalHTTP2FastCGIProxyServer HttpConfiguration config = new HttpConfiguration(); HttpConfiguration https_config = new HttpConfiguration(config); https_config.addCustomizer(new SecureRequestCustomizer()); - + // HTTP2 factory HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(https_config); ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory(); alpn.setDefaultProtocol(h2.getProtocol()); - + // SSL Factory - SslConnectionFactory ssl = new SslConnectionFactory(sslContextFactory,alpn.getProtocol()); - + SslConnectionFactory ssl = new SslConnectionFactory(sslContextFactory, alpn.getProtocol()); + // HTTP2 Connector - ServerConnector http2Connector = - new ServerConnector(server,ssl,alpn,h2,new HttpConnectionFactory(https_config)); + ServerConnector http2Connector = + new ServerConnector(server, ssl, alpn, h2, new HttpConnectionFactory(https_config)); http2Connector.setPort(8443); http2Connector.setIdleTimeout(15000); server.addConnector(http2Connector); diff --git a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServletTest.java b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServletTest.java index 9361914e6ad..e3a93abb663 100644 --- a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServletTest.java +++ b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServletTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,16 +18,10 @@ package org.eclipse.jetty.fcgi.server.proxy; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.IOException; import java.util.Random; import java.util.concurrent.TimeUnit; import java.util.stream.Stream; - import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -53,13 +47,18 @@ 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.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class FastCGIProxyServletTest { public static Stream factories() { return Stream.of( - true, // send status 200 - false // don't send status 200 + true, // send status 200 + false // don't send status 200 ).map(Arguments::of); } @@ -116,21 +115,21 @@ public class FastCGIProxyServletTest server.stop(); } - @ParameterizedTest(name="[{index}] sendStatus200={0}") + @ParameterizedTest(name = "[{index}] sendStatus200={0}") @MethodSource("factories") public void testGETWithSmallResponseContent(boolean sendStatus200) throws Exception { testGETWithResponseContent(sendStatus200, 1024, 0); } - @ParameterizedTest(name="[{index}] sendStatus200={0}") + @ParameterizedTest(name = "[{index}] sendStatus200={0}") @MethodSource("factories") public void testGETWithLargeResponseContent(boolean sendStatus200) throws Exception { testGETWithResponseContent(sendStatus200, 16 * 1024 * 1024, 0); } - @ParameterizedTest(name="[{index}] sendStatus200={0}") + @ParameterizedTest(name = "[{index}] sendStatus200={0}") @MethodSource("factories") public void testGETWithLargeResponseContentWithSlowClient(boolean sendStatus200) throws Exception { @@ -155,20 +154,20 @@ public class FastCGIProxyServletTest }); Request request = client.newRequest("localhost", httpConnector.getLocalPort()) - .onResponseContentAsync((response, content, callback) -> + .onResponseContentAsync((response, content, callback) -> + { + try { - try - { - if (delay > 0) - TimeUnit.MILLISECONDS.sleep(delay); - callback.succeeded(); - } - catch (InterruptedException x) - { - callback.failed(x); - } - }) - .path(path); + if (delay > 0) + TimeUnit.MILLISECONDS.sleep(delay); + callback.succeeded(); + } + catch (InterruptedException x) + { + callback.failed(x); + } + }) + .path(path); FutureResponseListener listener = new FutureResponseListener(request, length); request.send(listener); @@ -178,7 +177,7 @@ public class FastCGIProxyServletTest assertArrayEquals(data, response.getContent()); } - @ParameterizedTest(name="[{index}] sendStatus200={0}") + @ParameterizedTest(name = "[{index}] sendStatus200={0}") @MethodSource("factories") public void testURIRewrite(boolean sendStatus200) throws Exception { @@ -217,8 +216,8 @@ public class FastCGIProxyServletTest context.start(); ContentResponse response = client.newRequest("localhost", httpConnector.getLocalPort()) - .path(remotePath) - .send(); + .path(remotePath) + .send(); assertEquals(HttpStatus.OK_200, response.getStatus()); } diff --git a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/TryFilesFilterTest.java b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/TryFilesFilterTest.java index 173df037ac8..4a3fd24366e 100644 --- a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/TryFilesFilterTest.java +++ b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/TryFilesFilterTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,12 +18,8 @@ package org.eclipse.jetty.fcgi.server.proxy; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.IOException; import java.util.EnumSet; - import javax.servlet.DispatcherType; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -41,6 +37,9 @@ import org.eclipse.jetty.util.ssl.SslContextFactory; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class TryFilesFilterTest { private Server server; @@ -55,13 +54,10 @@ public class TryFilesFilterTest connector = new ServerConnector(server); server.addConnector(connector); - SslContextFactory sslContextFactory = new SslContextFactory(); - sslContextFactory.setEndpointIdentificationAlgorithm(""); - sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks"); - sslContextFactory.setKeyStorePassword("storepwd"); - sslContextFactory.setTrustStorePath("src/test/resources/truststore.jks"); - sslContextFactory.setTrustStorePassword("storepwd"); - sslConnector = new ServerConnector(server, sslContextFactory); + SslContextFactory.Server serverSslContextFactory = new SslContextFactory.Server(); + serverSslContextFactory.setKeyStorePath("src/test/resources/keystore.jks"); + serverSslContextFactory.setKeyStorePassword("storepwd"); + sslConnector = new ServerConnector(server, serverSslContextFactory); server.addConnector(sslConnector); ServletContextHandler context = new ServletContextHandler(server, "/"); @@ -72,7 +68,13 @@ public class TryFilesFilterTest context.addServlet(new ServletHolder(servlet), "/*"); - client = new HttpClient(sslContextFactory); + SslContextFactory.Client clientSslContextFactory = new SslContextFactory.Client(); + clientSslContextFactory.setEndpointIdentificationAlgorithm(null); + clientSslContextFactory.setKeyStorePath("src/test/resources/keystore.jks"); + clientSslContextFactory.setKeyStorePassword("storepwd"); + clientSslContextFactory.setTrustStorePath("src/test/resources/truststore.jks"); + clientSslContextFactory.setTrustStorePassword("storepwd"); + client = new HttpClient(clientSslContextFactory); server.addBean(client); server.start(); @@ -101,9 +103,9 @@ public class TryFilesFilterTest }); ContentResponse response = client.newRequest("localhost", sslConnector.getLocalPort()) - .scheme("https") - .path(path) - .send(); + .scheme("https") + .path(path) + .send(); assertEquals(200, response.getStatus()); } diff --git a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/WordPressHTTP2FastCGIProxyServer.java b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/WordPressHTTP2FastCGIProxyServer.java index f37b536bc6e..60e1de91fcc 100644 --- a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/WordPressHTTP2FastCGIProxyServer.java +++ b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/WordPressHTTP2FastCGIProxyServer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,7 +19,6 @@ package org.eclipse.jetty.fcgi.server.proxy; import java.util.EnumSet; - import javax.servlet.DispatcherType; import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory; @@ -43,8 +42,7 @@ public class WordPressHTTP2FastCGIProxyServer { int tlsPort = 8443; - SslContextFactory sslContextFactory = new SslContextFactory(); - sslContextFactory.setEndpointIdentificationAlgorithm(""); + SslContextFactory sslContextFactory = new SslContextFactory.Server(); sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks"); sslContextFactory.setKeyStorePassword("storepwd"); sslContextFactory.setTrustStorePath("src/test/resources/truststore.jks"); @@ -57,18 +55,18 @@ public class WordPressHTTP2FastCGIProxyServer HttpConfiguration config = new HttpConfiguration(); HttpConfiguration https_config = new HttpConfiguration(config); https_config.addCustomizer(new SecureRequestCustomizer()); - + // HTTP2 factory HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(https_config); ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory(); alpn.setDefaultProtocol(h2.getProtocol()); - + // SSL Factory - SslConnectionFactory ssl = new SslConnectionFactory(sslContextFactory,alpn.getProtocol()); - + SslConnectionFactory ssl = new SslConnectionFactory(sslContextFactory, alpn.getProtocol()); + // HTTP2 Connector - ServerConnector http2Connector = - new ServerConnector(server,ssl,alpn,h2,new HttpConnectionFactory(https_config)); + ServerConnector http2Connector = + new ServerConnector(server, ssl, alpn, h2, new HttpConnectionFactory(https_config)); http2Connector.setPort(tlsPort); http2Connector.setIdleTimeout(15000); server.addConnector(http2Connector); diff --git a/jetty-fcgi/pom.xml b/jetty-fcgi/pom.xml index c8bcc7ffb5a..2c42735269e 100644 --- a/jetty-fcgi/pom.xml +++ b/jetty-fcgi/pom.xml @@ -1,28 +1,28 @@ - - org.eclipse.jetty - jetty-project - 9.4.13-SNAPSHOT - + + org.eclipse.jetty + jetty-project + 9.4.21-SNAPSHOT + - 4.0.0 - org.eclipse.jetty.fcgi - fcgi-parent - pom - Jetty :: FastCGI :: Parent + 4.0.0 + org.eclipse.jetty.fcgi + fcgi-parent + pom + Jetty :: FastCGI :: Parent - - fcgi-client - fcgi-server - + + fcgi-client + fcgi-server + - - - org.eclipse.jetty.toolchain - jetty-test-helper - test - - + + + org.eclipse.jetty.toolchain + jetty-test-helper + test + + diff --git a/jetty-gcloud/jetty-gcloud-session-manager/pom.xml b/jetty-gcloud/jetty-gcloud-session-manager/pom.xml index 66c7a9f6430..6ba7297d839 100644 --- a/jetty-gcloud/jetty-gcloud-session-manager/pom.xml +++ b/jetty-gcloud/jetty-gcloud-session-manager/pom.xml @@ -1,11 +1,9 @@ - + org.eclipse.jetty.gcloud gcloud-parent - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 @@ -32,7 +30,32 @@ javax.servlet-api - + + + + io.grpc + grpc-core + compile + + + com.google.auto.value + auto-value + 1.2 + + + com.google.protobuf + protobuf-java + 3.2.0 + + + com.google.http-client + google-http-client-jackson2 + 1.21.0 + + + com.google.code.findbugs + jsr305 + 3.0.0 org.eclipse.jetty @@ -117,15 +140,8 @@ - - + + @@ -138,8 +154,8 @@ - - + + diff --git a/jetty-gcloud/jetty-gcloud-session-manager/src/main/config-template/etc/sessions/gcloud/session-store.xml b/jetty-gcloud/jetty-gcloud-session-manager/src/main/config-template/etc/sessions/gcloud/session-store.xml index dbe863e7a1c..278815e15c6 100644 --- a/jetty-gcloud/jetty-gcloud-session-manager/src/main/config-template/etc/sessions/gcloud/session-store.xml +++ b/jetty-gcloud/jetty-gcloud-session-manager/src/main/config-template/etc/sessions/gcloud/session-store.xml @@ -1,5 +1,4 @@ - - + diff --git a/jetty-gcloud/jetty-gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudSessionDataStore.java b/jetty-gcloud/jetty-gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudSessionDataStore.java index c8a6f30fca6..21f700d63af 100644 --- a/jetty-gcloud/jetty-gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudSessionDataStore.java +++ b/jetty-gcloud/jetty-gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudSessionDataStore.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,27 +16,12 @@ // ======================================================================== // - package org.eclipse.jetty.gcloud.session; import java.io.ByteArrayOutputStream; import java.io.ObjectOutputStream; import java.util.HashSet; -import java.util.Map; import java.util.Set; -import java.util.concurrent.atomic.AtomicReference; - -import org.eclipse.jetty.server.session.AbstractSessionDataStore; -import org.eclipse.jetty.server.session.SessionContext; -import org.eclipse.jetty.server.session.SessionData; -import org.eclipse.jetty.server.session.UnreadableSessionDataException; -import org.eclipse.jetty.server.session.UnwriteableSessionDataException; -import org.eclipse.jetty.util.ClassLoadingObjectInputStream; -import org.eclipse.jetty.util.StringUtil; -import org.eclipse.jetty.util.annotation.ManagedAttribute; -import org.eclipse.jetty.util.annotation.ManagedObject; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; import com.google.cloud.datastore.Blob; import com.google.cloud.datastore.BlobValue; @@ -51,17 +36,25 @@ import com.google.cloud.datastore.Query; import com.google.cloud.datastore.QueryResults; import com.google.cloud.datastore.StructuredQuery.CompositeFilter; import com.google.cloud.datastore.StructuredQuery.PropertyFilter; +import org.eclipse.jetty.server.session.AbstractSessionDataStore; +import org.eclipse.jetty.server.session.SessionContext; +import org.eclipse.jetty.server.session.SessionData; +import org.eclipse.jetty.server.session.UnreadableSessionDataException; +import org.eclipse.jetty.server.session.UnwriteableSessionDataException; +import org.eclipse.jetty.util.ClassLoadingObjectInputStream; +import org.eclipse.jetty.util.StringUtil; +import org.eclipse.jetty.util.annotation.ManagedAttribute; +import org.eclipse.jetty.util.annotation.ManagedObject; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; /** * GCloudSessionDataStore - * - * */ @ManagedObject public class GCloudSessionDataStore extends AbstractSessionDataStore { - private final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session"); - + private static final Logger LOG = Log.getLogger("org.eclipse.jetty.server.session"); public static final int DEFAULT_MAX_QUERY_RESULTS = 100; public static final int DEFAULT_MAX_RETRIES = 5; @@ -78,11 +71,8 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore protected EntityDataModel _model; protected boolean _modelProvided; - private String _namespace; - - - + /** * EntityDataModel * @@ -90,18 +80,18 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore */ public static class EntityDataModel { - public static final String ID = "id"; - public static final String CONTEXTPATH = "contextPath"; - public static final String VHOST = "vhost"; - public static final String ACCESSED = "accessed"; - public static final String LASTACCESSED = "lastAccessed"; - public static final String CREATETIME = "createTime"; - public static final String COOKIESETTIME = "cookieSetTime"; - public static final String LASTNODE = "lastNode"; - public static final String EXPIRY = "expiry"; - public static final String MAXINACTIVE = "maxInactive"; - public static final String ATTRIBUTES = "attributes"; - public static final String LASTSAVED = "lastSaved"; + public static final String ID = "id"; + public static final String CONTEXTPATH = "contextPath"; + public static final String VHOST = "vhost"; + public static final String ACCESSED = "accessed"; + public static final String LASTACCESSED = "lastAccessed"; + public static final String CREATETIME = "createTime"; + public static final String COOKIESETTIME = "cookieSetTime"; + public static final String LASTNODE = "lastNode"; + public static final String EXPIRY = "expiry"; + public static final String MAXINACTIVE = "maxInactive"; + public static final String ATTRIBUTES = "attributes"; + public static final String LASTSAVED = "lastSaved"; public static final String KIND = "GCloudSession"; protected String _kind = KIND; @@ -117,14 +107,13 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore protected String _expiry = EXPIRY; protected String _maxInactive = MAXINACTIVE; protected String _attributes = ATTRIBUTES; - - + private void checkNotNull(String s) { if (s == null) throw new IllegalArgumentException(s); } - + /** * @return the lastNode */ @@ -148,6 +137,7 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore { return _kind; } + /** * @param kind the kind to set */ @@ -156,6 +146,7 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore checkNotNull(kind); _kind = kind; } + /** * @return the id */ @@ -163,6 +154,7 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore { return _id; } + /** * @param id the id to set */ @@ -171,6 +163,7 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore checkNotNull(id); _id = id; } + /** * @return the contextPath */ @@ -178,6 +171,7 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore { return _contextPath; } + /** * @param contextPath the contextPath to set */ @@ -186,6 +180,7 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore checkNotNull(contextPath); _contextPath = contextPath; } + /** * @return the vhost */ @@ -193,6 +188,7 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore { return _vhost; } + /** * @param vhost the vhost to set */ @@ -201,6 +197,7 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore checkNotNull(vhost); _vhost = vhost; } + /** * @return the accessed */ @@ -208,6 +205,7 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore { return _accessed; } + /** * @param accessed the accessed to set */ @@ -216,6 +214,7 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore checkNotNull(accessed); _accessed = accessed; } + /** * @return the lastAccessed */ @@ -223,6 +222,7 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore { return _lastAccessed; } + /** * @param lastAccessed the lastAccessed to set */ @@ -231,6 +231,7 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore checkNotNull(lastAccessed); _lastAccessed = lastAccessed; } + /** * @return the createTime */ @@ -238,6 +239,7 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore { return _createTime; } + /** * @param createTime the createTime to set */ @@ -246,6 +248,7 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore checkNotNull(createTime); _createTime = createTime; } + /** * @return the cookieSetTime */ @@ -253,6 +256,7 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore { return _cookieSetTime; } + /** * @param cookieSetTime the cookieSetTime to set */ @@ -261,6 +265,7 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore checkNotNull(cookieSetTime); _cookieSetTime = cookieSetTime; } + /** * @return the expiry */ @@ -268,6 +273,7 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore { return _expiry; } + /** * @param expiry the expiry to set */ @@ -276,6 +282,7 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore checkNotNull(expiry); _expiry = expiry; } + /** * @return the maxInactive */ @@ -283,6 +290,7 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore { return _maxInactive; } + /** * @param maxInactive the maxInactive to set */ @@ -291,6 +299,7 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore checkNotNull(maxInactive); _maxInactive = maxInactive; } + /** * @return the attributes */ @@ -298,6 +307,7 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore { return _attributes; } + /** * @param attributes the attributes to set */ @@ -324,21 +334,14 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore _lastSaved = lastSaved; } - /** - * @see java.lang.Object#toString() - */ @Override public String toString() { - return String.format("%s==%s:%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s",this.getClass().getName(), - _kind,_accessed,_attributes,_contextPath,_cookieSetTime,_createTime,_expiry,_id,_lastAccessed,_lastNode,_maxInactive,_vhost); + return String.format("%s==%s:%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s", this.getClass().getName(), + _kind, _accessed, _attributes, _contextPath, _cookieSetTime, _createTime, _expiry, _id, _lastAccessed, _lastNode, _maxInactive, _vhost); } - - - } - - + /** * ExpiryInfo * @@ -349,13 +352,13 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore String _id; String _lastNode; long _expiry; - + /** * @param id session id - * @param lastNode last node id to manage the session - * @param expiry timestamp of expiry + * @param lastNode last node id to manage the session + * @param expiry timestamp of expiry */ - public ExpiryInfo (String id, String lastNode, long expiry) + public ExpiryInfo(String id, String lastNode, long expiry) { _id = id; _lastNode = lastNode; @@ -385,61 +388,53 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore { return _expiry; } - - } - + public void setEntityDataModel(EntityDataModel model) { updateBean(_model, model); _model = model; _modelProvided = true; } - - - public EntityDataModel getEntityDataModel () + + public EntityDataModel getEntityDataModel() { return _model; } - - - public void setBackoffMs (int ms) + + public void setBackoffMs(int ms) { _backoff = ms; } - - public void setNamespace (String namespace) + + public void setNamespace(String namespace) { _namespace = namespace; } - - @ManagedAttribute(value="gclound namespace", readonly=true) - public String getNamespace () + + @ManagedAttribute(value = "gclound namespace", readonly = true) + public String getNamespace() { return _namespace; } - - @ManagedAttribute(value="unit in ms of exponential backoff") - public int getBackoffMs () + + @ManagedAttribute(value = "unit in ms of exponential backoff") + public int getBackoffMs() { return _backoff; } - - - public void setMaxRetries (int retries) + + public void setMaxRetries(int retries) { _maxRetries = retries; } - - @ManagedAttribute(value="max number of retries for failed writes") - public int getMaxRetries () + + @ManagedAttribute(value = "max number of retries for failed writes") + public int getMaxRetries() { return _maxRetries; } - /** - * @see org.eclipse.jetty.server.session.AbstractSessionDataStore#doStart() - */ @Override protected void doStart() throws Exception { @@ -454,21 +449,18 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore if (_model == null) { _model = new EntityDataModel(); - addBean(_model,true); + addBean(_model, true); } - _keyFactory = _datastore.newKeyFactory().setKind(_model.getKind()); - + _keyFactory = _datastore.newKeyFactory().setKind(_model.getKind()); + _indexesPresent = checkIndexes(); if (!_indexesPresent) LOG.warn("Session indexes not uploaded, falling back to less efficient queries"); - + super.doStart(); } - /** - * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStop() - */ @Override protected void doStop() throws Exception { @@ -478,20 +470,19 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore if (!_modelProvided) _model = null; } - - public void setDatastore (Datastore datastore) + + public void setDatastore(Datastore datastore) { _datastore = datastore; _dsProvided = true; } - - @ManagedAttribute(value="max number of results to return from gcloud searches") + + @ManagedAttribute(value = "max number of results to return from gcloud searches") public int getMaxResults() { return _maxResults; } - public void setMaxResults(int maxResults) { if (_maxResults <= 0) @@ -499,23 +490,20 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore else _maxResults = maxResults; } - - - - /** - * @see org.eclipse.jetty.server.session.SessionDataStore#load(java.lang.String) - */ + @Override - public SessionData load(String id) throws Exception + public SessionData doLoad(String id) throws Exception { - if (LOG.isDebugEnabled()) LOG.debug("Loading session {} from DataStore", id); + if (LOG.isDebugEnabled()) + LOG.debug("Loading session {} from DataStore", id); try { Entity entity = _datastore.get(makeKey(id, _context)); if (entity == null) { - if (LOG.isDebugEnabled()) LOG.debug("No session {} in DataStore ", id); + if (LOG.isDebugEnabled()) + LOG.debug("No session {} in DataStore ", id); return null; } else @@ -529,20 +517,15 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore } } - /** - * @see org.eclipse.jetty.server.session.SessionDataStore#delete(java.lang.String) - */ @Override public boolean delete(String id) throws Exception { - if (LOG.isDebugEnabled()) LOG.debug("Removing session {} from DataStore", id); + if (LOG.isDebugEnabled()) + LOG.debug("Removing session {} from DataStore", id); _datastore.delete(makeKey(id, _context)); return true; } - /** - * @see org.eclipse.jetty.server.session.SessionDataStore#getExpired(Set) - */ @Override public Set doGetExpired(Set candidates) { @@ -550,14 +533,14 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore Set expired = new HashSet(); try - { + { Set info = null; if (_indexesPresent) info = queryExpiryByIndex(); else info = queryExpiryByEntity(); - - for (ExpiryInfo item:info) + + for (ExpiryInfo item : info) { if (StringUtil.isBlank(item.getLastNode())) { @@ -576,7 +559,8 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore //our first check, just look for sessions that we managed by another node that //expired at least 3 graceperiods ago if (item.getExpiry() < (now - (1000L * (3 * _gracePeriodSec)))) - expired.add(item.getId()); } + expired.add(item.getId()); + } else { //another node was last managing it, only expire it if it expired a graceperiod ago @@ -589,22 +573,22 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore //reconcile against ids that the SessionCache thinks are expired Set tmp = new HashSet(candidates); - tmp.removeAll(expired); + tmp.removeAll(expired); if (!tmp.isEmpty()) { //sessionstore thinks these are expired, but they are either no //longer in the db or not expired in the db, or we exceeded the //number of records retrieved by the expiry query, so check them //individually - for (String s:tmp) + for (String s : tmp) { try { Query q = Query.newKeyQueryBuilder() - .setKind(_model.getKind()) - .setFilter(PropertyFilter.eq(_model.getId(), s)) - .build(); - QueryResults res = _datastore.run(q); + .setKind(_model.getKind()) + .setFilter(PropertyFilter.eq(_model.getId(), s)) + .build(); + QueryResults res = _datastore.run(q); if (!res.hasNext()) expired.add(s); //not in db, can be expired } @@ -622,70 +606,70 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore LOG.warn(e); return expired; //return what we got } - } - /** * A less efficient query to find sessions whose expiry time has passed: * retrieves the whole Entity. - * @return set of ExpiryInfo representing the id, lastNode and expiry time of + * + * @return set of ExpiryInfo representing the id, lastNode and expiry time of * sessions that are expired * @throws Exception if datastore experiences a problem */ - protected Set queryExpiryByEntity () throws Exception + protected Set queryExpiryByEntity() throws Exception { Set info = new HashSet<>(); //get up to maxResult number of sessions that have expired Query query = Query.newEntityQueryBuilder() - .setKind(_model.getKind()) - .setFilter(CompositeFilter.and(PropertyFilter.gt(_model.getExpiry(), 0), PropertyFilter.le(_model.getExpiry(), System.currentTimeMillis()))) - .setLimit(_maxResults) - .build(); + .setKind(_model.getKind()) + .setFilter(CompositeFilter.and(PropertyFilter.gt(_model.getExpiry(), 0), PropertyFilter.le(_model.getExpiry(), System.currentTimeMillis()))) + .setLimit(_maxResults) + .build(); QueryResults results; if (LOG.isDebugEnabled()) { long start = System.currentTimeMillis(); results = _datastore.run(query); - LOG.debug("Expiry query no index in {}ms", System.currentTimeMillis()-start); + LOG.debug("Expiry query no index in {}ms", System.currentTimeMillis() - start); } else results = _datastore.run(query); while (results.hasNext()) { Entity entity = results.next(); - info.add(new ExpiryInfo(entity.getString(_model.getId()),entity.getString(_model.getLastNode()), entity.getLong(_model.getExpiry()))); + info.add(new ExpiryInfo(entity.getString(_model.getId()), entity.getString(_model.getLastNode()), entity.getLong(_model.getExpiry()))); } return info; } - - /** An efficient query to find sessions whose expiry time has passed: + /** + * An efficient query to find sessions whose expiry time has passed: * uses a projection query, which requires indexes to be uploaded. - * @return id,lastnode and expiry time of sessions that have expired + * + * @return id, lastnode and expiry time of sessions that have expired * @throws Exception if datastore experiences a problem */ - protected Set queryExpiryByIndex () throws Exception + protected Set queryExpiryByIndex() throws Exception { long now = System.currentTimeMillis(); Set info = new HashSet<>(); Query query = Query.newProjectionEntityQueryBuilder() - .setKind(_model.getKind()) - .setProjection(_model.getId(), _model.getLastNode(), _model.getExpiry()) - .setFilter(CompositeFilter.and(PropertyFilter.gt(_model.getExpiry(), 0), PropertyFilter.le(_model.getExpiry(), now))) - .setLimit(_maxResults) - .build(); + .setKind(_model.getKind()) + .setProjection(_model.getId(), _model.getLastNode(), _model.getExpiry()) + .setFilter(CompositeFilter.and(PropertyFilter.gt(_model.getExpiry(), 0), PropertyFilter.le(_model.getExpiry(), now))) + .setLimit(_maxResults) + .build(); QueryResults presults; - + if (LOG.isDebugEnabled()) { long start = System.currentTimeMillis(); presults = _datastore.run(query); - LOG.debug("Expiry query by index in {}ms", System.currentTimeMillis()-start); + LOG.debug("Expiry query by index in {}ms", System.currentTimeMillis() - start); } else presults = _datastore.run(query); @@ -693,37 +677,32 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore while (presults.hasNext()) { ProjectionEntity pe = presults.next(); - info.add(new ExpiryInfo(pe.getString(_model.getId()),pe.getString(_model.getLastNode()), pe.getLong(_model.getExpiry()))); + info.add(new ExpiryInfo(pe.getString(_model.getId()), pe.getString(_model.getLastNode()), pe.getLong(_model.getExpiry()))); } return info; } - - - /** - * @see org.eclipse.jetty.server.session.SessionDataStore#exists(java.lang.String) - */ @Override public boolean exists(String id) throws Exception { if (_indexesPresent) { Query query = Query.newProjectionEntityQueryBuilder() - .setKind(_model.getKind()) - .setProjection(_model.getExpiry()) - .setFilter(CompositeFilter.and(PropertyFilter.eq(_model.getId(), id), - PropertyFilter.eq(_model.getContextPath(), _context.getCanonicalContextPath()), - PropertyFilter.eq(_model.getVhost(), _context.getVhost()))) - //.setFilter(PropertyFilter.eq(_model.getId(), id)) - .build(); + .setKind(_model.getKind()) + .setProjection(_model.getExpiry()) + .setFilter(CompositeFilter.and(PropertyFilter.eq(_model.getId(), id), + PropertyFilter.eq(_model.getContextPath(), _context.getCanonicalContextPath()), + PropertyFilter.eq(_model.getVhost(), _context.getVhost()))) + //.setFilter(PropertyFilter.eq(_model.getId(), id)) + .build(); QueryResults presults; if (LOG.isDebugEnabled()) { long start = System.currentTimeMillis(); presults = _datastore.run(query); - LOG.debug("Exists query by index in {}ms", System.currentTimeMillis()-start); + LOG.debug("Exists query by index in {}ms", System.currentTimeMillis() - start); } else presults = _datastore.run(query); @@ -739,23 +718,23 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore else { Query query = Query.newEntityQueryBuilder() - .setKind(_model.getKind()) - .setFilter(CompositeFilter.and(PropertyFilter.eq(_model.getId(), id), - PropertyFilter.eq(_model.getContextPath(), _context.getCanonicalContextPath()), - PropertyFilter.eq(_model.getVhost(), _context.getVhost()))) - //.setFilter(PropertyFilter.eq(_model.getId(), id)) - .build(); - + .setKind(_model.getKind()) + .setFilter(CompositeFilter.and(PropertyFilter.eq(_model.getId(), id), + PropertyFilter.eq(_model.getContextPath(), _context.getCanonicalContextPath()), + PropertyFilter.eq(_model.getVhost(), _context.getVhost()))) + //.setFilter(PropertyFilter.eq(_model.getId(), id)) + .build(); + QueryResults results; if (LOG.isDebugEnabled()) { long start = System.currentTimeMillis(); results = _datastore.run(query); - LOG.debug("Exists query no index in {}ms", System.currentTimeMillis()-start); + LOG.debug("Exists query no index in {}ms", System.currentTimeMillis() - start); } else results = _datastore.run(query); - + if (results.hasNext()) { Entity entity = results.next(); @@ -765,28 +744,26 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore return false; } } - + /** * Check to see if the given time is in the past. - * + * * @param timestamp the time to check * @return false if the timestamp is 0 or less, true if it is in the past */ - protected boolean isExpired (long timestamp) + protected boolean isExpired(long timestamp) { if (timestamp <= 0) return false; - else - return timestamp < System.currentTimeMillis(); + else + return timestamp < System.currentTimeMillis(); } - /** - * @see org.eclipse.jetty.server.session.AbstractSessionDataStore#doStore(java.lang.String, org.eclipse.jetty.server.session.SessionData, long) - */ @Override public void doStore(String id, SessionData data, long lastSaveTime) throws Exception { - if (LOG.isDebugEnabled()) LOG.debug("Writing session {} to DataStore", data.getId()); + if (LOG.isDebugEnabled()) + LOG.debug("Writing session {} to DataStore", data.getId()); Entity entity = entityFromSession(data, makeKey(id, _context)); //attempt the update with exponential back-off @@ -803,24 +780,25 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore { if (e.isRetryable()) { - if (LOG.isDebugEnabled()) LOG.debug("Datastore put retry {} waiting {}ms", attempts, backoff); - + if (LOG.isDebugEnabled()) + LOG.debug("Datastore put retry {} waiting {}ms", attempts, backoff); + try { - Thread.currentThread().sleep(backoff); + Thread.sleep(backoff); } - catch (InterruptedException x) + catch (InterruptedException ignored) { } backoff *= 2; } else { - throw e; + throw e; } } } - + //retries have been exceeded throw new UnwriteableSessionDataException(id, _context, null); } @@ -834,22 +812,21 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore *

    13. the context path
    14. *
    15. the virtual hosts
    16. * - * * * @param id the id * @param context the session context * @return the key */ - protected Key makeKey (String id, SessionContext context) + protected Key makeKey(String id, SessionContext context) { - String key = context.getCanonicalContextPath()+"_"+context.getVhost()+"_"+id; + String key = context.getCanonicalContextPath() + "_" + context.getVhost() + "_" + id; return _keyFactory.newKey(key); } - /** * Check to see if indexes are available, in which case * we can do more performant queries. + * * @return true if indexes are available */ protected boolean checkIndexes() @@ -857,10 +834,10 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore try { Query query = Query.newProjectionEntityQueryBuilder() - .setKind(_model.getKind()) - .setProjection(_model.getExpiry()) - .setFilter(PropertyFilter.eq(_model.getId(), "-")) - .build(); + .setKind(_model.getKind()) + .setProjection(_model.getExpiry()) + .setFilter(PropertyFilter.eq(_model.getId(), "-")) + .build(); _datastore.run(query); return true; } @@ -874,28 +851,30 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore return false; } } + /** * Generate a gcloud datastore Entity from SessionData + * * @param session the session data * @param key the key * @return the entity * @throws Exception if there is a deserialization error */ - protected Entity entityFromSession (SessionData session, Key key) throws Exception + protected Entity entityFromSession(SessionData session, Key key) throws Exception { if (session == null) return null; - + Entity entity = null; - + //serialize the attribute map - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream oos = new ObjectOutputStream(baos); - oos.writeObject(session.getAllAttributes()); - oos.flush(); - - //turn a session into an entity - entity = Entity.newBuilder(key) + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos)) + { + SessionData.serializeAttributes(session, oos); + + //turn a session into an entity + entity = Entity.newBuilder(key) .set(_model.getId(), session.getId()) .set(_model.getContextPath(), session.getContextPath()) .set(_model.getVhost(), session.getVhost()) @@ -903,116 +882,80 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore .set(_model.getLastAccessed(), session.getLastAccessed()) .set(_model.getCreateTime(), session.getCreated()) .set(_model.getCookieSetTime(), session.getCookieSet()) - .set(_model.getLastNode(),session.getLastNode()) + .set(_model.getLastNode(), session.getLastNode()) .set(_model.getExpiry(), session.getExpiry()) .set(_model.getMaxInactive(), session.getMaxInactiveMs()) .set(_model.getLastSaved(), session.getLastSaved()) .set(_model.getAttributes(), BlobValue.newBuilder(Blob.copyFrom(baos.toByteArray())).setExcludeFromIndexes(true).build()).build(); - - - return entity; + return entity; + } } - + /** * Generate SessionData from an Entity retrieved from gcloud datastore. + * * @param entity the entity * @return the session data * @throws Exception if unable to get the entity */ - protected SessionData sessionFromEntity (Entity entity) throws Exception + protected SessionData sessionFromEntity(Entity entity) throws Exception { if (entity == null) return null; - final AtomicReference reference = new AtomicReference<>(); - final AtomicReference exception = new AtomicReference<>(); - Runnable load = new Runnable() - { - @Override - public void run () - { - try - { - //turn an Entity into a Session - String id = entity.getString(_model.getId()); - String contextPath = entity.getString(_model.getContextPath()); - String vhost = entity.getString(_model.getVhost()); - long accessed = entity.getLong(_model.getAccessed()); - long lastAccessed = entity.getLong(_model.getLastAccessed()); - long createTime = entity.getLong(_model.getCreateTime()); - long cookieSet = entity.getLong(_model.getCookieSetTime()); - String lastNode = entity.getString(_model.getLastNode()); + //turn an Entity into a Session + String id = entity.getString(_model.getId()); + String contextPath = entity.getString(_model.getContextPath()); + String vhost = entity.getString(_model.getVhost()); + long accessed = entity.getLong(_model.getAccessed()); + long lastAccessed = entity.getLong(_model.getLastAccessed()); + long createTime = entity.getLong(_model.getCreateTime()); + long cookieSet = entity.getLong(_model.getCookieSetTime()); + String lastNode = entity.getString(_model.getLastNode()); - long lastSaved = 0; - //for compatibility with previously saved sessions, lastSaved may not be present - try - { - lastSaved = entity.getLong(_model.getLastSaved()); - } - catch (DatastoreException e) - { - LOG.ignore(e); - } - long expiry = entity.getLong(_model.getExpiry()); - long maxInactive = entity.getLong(_model.getMaxInactive()); - Blob blob = (Blob) entity.getBlob(_model.getAttributes()); - - SessionData session = newSessionData (id, createTime, accessed, lastAccessed, maxInactive); - session.setLastNode(lastNode); - session.setContextPath(contextPath); - session.setVhost(vhost); - session.setCookieSet(cookieSet); - session.setLastNode(lastNode); - session.setLastSaved(lastSaved); - session.setExpiry(expiry); - try (ClassLoadingObjectInputStream ois = new ClassLoadingObjectInputStream(blob.asInputStream())) - { - Object o = ois.readObject(); - session.putAllAttributes((Map)o); - } - catch (Exception e) - { - throw new UnreadableSessionDataException (id, _context, e); - } - reference.set(session); - } - catch (Exception e) - { - exception.set(e); - } - } - }; - - //ensure this runs in the context classloader - _context.run(load); - - if (exception.get() != null) + long lastSaved = 0; + //for compatibility with previously saved sessions, lastSaved may not be present + try { - throw exception.get(); + lastSaved = entity.getLong(_model.getLastSaved()); } - - return reference.get(); + catch (DatastoreException e) + { + LOG.ignore(e); + } + long expiry = entity.getLong(_model.getExpiry()); + long maxInactive = entity.getLong(_model.getMaxInactive()); + Blob blob = entity.getBlob(_model.getAttributes()); + + SessionData session = newSessionData(id, createTime, accessed, lastAccessed, maxInactive); + session.setLastNode(lastNode); + session.setContextPath(contextPath); + session.setVhost(vhost); + session.setCookieSet(cookieSet); + session.setLastNode(lastNode); + session.setLastSaved(lastSaved); + session.setExpiry(expiry); + try (ClassLoadingObjectInputStream ois = new ClassLoadingObjectInputStream(blob.asInputStream())) + { + SessionData.deserializeAttributes(session, ois); + } + catch (Exception e) + { + throw new UnreadableSessionDataException(id, _context, e); + } + return session; } - /** - * @see org.eclipse.jetty.server.session.SessionDataStore#isPassivating() - */ - @ManagedAttribute(value="does gcloud serialize session data", readonly=true) + @ManagedAttribute(value = "does gcloud serialize session data", readonly = true) @Override public boolean isPassivating() { - return true; + return true; } - - /** - * @see org.eclipse.jetty.server.session.AbstractSessionDataStore#toString() - */ @Override public String toString() { - return String.format("%s[namespace=%s,backoff=%d,maxRetries=%d,maxResults=%d,indexes=%b]",super.toString(), _namespace, _backoff, _maxRetries, _maxResults,_indexesPresent); + return String.format("%s[namespace=%s,backoff=%d,maxRetries=%d,maxResults=%d,indexes=%b]", super.toString(), _namespace, _backoff, _maxRetries, _maxResults, _indexesPresent); } - - } diff --git a/jetty-gcloud/jetty-gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudSessionDataStoreFactory.java b/jetty-gcloud/jetty-gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudSessionDataStoreFactory.java index ad65d3e8d29..d4743b7af6d 100644 --- a/jetty-gcloud/jetty-gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudSessionDataStoreFactory.java +++ b/jetty-gcloud/jetty-gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudSessionDataStoreFactory.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,7 +16,6 @@ // ======================================================================== // - package org.eclipse.jetty.gcloud.session; import org.eclipse.jetty.server.session.AbstractSessionDataStoreFactory; @@ -25,8 +24,6 @@ import org.eclipse.jetty.server.session.SessionHandler; /** * GCloudSessionDataStoreFactory - * - * */ public class GCloudSessionDataStoreFactory extends AbstractSessionDataStoreFactory { @@ -34,13 +31,12 @@ public class GCloudSessionDataStoreFactory extends AbstractSessionDataStoreFacto private int _maxRetries; private int _backoffMs; private GCloudSessionDataStore.EntityDataModel _model; - - + public GCloudSessionDataStore.EntityDataModel getEntityDataModel() { return _model; } - + public void setEntityDataModel(GCloudSessionDataStore.EntityDataModel model) { _model = model; @@ -66,7 +62,6 @@ public class GCloudSessionDataStoreFactory extends AbstractSessionDataStoreFacto _backoffMs = backoffMs; } - /** * @return the namespace */ @@ -83,7 +78,7 @@ public class GCloudSessionDataStoreFactory extends AbstractSessionDataStoreFacto _namespace = namespace; } - /** + /** * @see org.eclipse.jetty.server.session.SessionDataStoreFactory#getSessionDataStore(org.eclipse.jetty.server.session.SessionHandler) */ @Override @@ -97,5 +92,4 @@ public class GCloudSessionDataStoreFactory extends AbstractSessionDataStoreFacto ds.setSavePeriodSec(getSavePeriodSec()); return ds; } - } diff --git a/jetty-gcloud/jetty-gcloud-session-manager/src/test/java/org/eclipse/jetty/gcloud/session/GCloudSessionTester.java b/jetty-gcloud/jetty-gcloud-session-manager/src/test/java/org/eclipse/jetty/gcloud/session/GCloudSessionTester.java index 6d50d76ae1c..b132a76511d 100644 --- a/jetty-gcloud/jetty-gcloud-session-manager/src/test/java/org/eclipse/jetty/gcloud/session/GCloudSessionTester.java +++ b/jetty-gcloud/jetty-gcloud-session-manager/src/test/java/org/eclipse/jetty/gcloud/session/GCloudSessionTester.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,38 +18,32 @@ package org.eclipse.jetty.gcloud.session; - - - import org.eclipse.jetty.security.HashLoginService; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.AllowSymLinkAliasChecker; -import org.eclipse.jetty.server.session.DefaultSessionIdManager; import org.eclipse.jetty.server.session.DefaultSessionCache; -import org.eclipse.jetty.server.session.SessionHandler; +import org.eclipse.jetty.server.session.DefaultSessionIdManager; import org.eclipse.jetty.webapp.WebAppContext; public class GCloudSessionTester { - public static void main( String[] args ) throws Exception + public static void main(String[] args) throws Exception { if (args.length < 4) System.err.println("Usage: GCloudSessionTester projectid p12file password serviceaccount"); - + System.setProperty("org.eclipse.jetty.server.session.LEVEL", "DEBUG"); - + Server server = new Server(8080); HashLoginService loginService = new HashLoginService(); - loginService.setName( "Test Realm" ); - loginService.setConfig( "../../jetty-distribution/target/distribution/demo-base/resources/realm.properties" ); - server.addBean( loginService ); - + loginService.setName("Test Realm"); + loginService.setConfig("../../jetty-distribution/target/distribution/demo-base/resources/realm.properties"); + server.addBean(loginService); DefaultSessionIdManager idmgr = new DefaultSessionIdManager(server); idmgr.setWorkerName("w1"); server.setSessionIdManager(idmgr); - WebAppContext webapp = new WebAppContext(); webapp.setContextPath("/"); webapp.setWar("../../jetty-distribution/target/distribution/demo-base/webapps/test.war"); @@ -68,7 +62,6 @@ public class GCloudSessionTester // Start things up! server.start(); - server.join(); } } diff --git a/jetty-gcloud/pom.xml b/jetty-gcloud/pom.xml index c0d7c073302..4ca2ca54e49 100644 --- a/jetty-gcloud/pom.xml +++ b/jetty-gcloud/pom.xml @@ -3,7 +3,7 @@ jetty-project org.eclipse.jetty - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 diff --git a/jetty-hazelcast/pom.xml b/jetty-hazelcast/pom.xml index ce9f253094d..61e36991ab2 100644 --- a/jetty-hazelcast/pom.xml +++ b/jetty-hazelcast/pom.xml @@ -1,10 +1,9 @@ - + org.eclipse.jetty jetty-project - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 @@ -12,7 +11,7 @@ Jetty :: Hazelcast Session Manager - 3.9.3 + 3.9.4 ${project.groupId}.hazelcast @@ -22,6 +21,7 @@ hazelcast ${hazelcast.version} test-jar + test com.hazelcast diff --git a/jetty-hazelcast/src/main/config/etc/sessions/hazelcast/default.xml b/jetty-hazelcast/src/main/config/etc/sessions/hazelcast/default.xml index 680e6f07d3f..57a40b146c9 100644 --- a/jetty-hazelcast/src/main/config/etc/sessions/hazelcast/default.xml +++ b/jetty-hazelcast/src/main/config/etc/sessions/hazelcast/default.xml @@ -1,5 +1,4 @@ - - + @@ -13,6 +12,7 @@ + diff --git a/jetty-hazelcast/src/main/config/etc/sessions/hazelcast/remote.xml b/jetty-hazelcast/src/main/config/etc/sessions/hazelcast/remote.xml index ca32fcff21d..96588eab19f 100644 --- a/jetty-hazelcast/src/main/config/etc/sessions/hazelcast/remote.xml +++ b/jetty-hazelcast/src/main/config/etc/sessions/hazelcast/remote.xml @@ -1,5 +1,4 @@ - - + @@ -12,6 +11,7 @@ + diff --git a/jetty-hazelcast/src/main/config/modules/hazelcast-embedded-sessions.mod b/jetty-hazelcast/src/main/config/modules/hazelcast-embedded-sessions.mod deleted file mode 100644 index 139fe8ff81e..00000000000 --- a/jetty-hazelcast/src/main/config/modules/hazelcast-embedded-sessions.mod +++ /dev/null @@ -1,26 +0,0 @@ -# -# Jetty Hazelcast module -# - -[depend] -annotations -webapp - -[files] -maven://com.hazelcast/hazelcast-all/3.8.2|lib/hazelcast/hazelcast-all-3.8.2.jar -maven://com.hazelcast/hazelcast-jetty9-sessionmanager/1.0.2|lib/hazelcast/hazelcast-jetty9-sessionmanager-1.0.2.jar -maven://org.eclipse.jetty/jetty-nosql/${jetty.version}|lib/hazelcast/jetty-nosql-${jetty.version}.jar - -[xml] -etc/sessions/hazelcast/default.xml - -[lib] -lib/hazelcast/*.jar - -[license] -Hazelcast is an open source project hosted on Github and released under the Apache 2.0 license. -https://hazelcast.org/ -http://www.apache.org/licenses/LICENSE-2.0.html - -[ini-template] -#jetty.session.hazelcast.configurationLocation= diff --git a/jetty-hazelcast/src/main/config/modules/hazelcast-remote-sessions.mod b/jetty-hazelcast/src/main/config/modules/hazelcast-remote-sessions.mod deleted file mode 100644 index 5038684659d..00000000000 --- a/jetty-hazelcast/src/main/config/modules/hazelcast-remote-sessions.mod +++ /dev/null @@ -1,26 +0,0 @@ -# -# Jetty Hazelcast module -# - -[depend] -annotations -webapp - -[files] -maven://com.hazelcast/hazelcast-all/3.8.2|lib/hazelcast/hazelcast-all-3.8.2.jar -maven://com.hazelcast/hazelcast-jetty9-sessionmanager/1.0.2|lib/hazelcast/hazelcast-jetty9-sessionmanager-1.0.2.jar -maven://org.eclipse.jetty/jetty-nosql/${jetty.version}|lib/hazelcast/jetty-nosql-${jetty.version}.jar - -[xml] -etc/sessions/hazelcast/remote.xml - -[lib] -lib/hazelcast/*.jar - -[license] -Hazelcast is an open source project hosted on Github and released under the Apache 2.0 license. -https://hazelcast.org/ -http://www.apache.org/licenses/LICENSE-2.0.html - -[ini-template] -#jetty.session.hazelcast.configurationLocation= diff --git a/jetty-hazelcast/src/main/config/modules/session-store-hazelcast-embedded.mod b/jetty-hazelcast/src/main/config/modules/session-store-hazelcast-embedded.mod index 2263ae0807b..374493bc509 100644 --- a/jetty-hazelcast/src/main/config/modules/session-store-hazelcast-embedded.mod +++ b/jetty-hazelcast/src/main/config/modules/session-store-hazelcast-embedded.mod @@ -13,7 +13,7 @@ session-store sessions [files] -maven://com.hazelcast/hazelcast/3.8.2|lib/hazelcast/hazelcast-3.8.2.jar +maven://com.hazelcast/hazelcast/3.9.4|lib/hazelcast/hazelcast-3.9.4.jar [xml] etc/sessions/hazelcast/default.xml @@ -32,5 +32,6 @@ http://www.apache.org/licenses/LICENSE-2.0.html jetty.session.hazelcast.mapName=jetty-distributed-session-map jetty.session.hazelcast.hazelcastInstanceName=JETTY_DISTRIBUTED_SESSION_INSTANCE #jetty.session.hazelcast.configurationLocation= +jetty.session.hazelcast.scavengeZombies=false jetty.session.gracePeriod.seconds=3600 -jetty.session.savePeriod.seconds=0 \ No newline at end of file +jetty.session.savePeriod.seconds=0 diff --git a/jetty-hazelcast/src/main/config/modules/session-store-hazelcast-remote.mod b/jetty-hazelcast/src/main/config/modules/session-store-hazelcast-remote.mod index c6a26fc7123..3796bef5924 100644 --- a/jetty-hazelcast/src/main/config/modules/session-store-hazelcast-remote.mod +++ b/jetty-hazelcast/src/main/config/modules/session-store-hazelcast-remote.mod @@ -13,8 +13,8 @@ session-store sessions [files] -maven://com.hazelcast/hazelcast/3.8.2|lib/hazelcast/hazelcast-3.8.2.jar -maven://com.hazelcast/hazelcast-client/3.8.2|lib/hazelcast/hazelcast-client-3.8.2.jar +maven://com.hazelcast/hazelcast/3.9.4|lib/hazelcast/hazelcast-3.9.4.jar +maven://com.hazelcast/hazelcast-client/3.9.4|lib/hazelcast/hazelcast-client-3.9.4.jar [xml] etc/sessions/hazelcast/remote.xml @@ -33,6 +33,7 @@ http://www.apache.org/licenses/LICENSE-2.0.html jetty.session.hazelcast.mapName=jetty-distributed-session-map jetty.session.hazelcast.hazelcastInstanceName=JETTY_DISTRIBUTED_SESSION_INSTANCE jetty.session.hazelcast.onlyClient=true +jetty.session.hazelcast.scavengeZombies=false #jetty.session.hazelcast.configurationLocation= jetty.session.gracePeriod.seconds=3600 -jetty.session.savePeriod.seconds=0 \ No newline at end of file +jetty.session.savePeriod.seconds=0 diff --git a/jetty-hazelcast/src/main/java/org/eclipse/jetty/hazelcast/session/HazelcastSessionDataStore.java b/jetty-hazelcast/src/main/java/org/eclipse/jetty/hazelcast/session/HazelcastSessionDataStore.java index 26ff7c7f30c..8e2d32c1906 100644 --- a/jetty-hazelcast/src/main/java/org/eclipse/jetty/hazelcast/session/HazelcastSessionDataStore.java +++ b/jetty-hazelcast/src/main/java/org/eclipse/jetty/hazelcast/session/HazelcastSessionDataStore.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,7 +18,16 @@ package org.eclipse.jetty.hazelcast.session; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; + import com.hazelcast.core.IMap; +import com.hazelcast.query.EntryObject; +import com.hazelcast.query.Predicate; +import com.hazelcast.query.PredicateBuilder; import org.eclipse.jetty.server.session.AbstractSessionDataStore; import org.eclipse.jetty.server.session.SessionContext; import org.eclipse.jetty.server.session.SessionData; @@ -28,11 +37,6 @@ import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import java.util.Collections; -import java.util.Set; -import java.util.concurrent.atomic.AtomicReference; -import java.util.stream.Collectors; - /** * Session data stored in Hazelcast */ @@ -42,51 +46,70 @@ public class HazelcastSessionDataStore implements SessionDataStore { - private final static Logger LOG = Log.getLogger( "org.eclipse.jetty.server.session"); + private static final Logger LOG = Log.getLogger("org.eclipse.jetty.server.session"); private IMap sessionDataMap; + private boolean _scavengeZombies; + public HazelcastSessionDataStore() { - // no op + } + + /** + * Control whether or not to execute queries to find + * "zombie" sessions - ie sessions that are no longer + * actively referenced by any jetty instance and should + * be expired. + * + * If you use this feature, be aware that if your session + * stores any attributes that use classes from within your + * webapp, or from within jetty, you will need to make sure + * those classes are available to all of your hazelcast + * instances, whether embedded or remote. + * + * @param scavengeZombies true means unreferenced sessions + * will be actively sought and expired. False means that they + * will remain in hazelcast until some other mechanism removes them. + */ + public void setScavengeZombieSessions(boolean scavengeZombies) + { + _scavengeZombies = scavengeZombies; + } + + public boolean isScavengeZombies() + { + return _scavengeZombies; } @Override - public SessionData load( String id ) + public SessionData doLoad(String id) throws Exception { - - final AtomicReference reference = new AtomicReference<>(); - final AtomicReference exception = new AtomicReference<>(); - - //ensure the load runs in the context classloader scope - _context.run( () -> { - try - { - if (LOG.isDebugEnabled()) - LOG.debug( "Loading session {} from hazelcast", id ); - - SessionData sd = sessionDataMap.get( getCacheKey( id ) ); - reference.set(sd); - } - catch (Exception e) - { - exception.set(new UnreadableSessionDataException(id, _context, e)); - } - } ); - - if (exception.get() != null) + try { - throw exception.get(); + if (LOG.isDebugEnabled()) + LOG.debug("Loading session {} from hazelcast", id); + + SessionData sd = sessionDataMap.get(getCacheKey(id)); + return sd; + } + catch (Exception e) + { + throw new UnreadableSessionDataException(id, _context, e); } - return reference.get(); } @Override - public boolean delete( String id ) + public boolean delete(String id) throws Exception { - return sessionDataMap == null ? false : sessionDataMap.remove( getCacheKey( id ) ) != null; + if (sessionDataMap == null) + return false; + + //use delete which does not deserialize the SessionData object being removed + sessionDataMap.delete(getCacheKey(id)); + return true; } public IMap getSessionDataMap() @@ -94,23 +117,25 @@ public class HazelcastSessionDataStore return sessionDataMap; } - public void setSessionDataMap( IMap sessionDataMap ) + public void setSessionDataMap(IMap sessionDataMap) { this.sessionDataMap = sessionDataMap; } @Override - public void initialize( SessionContext context ) + public void initialize(SessionContext context) throws Exception { - _context = context; + super.initialize(context); + if (isScavengeZombies()) + sessionDataMap.addIndex("expiry", true); } @Override - public void doStore( String id, SessionData data, long lastSaveTime ) + public void doStore(String id, SessionData data, long lastSaveTime) throws Exception { - this.sessionDataMap.set( getCacheKey( id ), data); + this.sessionDataMap.set(getCacheKey(id), data); } @Override @@ -120,19 +145,16 @@ public class HazelcastSessionDataStore } @Override - public Set doGetExpired( Set candidates ) + public Set doGetExpired(Set candidates) { - if (candidates == null || candidates.isEmpty()) - { - return Collections.emptySet(); - } - long now = System.currentTimeMillis(); - return candidates.stream().filter( candidate -> { - + + Set expiredSessionIds = candidates.stream().filter(candidate -> + { + if (LOG.isDebugEnabled()) - LOG.debug( "Checking expiry for candidate {}", candidate ); - + LOG.debug("Checking expiry for candidate {}", candidate); + try { SessionData sd = load(candidate); @@ -142,7 +164,7 @@ public class HazelcastSessionDataStore { if (LOG.isDebugEnabled()) { - LOG.debug( "Session {} does not exist in Hazelcast", candidate ); + LOG.debug("Session {} does not exist in Hazelcast", candidate); } return true; } @@ -151,11 +173,11 @@ public class HazelcastSessionDataStore if (_context.getWorkerName().equals(sd.getLastNode())) { //we are its manager, add it to the expired set if it is expired now - if ((sd.getExpiry() > 0 ) && sd.getExpiry() <= now) + if ((sd.getExpiry() > 0) && sd.getExpiry() <= now) { if (LOG.isDebugEnabled()) { - LOG.debug( "Session {} managed by {} is expired", candidate, _context.getWorkerName() ); + LOG.debug("Session {} managed by {} is expired", candidate, _context.getWorkerName()); } return true; } @@ -166,16 +188,16 @@ public class HazelcastSessionDataStore // this is our first expiryCheck and the session expired a long time ago //or //the session expired at least one graceperiod ago - if (_lastExpiryCheckTime <=0) + if (_lastExpiryCheckTime <= 0) { - if ((sd.getExpiry() > 0 ) && sd.getExpiry() < (now - (1000L * (3 * _gracePeriodSec)))) + if ((sd.getExpiry() > 0) && sd.getExpiry() < (now - (1000L * (3 * _gracePeriodSec)))) { return true; } } else { - if ((sd.getExpiry() > 0 ) && sd.getExpiry() < (now - (1000L * _gracePeriodSec))) + if ((sd.getExpiry() > 0) && sd.getExpiry() < (now - (1000L * _gracePeriodSec))) { return true; } @@ -189,12 +211,55 @@ public class HazelcastSessionDataStore return true; } return false; - } ).collect( Collectors.toSet() ); + }).collect(Collectors.toSet()); + + if (isScavengeZombies()) + { + //Now find other sessions in hazelcast that have expired + final AtomicReference> reference = new AtomicReference<>(); + final AtomicReference exception = new AtomicReference<>(); + + _context.run(() -> + { + try + { + Set ids = new HashSet<>(); + EntryObject eo = new PredicateBuilder().getEntryObject(); + Predicate predicate = eo.get("expiry").greaterThan(0).and(eo.get("expiry").lessEqual(now)); + Collection results = sessionDataMap.values(predicate); + if (results != null) + { + for (SessionData sd : results) + { + ids.add(sd.getId()); + } + } + reference.set(ids); + } + catch (Exception e) + { + exception.set(e); + } + }); + + if (exception.get() != null) + { + LOG.warn("Error querying for expired sessions {}", exception.get()); + return expiredSessionIds; + } + + if (reference.get() != null) + { + expiredSessionIds.addAll(reference.get()); + } + } + + return expiredSessionIds; } @Override - public boolean exists( String id ) - throws Exception + public boolean exists(String id) + throws Exception { //TODO find way to do query without pulling in whole session data SessionData sd = load(id); @@ -207,7 +272,7 @@ public class HazelcastSessionDataStore return sd.getExpiry() > System.currentTimeMillis(); //not expired yet } - public String getCacheKey( String id ) + public String getCacheKey(String id) { return _context.getCanonicalContextPath() + "_" + _context.getVhost() + "_" + id; } diff --git a/jetty-hazelcast/src/main/java/org/eclipse/jetty/hazelcast/session/HazelcastSessionDataStoreFactory.java b/jetty-hazelcast/src/main/java/org/eclipse/jetty/hazelcast/session/HazelcastSessionDataStoreFactory.java index 7fce2facb04..40718c61aa1 100644 --- a/jetty-hazelcast/src/main/java/org/eclipse/jetty/hazelcast/session/HazelcastSessionDataStoreFactory.java +++ b/jetty-hazelcast/src/main/java/org/eclipse/jetty/hazelcast/session/HazelcastSessionDataStoreFactory.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,21 +18,23 @@ package org.eclipse.jetty.hazelcast.session; +import java.io.IOException; + import com.hazelcast.client.HazelcastClient; import com.hazelcast.client.config.ClientConfig; import com.hazelcast.client.config.XmlClientConfigBuilder; import com.hazelcast.config.Config; import com.hazelcast.config.MapConfig; +import com.hazelcast.config.SerializerConfig; import com.hazelcast.config.XmlConfigBuilder; import com.hazelcast.core.Hazelcast; import com.hazelcast.core.HazelcastInstance; import org.eclipse.jetty.server.session.AbstractSessionDataStoreFactory; +import org.eclipse.jetty.server.session.SessionData; import org.eclipse.jetty.server.session.SessionDataStore; import org.eclipse.jetty.server.session.SessionDataStoreFactory; import org.eclipse.jetty.server.session.SessionHandler; -import java.io.IOException; - /** * Factory to construct {@link HazelcastSessionDataStore} */ @@ -53,66 +55,86 @@ public class HazelcastSessionDataStoreFactory private MapConfig mapConfig; + private boolean scavengeZombies = false; + + public boolean isScavengeZombies() + { + return scavengeZombies; + } + + public void setScavengeZombies(boolean scavengeZombies) + { + this.scavengeZombies = scavengeZombies; + } @Override - public SessionDataStore getSessionDataStore( SessionHandler handler ) - throws Exception + public SessionDataStore getSessionDataStore(SessionHandler handler) { HazelcastSessionDataStore hazelcastSessionDataStore = new HazelcastSessionDataStore(); - if ( hazelcastInstance == null ) + if (hazelcastInstance == null) { try { - if ( onlyClient ) + if (onlyClient) { - if ( configurationLocation == null ) + if (configurationLocation == null) { - hazelcastInstance = HazelcastClient.newHazelcastClient( new ClientConfig() ); + ClientConfig config = new ClientConfig(); + SerializerConfig sc = new SerializerConfig() + .setImplementation(new SessionDataSerializer()) + .setTypeClass(SessionData.class); + config.getSerializationConfig().addSerializerConfig(sc); + hazelcastInstance = HazelcastClient.newHazelcastClient(config); } else { hazelcastInstance = HazelcastClient.newHazelcastClient( - new XmlClientConfigBuilder( configurationLocation ).build() ); + new XmlClientConfigBuilder(configurationLocation).build()); } - } else { Config config; - if ( configurationLocation == null ) + if (configurationLocation == null) { + + SerializerConfig sc = new SerializerConfig() + .setImplementation(new SessionDataSerializer()) + .setTypeClass(SessionData.class); config = new Config(); + config.getSerializationConfig().addSerializerConfig(sc); // configure a default Map if null - if ( mapConfig == null ) + if (mapConfig == null) { mapConfig = new MapConfig(); - mapConfig.setName( mapName ); + mapConfig.setName(mapName); } else { // otherwise we reuse the name mapName = mapConfig.getName(); } - config.addMapConfig( mapConfig ); + config.addMapConfig(mapConfig); } else { - config = new XmlConfigBuilder( configurationLocation ).build(); + config = new XmlConfigBuilder(configurationLocation).build(); } - config.setInstanceName( hazelcastInstanceName ); - hazelcastInstance = Hazelcast.getOrCreateHazelcastInstance( config ); + config.setInstanceName(hazelcastInstanceName); + hazelcastInstance = Hazelcast.getOrCreateHazelcastInstance(config); } } - catch ( IOException e ) + catch (IOException e) { - throw new RuntimeException( e.getMessage(), e ); + throw new RuntimeException(e.getMessage(), e); } } // initialize the map - hazelcastSessionDataStore.setSessionDataMap(hazelcastInstance.getMap( mapName ) ); - hazelcastSessionDataStore.setGracePeriodSec( getGracePeriodSec() ); - hazelcastSessionDataStore.setSavePeriodSec( getSavePeriodSec() ); + hazelcastSessionDataStore.setSessionDataMap(hazelcastInstance.getMap(mapName)); + hazelcastSessionDataStore.setGracePeriodSec(getGracePeriodSec()); + hazelcastSessionDataStore.setSavePeriodSec(getSavePeriodSec()); + hazelcastSessionDataStore.setScavengeZombieSessions(scavengeZombies); return hazelcastSessionDataStore; } @@ -122,11 +144,10 @@ public class HazelcastSessionDataStoreFactory } /** - * * @param onlyClient if true the session manager will only connect to an external Hazelcast instance - * and not use this JVM to start an Hazelcast instance + * and not use this JVM to start an Hazelcast instance */ - public void setOnlyClient( boolean onlyClient ) + public void setOnlyClient(boolean onlyClient) { this.onlyClient = onlyClient; } @@ -136,7 +157,7 @@ public class HazelcastSessionDataStoreFactory return configurationLocation; } - public void setConfigurationLocation( String configurationLocation ) + public void setConfigurationLocation(String configurationLocation) { this.configurationLocation = configurationLocation; } @@ -146,7 +167,7 @@ public class HazelcastSessionDataStoreFactory return mapName; } - public void setMapName( String mapName ) + public void setMapName(String mapName) { this.mapName = mapName; } @@ -156,7 +177,7 @@ public class HazelcastSessionDataStoreFactory return hazelcastInstance; } - public void setHazelcastInstance( HazelcastInstance hazelcastInstance ) + public void setHazelcastInstance(HazelcastInstance hazelcastInstance) { this.hazelcastInstance = hazelcastInstance; } @@ -166,7 +187,7 @@ public class HazelcastSessionDataStoreFactory return mapConfig; } - public void setMapConfig( MapConfig mapConfig ) + public void setMapConfig(MapConfig mapConfig) { this.mapConfig = mapConfig; } @@ -176,7 +197,7 @@ public class HazelcastSessionDataStoreFactory return hazelcastInstanceName; } - public void setHazelcastInstanceName( String hazelcastInstanceName ) + public void setHazelcastInstanceName(String hazelcastInstanceName) { this.hazelcastInstanceName = hazelcastInstanceName; } diff --git a/jetty-hazelcast/src/main/java/org/eclipse/jetty/hazelcast/session/SessionDataSerializer.java b/jetty-hazelcast/src/main/java/org/eclipse/jetty/hazelcast/session/SessionDataSerializer.java new file mode 100644 index 00000000000..b4b82fb96ae --- /dev/null +++ b/jetty-hazelcast/src/main/java/org/eclipse/jetty/hazelcast/session/SessionDataSerializer.java @@ -0,0 +1,108 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.hazelcast.session; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; + +import com.hazelcast.nio.ObjectDataInput; +import com.hazelcast.nio.ObjectDataOutput; +import com.hazelcast.nio.serialization.StreamSerializer; +import org.eclipse.jetty.server.session.SessionData; +import org.eclipse.jetty.util.ClassLoadingObjectInputStream; + +/** + * SessionDataSerializer + * + * Handles serialization on behalf of the SessionData object, and + * ensures that we use jetty's classloading knowledge. + */ +public class SessionDataSerializer implements StreamSerializer +{ + public static final int __TYPEID = 99; + + @Override + public int getTypeId() + { + return __TYPEID; + } + + @Override + public void destroy() + { + } + + @Override + public void write(ObjectDataOutput out, SessionData data) throws IOException + { + out.writeUTF(data.getId()); + out.writeUTF(data.getContextPath()); + out.writeUTF(data.getVhost()); + + out.writeLong(data.getAccessed()); + out.writeLong(data.getLastAccessed()); + out.writeLong(data.getCreated()); + out.writeLong(data.getCookieSet()); + out.writeUTF(data.getLastNode()); + + out.writeLong(data.getExpiry()); + out.writeLong(data.getMaxInactiveMs()); + + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos)) + { + SessionData.serializeAttributes(data, oos); + out.writeByteArray(baos.toByteArray()); + } + } + + @Override + public SessionData read(ObjectDataInput in) throws IOException + { + String id = in.readUTF(); + String contextPath = in.readUTF(); + String vhost = in.readUTF(); + + long accessed = in.readLong(); + long lastAccessed = in.readLong(); + long created = in.readLong(); + long cookieSet = in.readLong(); + String lastNode = in.readUTF(); + long expiry = in.readLong(); + long maxInactiveMs = in.readLong(); + + SessionData sd = new SessionData(id, contextPath, vhost, created, accessed, lastAccessed, maxInactiveMs); + + ByteArrayInputStream bais = new ByteArrayInputStream(in.readByteArray()); + try (ClassLoadingObjectInputStream ois = new ClassLoadingObjectInputStream(bais)) + { + SessionData.deserializeAttributes(sd, ois); + } + catch (ClassNotFoundException e) + { + throw new IOException(e); + } + sd.setCookieSet(cookieSet); + sd.setLastNode(lastNode); + sd.setExpiry(expiry); + return sd; + } +} diff --git a/jetty-hazelcast/src/test/java/org/eclipse/jetty/hazelcast/session/TestHazelcastSessions.java b/jetty-hazelcast/src/test/java/org/eclipse/jetty/hazelcast/session/TestHazelcastSessions.java index 3ba4c4f31df..641dd478007 100644 --- a/jetty-hazelcast/src/test/java/org/eclipse/jetty/hazelcast/session/TestHazelcastSessions.java +++ b/jetty-hazelcast/src/test/java/org/eclipse/jetty/hazelcast/session/TestHazelcastSessions.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,6 +18,13 @@ package org.eclipse.jetty.hazelcast.session; +import java.io.IOException; +import java.io.PrintWriter; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.api.ContentResponse; @@ -33,15 +40,9 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; -import java.io.IOException; -import java.io.PrintWriter; - -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; public class TestHazelcastSessions { @@ -50,46 +51,45 @@ public class TestHazelcastSessions { @Override - protected void doGet( HttpServletRequest req, HttpServletResponse resp ) + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - String arg = req.getParameter( "action" ); - if ( arg == null ) + String arg = req.getParameter("action"); + if (arg == null) { return; } HttpSession s = null; - if ( "set".equals( arg ) ) + if ("set".equals(arg)) { - s = req.getSession( true ); - assertNotNull( s ); - s.setAttribute( "val", req.getParameter( "value" ) ); + s = req.getSession(true); + assertNotNull(s); + s.setAttribute("val", req.getParameter("value")); } - else if ( "get".equals( arg ) ) + else if ("get".equals(arg)) { - s = req.getSession( false ); - System.err.println( "GET: s=" + s + ",id=" + (s != null ? s.getId() : "" ) ); + s = req.getSession(false); + System.err.println("GET: s=" + s + ",id=" + (s != null ? s.getId() : "")); } - else if ( "del".equals( arg ) ) + else if ("del".equals(arg)) { s = req.getSession(); - assertNotNull( s ); + assertNotNull(s); s.invalidate(); s = null; } - resp.setContentType( "text/html" ); + resp.setContentType("text/html"); PrintWriter w = resp.getWriter(); - if ( s == null ) + if (s == null) { - w.write( "No session" ); + w.write("No session"); } else { - w.write( (String) s.getAttribute( "val" ) ); + w.write((String)s.getAttribute("val")); } } - } private HazelcastSessionDataStore hazelcastSessionDataStore; @@ -107,26 +107,26 @@ public class TestHazelcastSessions { server = new Server(); - serverConnector = new ServerConnector( server, new HttpConnectionFactory() ); - server.addConnector( serverConnector ); + serverConnector = new ServerConnector(server, new HttpConnectionFactory()); + server.addConnector(serverConnector); - ServletContextHandler context = new ServletContextHandler( ServletContextHandler.SESSIONS ); - context.setContextPath( contextPath ); - context.setResourceBase( System.getProperty( "java.io.tmpdir" ) ); - server.setHandler( context ); + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath(contextPath); + context.setResourceBase(System.getProperty("java.io.tmpdir")); + server.setHandler(context); - SessionContext sessionContext = new SessionContext( "foo", null ); + SessionContext sessionContext = new SessionContext("foo", null); hazelcastSessionDataStoreFactory = new HazelcastSessionDataStoreFactory(); - hazelcastSessionDataStore = (HazelcastSessionDataStore) hazelcastSessionDataStoreFactory.getSessionDataStore( - context.getSessionHandler() ); - hazelcastSessionDataStore.initialize( sessionContext ); + hazelcastSessionDataStore = (HazelcastSessionDataStore)hazelcastSessionDataStoreFactory.getSessionDataStore( + context.getSessionHandler()); + hazelcastSessionDataStore.initialize(sessionContext); - DefaultSessionCache defaultSessionCache = new DefaultSessionCache( context.getSessionHandler() ); - defaultSessionCache.setSessionDataStore( hazelcastSessionDataStore ); - context.getSessionHandler().setSessionCache( defaultSessionCache ); + DefaultSessionCache defaultSessionCache = new DefaultSessionCache(context.getSessionHandler()); + defaultSessionCache.setSessionDataStore(hazelcastSessionDataStore); + context.getSessionHandler().setSessionCache(defaultSessionCache); // Add a test servlet - context.addServlet( new ServletHolder( new TestServlet() ), contextPath ); + context.addServlet(new ServletHolder(new TestServlet()), contextPath); server.start(); } @@ -151,47 +151,42 @@ public class TestHazelcastSessions { int value = 42; ContentResponse response = - client.GET( "http://localhost:" + port + contextPath + "?action=set&value=" + value ); - assertEquals( HttpServletResponse.SC_OK, response.getStatus() ); - String sessionCookie = response.getHeaders().get( "Set-Cookie" ); - assertTrue( sessionCookie != null ); + client.GET("http://localhost:" + port + contextPath + "?action=set&value=" + value); + assertEquals(HttpServletResponse.SC_OK, response.getStatus()); + String sessionCookie = response.getHeaders().get("Set-Cookie"); + assertTrue(sessionCookie != null); // Mangle the cookie, replacing Path with $Path, etc. - sessionCookie = sessionCookie.replaceFirst( "(\\W)(P|p)ath=", "$1\\$Path=" ); + sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); String resp = response.getContentAsString(); - assertEquals( resp.trim(), String.valueOf( value ) ); + assertEquals(resp.trim(), String.valueOf(value)); // Be sure the session value is still there - Request request = client.newRequest( "http://localhost:" + port + contextPath + "?action=get" ); - request.header( "Cookie", sessionCookie ); + Request request = client.newRequest("http://localhost:" + port + contextPath + "?action=get"); + request.header("Cookie", sessionCookie); response = request.send(); - assertEquals( HttpServletResponse.SC_OK, response.getStatus() ); + assertEquals(HttpServletResponse.SC_OK, response.getStatus()); resp = response.getContentAsString(); - assertEquals( String.valueOf( value ), resp.trim() ); + assertEquals(String.valueOf(value), resp.trim()); //Delete the session - request = client.newRequest( "http://localhost:" + port + contextPath + "?action=del" ); - request.header( "Cookie", sessionCookie ); + request = client.newRequest("http://localhost:" + port + contextPath + "?action=del"); + request.header("Cookie", sessionCookie); response = request.send(); - assertEquals( HttpServletResponse.SC_OK, response.getStatus() ); + assertEquals(HttpServletResponse.SC_OK, response.getStatus()); //Check that the session is gone - request = client.newRequest( "http://localhost:" + port + contextPath + "?action=get" ); - request.header( "Cookie", sessionCookie ); + request = client.newRequest("http://localhost:" + port + contextPath + "?action=get"); + request.header("Cookie", sessionCookie); response = request.send(); - assertEquals( HttpServletResponse.SC_OK, response.getStatus() ); + assertEquals(HttpServletResponse.SC_OK, response.getStatus()); resp = response.getContentAsString(); - assertEquals( "No session", resp.trim() ); - - - + assertEquals("No session", resp.trim()); } finally { client.stop(); } - } - } diff --git a/jetty-home/pom.xml b/jetty-home/pom.xml index c00b7b4bb6a..02201232284 100644 --- a/jetty-home/pom.xml +++ b/jetty-home/pom.xml @@ -3,7 +3,7 @@ jetty-project org.eclipse.jetty - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 jetty-home @@ -324,7 +324,7 @@ javax.annotation,org.eclipse.jetty.orbit,org.ow2.asm - javax.annotation-api,asm,asm-commons + javax.annotation-api,asm,asm-commons,asm-tree,asm-analysis jar ${assembly-directory}/lib/annotations @@ -337,7 +337,7 @@ javax.annotation,org.eclipse.jetty.orbit,org.ow2.asm - javax.annotation-api,asm,asm-commons + javax.annotation-api,asm,asm-commons,asm-tree,asm-analysis jar sources ${source-assembly-directory}/lib/annotations @@ -440,12 +440,41 @@ org.eclipse.jetty,org.eclipse.jetty.websocket + infinispan-embedded,infinispan-remote,jetty-test-helper,alpn-api,javax.security.auth.message,javax.activation config false META-INF/** ${assembly-directory} + + unpack-infinispan-config + generate-resources + + unpack + + + + + org.eclipse.jetty + infinispan-embedded + ${project.version} + config + jar + + + org.eclipse.jetty + infinispan-remote + ${project.version} + config + jar + + + true + META-INF/** + ${assembly-directory} + + @@ -547,6 +576,14 @@ org.ow2.asm asm-commons + + org.ow2.asm + asm-tree + + + org.ow2.asm + asm-analysis + @@ -636,13 +673,12 @@ ${project.version} - org.eclipse.jetty.cdi - cdi-servlet - ${project.version} + org.jboss.logging + jboss-logging - org.eclipse.jetty.cdi - cdi-2 + org.eclipse.jetty + jetty-cdi ${project.version} @@ -687,7 +723,24 @@ org.eclipse.jetty - jetty-infinispan + infinispan-embedded + ${project.version} + pom + + + org.eclipse.jetty + infinispan-embedded-query + ${project.version} + + + org.eclipse.jetty + infinispan-remote + ${project.version} + pom + + + org.eclipse.jetty + infinispan-remote-query ${project.version} diff --git a/jetty-home/src/main/resources/etc/jetty-setuid.xml b/jetty-home/src/main/resources/etc/jetty-setuid.xml index cb33a1a5429..e930973bc88 100644 --- a/jetty-home/src/main/resources/etc/jetty-setuid.xml +++ b/jetty-home/src/main/resources/etc/jetty-setuid.xml @@ -1,9 +1,6 @@ - - + - - - + diff --git a/jetty-home/src/main/resources/etc/jetty-started.xml b/jetty-home/src/main/resources/etc/jetty-started.xml index faa28395ac5..64af23e15aa 100644 --- a/jetty-home/src/main/resources/etc/jetty-started.xml +++ b/jetty-home/src/main/resources/etc/jetty-started.xml @@ -1,9 +1,6 @@ - - + - - - + diff --git a/jetty-home/src/main/resources/etc/jetty-stop.xml b/jetty-home/src/main/resources/etc/jetty-stop.xml index d63e52f23cf..efd51ac9989 100644 --- a/jetty-home/src/main/resources/etc/jetty-stop.xml +++ b/jetty-home/src/main/resources/etc/jetty-stop.xml @@ -1,5 +1,4 @@ - - + diff --git a/jetty-home/src/main/resources/modules/conscrypt.mod b/jetty-home/src/main/resources/modules/conscrypt.mod index 66bcf8d06fc..9a886357be8 100644 --- a/jetty-home/src/main/resources/modules/conscrypt.mod +++ b/jetty-home/src/main/resources/modules/conscrypt.mod @@ -29,6 +29,6 @@ Conscrypt is distributed under the Apache Licence 2.0 https://github.com/google/conscrypt/blob/master/LICENSE [ini] -conscrypt.version?=1.1.4 +conscrypt.version?=2.0.0 jetty.sslContext.provider?=Conscrypt diff --git a/jetty-home/src/main/resources/modules/conscrypt/conscrypt.xml b/jetty-home/src/main/resources/modules/conscrypt/conscrypt.xml index f3c69bd0953..cd39f281cda 100644 --- a/jetty-home/src/main/resources/modules/conscrypt/conscrypt.xml +++ b/jetty-home/src/main/resources/modules/conscrypt/conscrypt.xml @@ -1,5 +1,4 @@ - - + diff --git a/jetty-home/src/main/resources/modules/deprecated.properties b/jetty-home/src/main/resources/modules/deprecated.properties index 977bd893a5f..0daf7bed58d 100644 --- a/jetty-home/src/main/resources/modules/deprecated.properties +++ b/jetty-home/src/main/resources/modules/deprecated.properties @@ -1,8 +1,8 @@ -gcloud-memcached-sessions : replaced by 'session-store-cache,session-store-gcloud' -gcloud-session-idmgr : no longer required -gcloud-sessions : replaced by 'session-store-gcloud' -infinispan : replaced by either 'session-store-infinispan-embedded' or 'session-store-infinispan-remote' -jdbc-sessions : replaced by 'session-store-jdbc' -logging : replaced by 'console-capture' -monitor : no longer supported -nosql : replaced by 'session-store-mongo' +gcloud-memcached-sessions = replaced by 'session-store-cache,session-store-gcloud' +gcloud-session-idmgr = no longer required +gcloud-sessions = replaced by 'session-store-gcloud' +infinispan = replaced by either 'session-store-infinispan-embedded' or 'session-store-infinispan-remote' +jdbc-sessions = replaced by 'session-store-jdbc' +logging = replaced by 'console-capture' +monitor = no longer supported +nosql = replaced by 'session-store-mongo' diff --git a/jetty-home/src/main/resources/modules/hawtio/hawtio.xml b/jetty-home/src/main/resources/modules/hawtio/hawtio.xml index cc87fce9879..8c0a970610e 100644 --- a/jetty-home/src/main/resources/modules/hawtio/hawtio.xml +++ b/jetty-home/src/main/resources/modules/hawtio/hawtio.xml @@ -1,5 +1,4 @@ - - + diff --git a/jetty-home/src/main/resources/modules/jamon/jamon.xml b/jetty-home/src/main/resources/modules/jamon/jamon.xml index 2ec2d89db4b..f9447f41d09 100644 --- a/jetty-home/src/main/resources/modules/jamon/jamon.xml +++ b/jetty-home/src/main/resources/modules/jamon/jamon.xml @@ -1,9 +1,6 @@ - - + - - - + diff --git a/jetty-home/src/main/resources/modules/jolokia/jolokia.xml b/jetty-home/src/main/resources/modules/jolokia/jolokia.xml index b6e240497a3..a3a5bf19e53 100644 --- a/jetty-home/src/main/resources/modules/jolokia/jolokia.xml +++ b/jetty-home/src/main/resources/modules/jolokia/jolokia.xml @@ -1,5 +1,4 @@ - - + diff --git a/jetty-http-spi/pom.xml b/jetty-http-spi/pom.xml index 5070cb4560a..7841dac41af 100644 --- a/jetty-http-spi/pom.xml +++ b/jetty-http-spi/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 jetty-http-spi @@ -22,7 +22,7 @@ jetty-client ${project.version} test - + com.sun.net.httpserver http @@ -56,14 +56,14 @@ org.apache.felix maven-bundle-plugin true - - - Jetty Http SPI - osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional - osgi.serviceloader; osgi.serviceloader=com.sun.net.httpserver.spi.HttpServerProvider - <_nouses>true - - + + + Jetty Http SPI + osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional + osgi.serviceloader; osgi.serviceloader=com.sun.net.httpserver.spi.HttpServerProvider + <_nouses>true + + org.jacoco diff --git a/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/DelegatingThreadPool.java b/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/DelegatingThreadPool.java index 5a664d7e05b..9dac2add752 100644 --- a/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/DelegatingThreadPool.java +++ b/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/DelegatingThreadPool.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -29,55 +29,50 @@ import org.eclipse.jetty.util.thread.ThreadPool; import org.eclipse.jetty.util.thread.TryExecutor; public class DelegatingThreadPool extends ContainerLifeCycle implements ThreadPool, TryExecutor -{ +{ private Executor _executor; // memory barrier provided by start/stop semantics private TryExecutor _tryExecutor; public DelegatingThreadPool(Executor executor) { - _executor=executor; - _tryExecutor=TryExecutor.asTryExecutor(executor); + _executor = executor; + _tryExecutor = TryExecutor.asTryExecutor(executor); addBean(_executor); } - /* ------------------------------------------------------------ */ public Executor getExecutor() { return _executor; } - - /* ------------------------------------------------------------ */ + public void setExecutor(Executor executor) { if (isRunning()) throw new IllegalStateException(getState()); - updateBean(_executor,executor); - _executor=executor; - _tryExecutor=TryExecutor.asTryExecutor(executor); + updateBean(_executor, executor); + _executor = executor; + _tryExecutor = TryExecutor.asTryExecutor(executor); } - - /* ------------------------------------------------------------ */ + @Override public void execute(Runnable job) { _executor.execute(job); } - /* ------------------------------------------------------------ */ @Override public boolean tryExecute(Runnable task) { return _tryExecutor.tryExecute(task); } - /* ------------------------------------------------------------ */ @Override public int getIdleThreads() { - final Executor executor=_executor; + final Executor executor = _executor; if (executor instanceof ThreadPool) return ((ThreadPool)executor).getIdleThreads(); - + if (executor instanceof ThreadPoolExecutor) { final ThreadPoolExecutor tpe = (ThreadPoolExecutor)executor; @@ -86,14 +81,13 @@ public class DelegatingThreadPool extends ContainerLifeCycle implements ThreadPo return -1; } - /* ------------------------------------------------------------ */ @Override public int getThreads() { - final Executor executor=_executor; + final Executor executor = _executor; if (executor instanceof ThreadPool) return ((ThreadPool)executor).getThreads(); - + if (executor instanceof ThreadPoolExecutor) { final ThreadPoolExecutor tpe = (ThreadPoolExecutor)executor; @@ -102,29 +96,27 @@ public class DelegatingThreadPool extends ContainerLifeCycle implements ThreadPo return -1; } - /* ------------------------------------------------------------ */ @Override public boolean isLowOnThreads() { - final Executor executor=_executor; + final Executor executor = _executor; if (executor instanceof ThreadPool) return ((ThreadPool)executor).isLowOnThreads(); - + if (executor instanceof ThreadPoolExecutor) { final ThreadPoolExecutor tpe = (ThreadPoolExecutor)executor; // getActiveCount() locks the thread pool, so execute it last return tpe.getPoolSize() == tpe.getMaximumPoolSize() && - tpe.getQueue().size() >= tpe.getPoolSize() - tpe.getActiveCount(); + tpe.getQueue().size() >= tpe.getPoolSize() - tpe.getActiveCount(); } return false; } - /* ------------------------------------------------------------ */ @Override public void join() throws InterruptedException { - final Executor executor=_executor; + final Executor executor = _executor; if (executor instanceof ThreadPool) ((ThreadPool)executor).join(); else if (executor instanceof ExecutorService) @@ -133,7 +125,6 @@ public class DelegatingThreadPool extends ContainerLifeCycle implements ThreadPo throw new IllegalStateException(); } - /* ------------------------------------------------------------ */ @Override protected void doStop() throws Exception { @@ -141,5 +132,4 @@ public class DelegatingThreadPool extends ContainerLifeCycle implements ThreadPo if (!(_executor instanceof LifeCycle) && (_executor instanceof ExecutorService)) ((ExecutorService)_executor).shutdownNow(); } - } diff --git a/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/HttpSpiContextHandler.java b/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/HttpSpiContextHandler.java index 0627db74bcc..8753e30493f 100644 --- a/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/HttpSpiContextHandler.java +++ b/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/HttpSpiContextHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -22,23 +22,21 @@ import java.io.IOException; import java.io.PrintWriter; import java.util.List; import java.util.Map; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.handler.ContextHandler; -import org.eclipse.jetty.util.StringUtil; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - import com.sun.net.httpserver.Authenticator; import com.sun.net.httpserver.Authenticator.Result; import com.sun.net.httpserver.HttpContext; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpPrincipal; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.handler.ContextHandler; +import org.eclipse.jetty.util.StringUtil; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; /** * Jetty handler that bridges requests to {@link HttpHandler}. @@ -68,11 +66,11 @@ public class HttpSpiContextHandler extends ContextHandler HttpExchange jettyHttpExchange; if (baseRequest.isSecure()) { - jettyHttpExchange = new JettyHttpsExchange(_httpContext,req,resp); + jettyHttpExchange = new JettyHttpsExchange(_httpContext, req, resp); } else { - jettyHttpExchange = new JettyHttpExchange(_httpContext,req,resp); + jettyHttpExchange = new JettyHttpExchange(_httpContext, req, resp); } // TODO: add filters processing @@ -82,7 +80,7 @@ public class HttpSpiContextHandler extends ContextHandler Authenticator auth = _httpContext.getAuthenticator(); if (auth != null) { - handleAuthentication(resp,jettyHttpExchange,auth); + handleAuthentication(resp, jettyHttpExchange, auth); } else { @@ -105,8 +103,8 @@ public class HttpSpiContextHandler extends ContextHandler ex.printStackTrace(writer); writer.println(""); } - - baseRequest.getHttpChannel().getHttpConfiguration().writePoweredBy(writer,"

      ","

      "); + + baseRequest.getHttpChannel().getHttpConfiguration().writePoweredBy(writer, "

      ", "

      "); writer.close(); } @@ -114,7 +112,6 @@ public class HttpSpiContextHandler extends ContextHandler { baseRequest.setHandled(true); } - } private void handleAuthentication(HttpServletResponse resp, HttpExchange httpExchange, Authenticator auth) throws IOException @@ -123,20 +120,24 @@ public class HttpSpiContextHandler extends ContextHandler if (result instanceof Authenticator.Failure) { int rc = ((Authenticator.Failure)result).getResponseCode(); - for (Map.Entry> header : httpExchange.getResponseHeaders().entrySet()) + for (Map.Entry> header : httpExchange.getResponseHeaders().entrySet()) { for (String value : header.getValue()) - resp.addHeader(header.getKey(),value); + { + resp.addHeader(header.getKey(), value); + } } resp.sendError(rc); } else if (result instanceof Authenticator.Retry) { int rc = ((Authenticator.Retry)result).getResponseCode(); - for (Map.Entry> header : httpExchange.getResponseHeaders().entrySet()) + for (Map.Entry> header : httpExchange.getResponseHeaders().entrySet()) { for (String value : header.getValue()) - resp.addHeader(header.getKey(),value); + { + resp.addHeader(header.getKey(), value); + } } resp.setStatus(rc); resp.flushBuffer(); @@ -158,5 +159,4 @@ public class HttpSpiContextHandler extends ContextHandler { this._httpHandler = handler; } - } diff --git a/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyExchange.java b/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyExchange.java index 73af298d8fb..ecb02f41bac 100644 --- a/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyExchange.java +++ b/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyExchange.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,8 +20,8 @@ package org.eclipse.jetty.http.spi; import com.sun.net.httpserver.HttpPrincipal; -/* ------------------------------------------------------------ */ /** + * */ public interface JettyExchange { @@ -29,5 +29,4 @@ public interface JettyExchange HttpPrincipal getPrincipal(); void setPrincipal(HttpPrincipal principal); - } diff --git a/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyHttpContext.java b/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyHttpContext.java index 18b45d99ea5..98da2cad6a4 100644 --- a/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyHttpContext.java +++ b/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyHttpContext.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -37,16 +37,15 @@ public class JettyHttpContext extends com.sun.net.httpserver.HttpContext private HttpSpiContextHandler _jettyContextHandler; private HttpServer _server; - - private Map _attributes = new HashMap(); - + + private Map _attributes = new HashMap(); + private List _filters = new ArrayList(); - + private Authenticator _authenticator; - protected JettyHttpContext(HttpServer server, String path, - HttpHandler handler) + HttpHandler handler) { this._server = server; _jettyContextHandler = new HttpSpiContextHandler(this, handler); @@ -107,5 +106,4 @@ public class JettyHttpContext extends com.sun.net.httpserver.HttpContext { return _authenticator; } - } diff --git a/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyHttpExchange.java b/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyHttpExchange.java index 802b8b3f604..01ab7408c42 100644 --- a/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyHttpExchange.java +++ b/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyHttpExchange.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -23,7 +23,6 @@ import java.io.InputStream; import java.io.OutputStream; import java.net.InetSocketAddress; import java.net.URI; - import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -39,154 +38,132 @@ public class JettyHttpExchange extends HttpExchange implements JettyExchange public JettyHttpExchange(HttpContext jaxWsContext, HttpServletRequest req, HttpServletResponse resp) { super(); - _delegate = new JettyHttpExchangeDelegate(jaxWsContext,req,resp); + _delegate = new JettyHttpExchangeDelegate(jaxWsContext, req, resp); } - /* ------------------------------------------------------------ */ @Override public int hashCode() { return _delegate.hashCode(); } - /* ------------------------------------------------------------ */ @Override public Headers getRequestHeaders() { return _delegate.getRequestHeaders(); } - /* ------------------------------------------------------------ */ @Override public Headers getResponseHeaders() { return _delegate.getResponseHeaders(); } - /* ------------------------------------------------------------ */ @Override public URI getRequestURI() { return _delegate.getRequestURI(); } - /* ------------------------------------------------------------ */ @Override public String getRequestMethod() { return _delegate.getRequestMethod(); } - /* ------------------------------------------------------------ */ @Override public HttpContext getHttpContext() { return _delegate.getHttpContext(); } - /* ------------------------------------------------------------ */ @Override public void close() { _delegate.close(); } - /* ------------------------------------------------------------ */ @Override public boolean equals(Object obj) { return _delegate.equals(obj); } - /* ------------------------------------------------------------ */ @Override public InputStream getRequestBody() { return _delegate.getRequestBody(); } - /* ------------------------------------------------------------ */ @Override public OutputStream getResponseBody() { return _delegate.getResponseBody(); } - /* ------------------------------------------------------------ */ @Override public void sendResponseHeaders(int rCode, long responseLength) throws IOException { - _delegate.sendResponseHeaders(rCode,responseLength); + _delegate.sendResponseHeaders(rCode, responseLength); } - /* ------------------------------------------------------------ */ @Override public InetSocketAddress getRemoteAddress() { return _delegate.getRemoteAddress(); } - /* ------------------------------------------------------------ */ @Override public int getResponseCode() { return _delegate.getResponseCode(); } - /* ------------------------------------------------------------ */ @Override public InetSocketAddress getLocalAddress() { return _delegate.getLocalAddress(); } - /* ------------------------------------------------------------ */ @Override public String getProtocol() { return _delegate.getProtocol(); } - /* ------------------------------------------------------------ */ @Override public Object getAttribute(String name) { return _delegate.getAttribute(name); } - /* ------------------------------------------------------------ */ @Override public void setAttribute(String name, Object value) { - _delegate.setAttribute(name,value); + _delegate.setAttribute(name, value); } - /* ------------------------------------------------------------ */ @Override public void setStreams(InputStream i, OutputStream o) { - _delegate.setStreams(i,o); + _delegate.setStreams(i, o); } - /* ------------------------------------------------------------ */ @Override public HttpPrincipal getPrincipal() { return _delegate.getPrincipal(); } - /* ------------------------------------------------------------ */ @Override public void setPrincipal(HttpPrincipal principal) { _delegate.setPrincipal(principal); } - /* ------------------------------------------------------------ */ @Override public String toString() { return _delegate.toString(); } - } diff --git a/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyHttpExchangeDelegate.java b/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyHttpExchangeDelegate.java index 556efbc81ce..20ba1c4bcb4 100644 --- a/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyHttpExchangeDelegate.java +++ b/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyHttpExchangeDelegate.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -27,7 +27,6 @@ import java.net.URISyntaxException; import java.util.Enumeration; import java.util.List; import java.util.Map; - import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -86,7 +85,7 @@ public class JettyHttpExchangeDelegate extends HttpExchange while (en2.hasMoreElements()) { String value = (String)en2.nextElement(); - headers.add(name,value); + headers.add(name, value); } } return headers; @@ -166,12 +165,12 @@ public class JettyHttpExchangeDelegate extends HttpExchange for (String value : values) { - _resp.setHeader(name,value); + _resp.setHeader(name, value); } } if (responseLength > 0) { - _resp.setHeader("content-length","" + responseLength); + _resp.setHeader("content-length", "" + responseLength); } _resp.setStatus(rCode); } @@ -179,7 +178,7 @@ public class JettyHttpExchangeDelegate extends HttpExchange @Override public InetSocketAddress getRemoteAddress() { - return new InetSocketAddress(_req.getRemoteAddr(),_req.getRemotePort()); + return new InetSocketAddress(_req.getRemoteAddr(), _req.getRemotePort()); } @Override @@ -191,7 +190,7 @@ public class JettyHttpExchangeDelegate extends HttpExchange @Override public InetSocketAddress getLocalAddress() { - return new InetSocketAddress(_req.getLocalAddr(),_req.getLocalPort()); + return new InetSocketAddress(_req.getLocalAddr(), _req.getLocalPort()); } @Override @@ -209,7 +208,7 @@ public class JettyHttpExchangeDelegate extends HttpExchange @Override public void setAttribute(String name, Object value) { - _req.setAttribute(name,value); + _req.setAttribute(name, value); } @Override @@ -229,5 +228,4 @@ public class JettyHttpExchangeDelegate extends HttpExchange { this._httpPrincipal = principal; } - } diff --git a/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyHttpServer.java b/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyHttpServer.java index cb0a3754af0..d8112eba842 100644 --- a/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyHttpServer.java +++ b/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyHttpServer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -24,8 +24,9 @@ import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Executor; -import java.util.concurrent.ThreadPoolExecutor; +import com.sun.net.httpserver.HttpContext; +import com.sun.net.httpserver.HttpHandler; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.HttpConfiguration; @@ -40,9 +41,6 @@ import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.thread.ThreadPool; -import com.sun.net.httpserver.HttpContext; -import com.sun.net.httpserver.HttpHandler; - /** * Jetty implementation of {@link com.sun.net.httpserver.HttpServer}. */ @@ -58,15 +56,13 @@ public class JettyHttpServer extends com.sun.net.httpserver.HttpServer private InetSocketAddress _addr; - private Map _contexts = new HashMap<>(); private Map _connectors = new HashMap<>(); - public JettyHttpServer(Server server, boolean shared) { - this(server,shared,new HttpConfiguration()); + this(server, shared, new HttpConfiguration()); } public JettyHttpServer(Server server, boolean shared, HttpConfiguration configuration) @@ -91,8 +87,10 @@ public class JettyHttpServer extends com.sun.net.httpserver.HttpServer { for (NetworkConnector connector : connectors) { - if (connector.getPort() == addr.getPort()||connector.getLocalPort() == addr.getPort()) { - if (LOG.isDebugEnabled()) LOG.debug("server already bound to port " + addr.getPort() + ", no need to rebind"); + if (connector.getPort() == addr.getPort() || connector.getLocalPort() == addr.getPort()) + { + if (LOG.isDebugEnabled()) + LOG.debug("server already bound to port " + addr.getPort() + ", no need to rebind"); return; } } @@ -101,9 +99,8 @@ public class JettyHttpServer extends com.sun.net.httpserver.HttpServer if (_serverShared) throw new IOException("jetty server is not bound to port " + addr.getPort()); - - - if (LOG.isDebugEnabled()) LOG.debug("binding server to port " + addr.getPort()); + if (LOG.isDebugEnabled()) + LOG.debug("binding server to port " + addr.getPort()); ServerConnector connector = new ServerConnector(_server); connector.setPort(addr.getPort()); connector.setHost(addr.getHostName()); @@ -112,15 +109,15 @@ public class JettyHttpServer extends com.sun.net.httpserver.HttpServer _connectors.put(addr.getHostName() + addr.getPort(), connector); } - + protected Server getServer() { return _server; } - protected ServerConnector newServerConnector(InetSocketAddress addr,int backlog) + protected ServerConnector newServerConnector(InetSocketAddress addr, int backlog) { - ServerConnector connector = new ServerConnector(_server,new HttpConnectionFactory(_httpConfiguration)); + ServerConnector connector = new ServerConnector(_server, new HttpConnectionFactory(_httpConfiguration)); connector.setPort(addr.getPort()); connector.setHost(addr.getHostName()); return connector; @@ -135,7 +132,8 @@ public class JettyHttpServer extends com.sun.net.httpserver.HttpServer @Override public void start() { - if (_serverShared) return; + if (_serverShared) + return; try { @@ -161,15 +159,17 @@ public class JettyHttpServer extends com.sun.net.httpserver.HttpServer { _server.stop(); } - ((DelegatingThreadPool) _server.getThreadPool()).setExecutor(executor); + ((DelegatingThreadPool)_server.getThreadPool()).setExecutor(executor); _server.start(); } - catch ( Exception e ) + catch (Exception e) { throw new RuntimeException(e.getMessage(), e); } - } else { - throw new UnsupportedOperationException( "!DelegatingThreadPool" ); + } + else + { + throw new UnsupportedOperationException("!DelegatingThreadPool"); } } @@ -188,7 +188,8 @@ public class JettyHttpServer extends com.sun.net.httpserver.HttpServer cleanUpContexts(); cleanUpConnectors(); - if (_serverShared) return; + if (_serverShared) + return; try { @@ -218,8 +219,8 @@ public class JettyHttpServer extends com.sun.net.httpserver.HttpServer try { connector.stop(); - } - catch (Exception ex) + } + catch (Exception ex) { LOG.warn(ex); } @@ -243,6 +244,18 @@ public class JettyHttpServer extends com.sun.net.httpserver.HttpServer chc.addHandler(jettyContextHandler); _contexts.put(path, context); + if (!jettyContextHandler.isStarted()) + { + try + { + jettyContextHandler.start(); + } + catch (Exception e) + { + throw new RuntimeException(e.getMessage(), e); + } + } + return context; } @@ -255,12 +268,12 @@ public class JettyHttpServer extends com.sun.net.httpserver.HttpServer { if (handler instanceof ContextHandlerCollection) { - return (ContextHandlerCollection) handler; + return (ContextHandlerCollection)handler; } if (handler instanceof HandlerCollection) { - HandlerCollection hc = (HandlerCollection) handler; + HandlerCollection hc = (HandlerCollection)handler; ContextHandlerCollection chc = findContextHandlerCollection(hc.getHandlers()); if (chc != null) return chc; @@ -274,18 +287,20 @@ public class JettyHttpServer extends com.sun.net.httpserver.HttpServer Handler serverHandler = _server.getHandler(); if (serverHandler instanceof ContextHandler) { - ContextHandler ctx = (ContextHandler) serverHandler; + ContextHandler ctx = (ContextHandler)serverHandler; if (ctx.getContextPath().equals(path)) throw new RuntimeException("another context already bound to path " + path); } Handler[] handlers = _server.getHandlers(); - if (handlers == null) return; + if (handlers == null) + return; for (Handler handler : handlers) { - if (handler instanceof ContextHandler) { - ContextHandler ctx = (ContextHandler) handler; + if (handler instanceof ContextHandler) + { + ContextHandler ctx = (ContextHandler)handler; if (ctx.getContextPath().equals(path)) throw new RuntimeException("another context already bound to path " + path); } @@ -302,7 +317,8 @@ public class JettyHttpServer extends com.sun.net.httpserver.HttpServer public void removeContext(String path) throws IllegalArgumentException { JettyHttpContext context = _contexts.remove(path); - if (context == null) return; + if (context == null) + return; _server.removeBean(context.getJettyContextHandler()); } @@ -311,5 +327,4 @@ public class JettyHttpServer extends com.sun.net.httpserver.HttpServer { removeContext(context.getPath()); } - } diff --git a/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyHttpServerProvider.java b/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyHttpServerProvider.java index eb5f07eca92..6809d698577 100644 --- a/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyHttpServerProvider.java +++ b/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyHttpServerProvider.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -21,6 +21,9 @@ package org.eclipse.jetty.http.spi; import java.io.IOException; import java.net.InetSocketAddress; +import com.sun.net.httpserver.HttpServer; +import com.sun.net.httpserver.HttpsServer; +import com.sun.net.httpserver.spi.HttpServerProvider; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.ContextHandlerCollection; @@ -29,10 +32,6 @@ import org.eclipse.jetty.server.handler.HandlerCollection; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.eclipse.jetty.util.thread.ThreadPool; -import com.sun.net.httpserver.HttpServer; -import com.sun.net.httpserver.HttpsServer; -import com.sun.net.httpserver.spi.HttpServerProvider; - /** * Jetty implementation of Java HTTP Server SPI */ @@ -48,7 +47,7 @@ public class JettyHttpServerProvider extends HttpServerProvider @Override public HttpServer createHttpServer(InetSocketAddress addr, int backlog) - throws IOException + throws IOException { Server server = _server; boolean shared = true; @@ -59,7 +58,7 @@ public class JettyHttpServerProvider extends HttpServerProvider server = new Server(threadPool); HandlerCollection handlerCollection = new HandlerCollection(); - handlerCollection.setHandlers(new Handler[] {new ContextHandlerCollection(), new DefaultHandler()}); + handlerCollection.setHandlers(new Handler[]{new ContextHandlerCollection(), new DefaultHandler()}); server.setHandler(handlerCollection); shared = false; @@ -67,7 +66,7 @@ public class JettyHttpServerProvider extends HttpServerProvider JettyHttpServer jettyHttpServer = new JettyHttpServer(server, shared); if (addr != null) - jettyHttpServer.bind(addr, backlog); + jettyHttpServer.bind(addr, backlog); return jettyHttpServer; } @@ -76,5 +75,4 @@ public class JettyHttpServerProvider extends HttpServerProvider { throw new UnsupportedOperationException(); } - } diff --git a/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyHttpsExchange.java b/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyHttpsExchange.java index b96dee48d05..02e0e82498b 100644 --- a/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyHttpsExchange.java +++ b/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyHttpsExchange.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -23,7 +23,6 @@ import java.io.InputStream; import java.io.OutputStream; import java.net.InetSocketAddress; import java.net.URI; - import javax.net.ssl.SSLSession; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -33,8 +32,8 @@ import com.sun.net.httpserver.HttpContext; import com.sun.net.httpserver.HttpPrincipal; import com.sun.net.httpserver.HttpsExchange; -/* ------------------------------------------------------------ */ /** + * */ public class JettyHttpsExchange extends HttpsExchange implements JettyExchange { @@ -43,7 +42,7 @@ public class JettyHttpsExchange extends HttpsExchange implements JettyExchange public JettyHttpsExchange(HttpContext jaxWsContext, HttpServletRequest req, HttpServletResponse resp) { super(); - _delegate = new JettyHttpExchangeDelegate(jaxWsContext,req,resp); + _delegate = new JettyHttpExchangeDelegate(jaxWsContext, req, resp); } @Override @@ -109,7 +108,7 @@ public class JettyHttpsExchange extends HttpsExchange implements JettyExchange @Override public void sendResponseHeaders(int rCode, long responseLength) throws IOException { - _delegate.sendResponseHeaders(rCode,responseLength); + _delegate.sendResponseHeaders(rCode, responseLength); } @Override @@ -145,13 +144,13 @@ public class JettyHttpsExchange extends HttpsExchange implements JettyExchange @Override public void setAttribute(String name, Object value) { - _delegate.setAttribute(name,value); + _delegate.setAttribute(name, value); } @Override public void setStreams(InputStream i, OutputStream o) { - _delegate.setStreams(i,o); + _delegate.setStreams(i, o); } @Override @@ -172,7 +171,6 @@ public class JettyHttpsExchange extends HttpsExchange implements JettyExchange return _delegate.toString(); } - /* ------------------------------------------------------------ */ /** * @see com.sun.net.httpserver.HttpsExchange#getSSLSession() */ @@ -181,5 +179,4 @@ public class JettyHttpsExchange extends HttpsExchange implements JettyExchange { return null; } - } diff --git a/jetty-http-spi/src/test/java/org/eclipse/jetty/http/spi/TestEndpointMultiplePublishProblem.java b/jetty-http-spi/src/test/java/org/eclipse/jetty/http/spi/TestEndpointMultiplePublishProblem.java index aca8ddb5ad9..e488b24aa2d 100644 --- a/jetty-http-spi/src/test/java/org/eclipse/jetty/http/spi/TestEndpointMultiplePublishProblem.java +++ b/jetty-http-spi/src/test/java/org/eclipse/jetty/http/spi/TestEndpointMultiplePublishProblem.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,18 +18,27 @@ package org.eclipse.jetty.http.spi; +import java.net.URL; +import javax.jws.WebMethod; +import javax.jws.WebService; +import javax.xml.namespace.QName; +import javax.xml.ws.BindingProvider; +import javax.xml.ws.Endpoint; +import javax.xml.ws.Service; +import javax.xml.ws.WebEndpoint; +import javax.xml.ws.WebServiceClient; + +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.api.ContentResponse; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.handler.ContextHandlerCollection; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import javax.jws.WebMethod; -import javax.jws.WebService; -import javax.xml.ws.Endpoint; - public class TestEndpointMultiplePublishProblem { @@ -44,14 +53,16 @@ public class TestEndpointMultiplePublishProblem @AfterAll public static void restore_Impl() { - if(default_impl != null) + if (default_impl != null) { - System.setProperty( "com.sun.net.httpserver.HttpServerProvider", default_impl ); + System.setProperty("com.sun.net.httpserver.HttpServerProvider", default_impl); } } @Test - public void mainJetty() throws Exception { + public void mainJetty() + throws Exception + { Server jettyWebServer = new Server(new DelegatingThreadPool(new QueuedThreadPool())); ServerConnector connector = new ServerConnector(jettyWebServer); @@ -65,21 +76,86 @@ public class TestEndpointMultiplePublishProblem jettyWebServer.start(); - Endpoint.publish(String.format("http://%s:%d/hello", "localhost", 0), new Ws()); - // Comment out the below line for success in later java such as java8_u172, works before u151 or so - Endpoint.publish(String.format("http://%s:%d/hello2", "localhost", 0), new Ws()); + Endpoint.publish(String.format("http://%s:%d/hello", "localhost", 0), new WsHello()); + Endpoint.publish(String.format("http://%s:%d/hello2", "localhost", 0), new WsHello()); int port = connector.getLocalPort(); - System.out.printf("Started, check: http://localhost:%d/hello?wsdl%n", port); + HttpClient httpClient = new HttpClient(); + httpClient.start(); + + { + String url = String.format("http://localhost:%d/hello", port); + String urlWsdl = url + "?wsdl"; + + ContentResponse contentResponse = httpClient.newRequest(url).send(); + Assertions.assertEquals(200, contentResponse.getStatus()); + + HelloMessengerService helloMessengerService = new HelloMessengerService(new URL(urlWsdl)); + Hello hello = helloMessengerService.getHelloMessengerPort(); + ((BindingProvider)hello).getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, url); + String helloResponse = hello.hello(); + Assertions.assertEquals("G'Day mate!", helloResponse); + } + + { + + String url2 = String.format("http://localhost:%d/hello2", port); + String url2Wsdl = url2 + "?wsdl"; + + ContentResponse contentResponse = httpClient.newRequest(url2Wsdl).send(); + Assertions.assertEquals(200, contentResponse.getStatus()); + + HelloMessengerService helloMessengerService = new HelloMessengerService(new URL(url2Wsdl)); + Hello hello = helloMessengerService.getHelloMessengerPort(); + ((BindingProvider)hello).getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, url2); + String helloResponse = hello.hello(); + Assertions.assertEquals("G'Day mate!", helloResponse); + } + httpClient.stop(); + jettyWebServer.stop(); } - - @WebService - public static class Ws { + @WebService(targetNamespace = "http://org.eclipse.jetty.ws.test", name = "HelloService") + public interface Hello + { @WebMethod - public String hello() { - return "Hello"; + String hello(); + } + + @WebService(targetNamespace = "http://org.eclipse.jetty.ws.test", name = "HelloService") + public static class WsHello + implements Hello + { + @WebMethod + public String hello() + { + return "G'Day mate!"; } } + + @WebServiceClient(name = "HelloService", targetNamespace = "http://org.eclipse.jetty.ws.test") + public static class HelloMessengerService + extends Service + { + + public HelloMessengerService(URL wsdlLocation) + { + super(wsdlLocation, // + new QName("http://org.eclipse.jetty.ws.test", "WsHelloService")); + } + + @WebEndpoint(name = "HelloServicePort") + public Hello getHelloMessengerPort() + { + return super.getPort(new QName("http://org.eclipse.jetty.ws.test", "HelloServicePort"), // + Hello.class); + } + } + + private void assertWsdl(String wsdl) + throws Exception + { + + } } diff --git a/jetty-http-spi/src/test/java/org/eclipse/jetty/http/spi/TestSPIServer.java b/jetty-http-spi/src/test/java/org/eclipse/jetty/http/spi/TestSPIServer.java index 429c517bccd..1b44817bd46 100644 --- a/jetty-http-spi/src/test/java/org/eclipse/jetty/http/spi/TestSPIServer.java +++ b/jetty-http-spi/src/test/java/org/eclipse/jetty/http/spi/TestSPIServer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,46 +18,34 @@ package org.eclipse.jetty.http.spi; +import java.io.OutputStream; +import java.net.InetSocketAddress; +import java.net.URI; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import javax.servlet.http.HttpServletResponse; + +import com.sun.net.httpserver.BasicAuthenticator; +import com.sun.net.httpserver.Headers; +import com.sun.net.httpserver.HttpContext; +import com.sun.net.httpserver.HttpServer; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.api.ContentResponse; import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.util.BasicAuthentication; import org.eclipse.jetty.server.NetworkConnector; import org.eclipse.jetty.server.Server; +import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; -import java.io.IOException; -import java.io.OutputStream; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.URI; -import java.util.Iterator; -import java.util.List; -import java.util.Set; - -import javax.servlet.http.HttpServletResponse; - -import com.sun.net.httpserver.BasicAuthenticator; -import com.sun.net.httpserver.Headers; -import com.sun.net.httpserver.HttpContext; -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; -import com.sun.net.httpserver.HttpServer; - -import org.junit.jupiter.api.Test; - - - - public class TestSPIServer { - + /** * Create a server that has a null InetSocketAddress, then * bind before using. - * - * @throws Exception */ @Test public void testUnboundHttpServer() throws Exception @@ -71,10 +59,11 @@ public class TestSPIServer server = new JettyHttpServerProvider().createHttpServer(null, 10); final HttpContext httpContext = server.createContext("/", - exchange -> { + exchange -> + { Headers responseHeaders = exchange.getResponseHeaders(); - responseHeaders.set("Content-Type","text/plain"); - exchange.sendResponseHeaders(200,0); + responseHeaders.set("Content-Type", "text/plain"); + exchange.sendResponseHeaders(200, 0); OutputStream responseBody = exchange.getResponseBody(); Headers requestHeaders = exchange.getRequestHeaders(); @@ -88,7 +77,7 @@ public class TestSPIServer responseBody.write(s.getBytes()); } responseBody.close(); - }); + }); httpContext.setAuthenticator(new BasicAuthenticator("Test") { @@ -105,23 +94,23 @@ public class TestSPIServer //address to bind so this test isn't port-specific //and thus is portable and can be run concurrently on CI //environments - server.bind(new InetSocketAddress("localhost", 0), 10); - + server.bind(new InetSocketAddress("localhost", 0), 10); + server.start(); //find out the port jetty picked Server jetty = ((JettyHttpServer)server).getServer(); - int port = ((NetworkConnector)jetty.getConnectors()[0]).getLocalPort(); - + int port = ((NetworkConnector)jetty.getConnectors()[0]).getLocalPort(); + HttpClient client = new HttpClient(); client.start(); try { Request request = client.newRequest("http://localhost:" + port + "/"); - client.getAuthenticationStore().addAuthentication(new BasicAuthentication(URI.create("http://localhost:"+port), "Test", "username", "password")); + client.getAuthenticationStore().addAuthentication(new BasicAuthentication(URI.create("http://localhost:" + port), "Test", "username", "password")); ContentResponse response = request.send(); - assertEquals(HttpServletResponse.SC_OK,response.getStatus()); + assertEquals(HttpServletResponse.SC_OK, response.getStatus()); } finally { @@ -137,11 +126,10 @@ public class TestSPIServer /** * Test using a server that is created with a given InetSocketAddress - * @throws Exception */ @Test public void testBoundHttpServer() throws Exception - { + { HttpServer server = null; @@ -151,13 +139,14 @@ public class TestSPIServer //jetty to pick a free port. Ensures test is not tied to specific port number //for test portability and concurrency. server = new JettyHttpServerProvider().createHttpServer(new - InetSocketAddress("localhost", 0), 10); + InetSocketAddress("localhost", 0), 10); final HttpContext httpContext = server.createContext("/", - exchange -> { + exchange -> + { Headers responseHeaders = exchange.getResponseHeaders(); - responseHeaders.set("Content-Type","text/plain"); - exchange.sendResponseHeaders(200,0); + responseHeaders.set("Content-Type", "text/plain"); + exchange.sendResponseHeaders(200, 0); OutputStream responseBody = exchange.getResponseBody(); Headers requestHeaders = exchange.getRequestHeaders(); @@ -171,7 +160,7 @@ public class TestSPIServer responseBody.write(s.getBytes()); } responseBody.close(); - }); + }); httpContext.setAuthenticator(new BasicAuthenticator("Test") { @@ -188,7 +177,7 @@ public class TestSPIServer //find out the port jetty picked Server jetty = ((JettyHttpServer)server).getServer(); - int port = ((NetworkConnector)jetty.getConnectors()[0]).getLocalPort(); + int port = ((NetworkConnector)jetty.getConnectors()[0]).getLocalPort(); HttpClient client = new HttpClient(); client.start(); @@ -196,9 +185,9 @@ public class TestSPIServer try { Request request = client.newRequest("http://localhost:" + port + "/"); - client.getAuthenticationStore().addAuthentication(new BasicAuthentication(URI.create("http://localhost:"+port), "Test", "username", "password")); + client.getAuthenticationStore().addAuthentication(new BasicAuthentication(URI.create("http://localhost:" + port), "Test", "username", "password")); ContentResponse response = request.send(); - assertEquals(HttpServletResponse.SC_OK,response.getStatus()); + assertEquals(HttpServletResponse.SC_OK, response.getStatus()); } finally { diff --git a/jetty-http/pom.xml b/jetty-http/pom.xml index af67747e28d..d482f9184a9 100644 --- a/jetty-http/pom.xml +++ b/jetty-http/pom.xml @@ -3,7 +3,7 @@ jetty-project org.eclipse.jetty - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 jetty-http @@ -40,12 +40,12 @@ org.apache.felix maven-bundle-plugin true - - - osgi.serviceloader; filter:="(osgi.serviceloader=org.eclipse.jetty.http.HttpFieldPreEncoder)";resolution:=optional;cardinality:=multiple, osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)";resolution:=optional, osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional - osgi.serviceloader; osgi.serviceloader=org.eclipse.jetty.http.HttpFieldPreEncoder - - + + + osgi.serviceloader; filter:="(osgi.serviceloader=org.eclipse.jetty.http.HttpFieldPreEncoder)";resolution:=optional;cardinality:=multiple, osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)";resolution:=optional, osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional + osgi.serviceloader; osgi.serviceloader=org.eclipse.jetty.http.HttpFieldPreEncoder + +
      org.apache.maven.plugins @@ -84,17 +84,16 @@ - + org.openjdk.jmh.Main - org.openjdk.jmh:jmh-core - - ** - + org.openjdk.jmh:jmh-core + + ** + *:* diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/BadMessageException.java b/jetty-http/src/main/java/org/eclipse/jetty/http/BadMessageException.java index 6810a856aa7..84c446edd9f 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/BadMessageException.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/BadMessageException.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,8 +18,7 @@ package org.eclipse.jetty.http; -/* ------------------------------------------------------------------------------- */ -/** +/** *

      Exception thrown to indicate a Bad HTTP Message has either been received * or attempted to be generated. Typically these are handled with either 400 * or 500 responses.

      @@ -32,43 +31,41 @@ public class BadMessageException extends RuntimeException public BadMessageException() { - this(400,null); + this(400, null); } - + public BadMessageException(int code) { - this(code,null); + this(code, null); } - + public BadMessageException(String reason) { - this(400,reason); + this(400, reason); } - + public BadMessageException(String reason, Throwable cause) { this(400, reason, cause); } - + public BadMessageException(int code, String reason) { - super(code+": "+reason); - _code=code; - _reason=reason; + this(code, reason, null); } - + public BadMessageException(int code, String reason, Throwable cause) { - super(code+": "+reason, cause); - _code=code; - _reason=reason; + super(code + ": " + reason, cause); + _code = code; + _reason = reason; } - + public int getCode() { return _code; } - + public String getReason() { return _reason; diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/CompressedContentFormat.java b/jetty-http/src/main/java/org/eclipse/jetty/http/CompressedContentFormat.java index 93b9501541c..dfe8c9db79f 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/CompressedContentFormat.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/CompressedContentFormat.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,8 +18,6 @@ package org.eclipse.jetty.http; - -/* ------------------------------------------------------------ */ public class CompressedContentFormat { public static final CompressedContentFormat GZIP = new CompressedContentFormat("gzip", ".gz"); @@ -40,19 +38,19 @@ public class CompressedContentFormat _etagQuote = _etag + "\""; _contentEncoding = new PreEncodedHttpField(HttpHeader.CONTENT_ENCODING, encoding); } - + @Override public boolean equals(Object o) { if (!(o instanceof CompressedContentFormat)) return false; CompressedContentFormat ccf = (CompressedContentFormat)o; - if (_encoding==null && ccf._encoding!=null) + if (_encoding == null && ccf._encoding != null) return false; - if (_extension==null && ccf._extension!=null) + if (_extension == null && ccf._extension != null) return false; - - return _encoding.equalsIgnoreCase(ccf._encoding) && _extension.equalsIgnoreCase(ccf._extension); + + return _encoding.equalsIgnoreCase(ccf._encoding) && _extension.equalsIgnoreCase(ccf._extension); } public static boolean tagEquals(String etag, String tag) @@ -61,8 +59,8 @@ public class CompressedContentFormat return true; int dashdash = tag.indexOf("--"); - if (dashdash>0 && dashdash==etag.length()-1) - return etag.regionMatches(0,tag,0,dashdash); + if (dashdash > 0 && dashdash == etag.length() - 1) + return etag.regionMatches(0, tag, 0, dashdash); return false; } } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/CookieCompliance.java b/jetty-http/src/main/java/org/eclipse/jetty/http/CookieCompliance.java index dc208524d25..eda3b75048e 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/CookieCompliance.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/CookieCompliance.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,6 +20,9 @@ package org.eclipse.jetty.http; /** * The compliance for Cookie handling. - * */ -public enum CookieCompliance { RFC6265, RFC2965 } +public enum CookieCompliance +{ + RFC6265, + RFC2965 +} diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/DateGenerator.java b/jetty-http/src/main/java/org/eclipse/jetty/http/DateGenerator.java index 2b29b5f1516..f37b2cb0ab4 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/DateGenerator.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/DateGenerator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -30,18 +30,18 @@ import org.eclipse.jetty.util.StringUtil; public class DateGenerator { private static final TimeZone __GMT = TimeZone.getTimeZone("GMT"); + static { __GMT.setID("GMT"); } - + static final String[] DAYS = - { "Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; + {"Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; static final String[] MONTHS = - { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Jan"}; + {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Jan"}; - - private static final ThreadLocal __dateGenerator =new ThreadLocal() + private static final ThreadLocal __dateGenerator = new ThreadLocal() { @Override protected DateGenerator initialValue() @@ -50,11 +50,11 @@ public class DateGenerator } }; + public static final String __01Jan1970 = DateGenerator.formatDate(0); - public final static String __01Jan1970=DateGenerator.formatDate(0); - /** * Format HTTP date "EEE, dd MMM yyyy HH:mm:ss 'GMT'" + * * @param date the date in milliseconds * @return the formatted date */ @@ -65,17 +65,19 @@ public class DateGenerator /** * Format "EEE, dd-MMM-yyyy HH:mm:ss 'GMT'" for cookies + * * @param buf the buffer to put the formatted date into * @param date the date in milliseconds */ public static void formatCookieDate(StringBuilder buf, long date) { - __dateGenerator.get().doFormatCookieDate(buf,date); + __dateGenerator.get().doFormatCookieDate(buf, date); } /** * Format "EEE, dd-MMM-yyyy HH:mm:ss 'GMT'" for cookies - * @param date the date in milliseconds + * + * @param date the date in milliseconds * @return the formatted date */ public static String formatCookieDate(long date) @@ -84,12 +86,13 @@ public class DateGenerator formatCookieDate(buf, date); return buf.toString(); } - + private final StringBuilder buf = new StringBuilder(32); private final GregorianCalendar gc = new GregorianCalendar(__GMT); /** * Format HTTP date "EEE, dd MMM yyyy HH:mm:ss 'GMT'" + * * @param date the date in milliseconds * @return the formatted date */ @@ -98,8 +101,8 @@ public class DateGenerator buf.setLength(0); gc.setTimeInMillis(date); - int day_of_week = gc.get(Calendar.DAY_OF_WEEK); - int day_of_month = gc.get(Calendar.DAY_OF_MONTH); + int dayOfWeek = gc.get(Calendar.DAY_OF_WEEK); + int dayOfMonth = gc.get(Calendar.DAY_OF_MONTH); int month = gc.get(Calendar.MONTH); int year = gc.get(Calendar.YEAR); int century = year / 100; @@ -109,10 +112,10 @@ public class DateGenerator int minutes = gc.get(Calendar.MINUTE); int seconds = gc.get(Calendar.SECOND); - buf.append(DAYS[day_of_week]); + buf.append(DAYS[dayOfWeek]); buf.append(','); buf.append(' '); - StringUtil.append2digits(buf, day_of_month); + StringUtil.append2digits(buf, dayOfMonth); buf.append(' '); buf.append(MONTHS[month]); @@ -132,6 +135,7 @@ public class DateGenerator /** * Format "EEE, dd-MMM-yy HH:mm:ss 'GMT'" for cookies + * * @param buf the buffer to format the date into * @param date the date in milliseconds */ @@ -139,28 +143,28 @@ public class DateGenerator { gc.setTimeInMillis(date); - int day_of_week = gc.get(Calendar.DAY_OF_WEEK); - int day_of_month = gc.get(Calendar.DAY_OF_MONTH); + int dayOfWeek = gc.get(Calendar.DAY_OF_WEEK); + int dayOfMonth = gc.get(Calendar.DAY_OF_MONTH); int month = gc.get(Calendar.MONTH); int year = gc.get(Calendar.YEAR); year = year % 10000; - int epoch = (int) ((date / 1000) % (60 * 60 * 24)); + int epoch = (int)((date / 1000) % (60 * 60 * 24)); int seconds = epoch % 60; epoch = epoch / 60; int minutes = epoch % 60; int hours = epoch / 60; - buf.append(DAYS[day_of_week]); + buf.append(DAYS[dayOfWeek]); buf.append(','); buf.append(' '); - StringUtil.append2digits(buf, day_of_month); + StringUtil.append2digits(buf, dayOfMonth); buf.append('-'); buf.append(MONTHS[month]); buf.append('-'); - StringUtil.append2digits(buf, year/100); - StringUtil.append2digits(buf, year%100); + StringUtil.append2digits(buf, year / 100); + StringUtil.append2digits(buf, year % 100); buf.append(' '); StringUtil.append2digits(buf, hours); diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/DateParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/DateParser.java index e76a0a1310b..3cc117e174f 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/DateParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/DateParser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -25,37 +25,37 @@ import java.util.TimeZone; /** * ThreadLocal data parsers for HTTP style dates - * */ public class DateParser { private static final TimeZone __GMT = TimeZone.getTimeZone("GMT"); + static { __GMT.setID("GMT"); } - - final static String __dateReceiveFmt[] = - { - "EEE, dd MMM yyyy HH:mm:ss zzz", - "EEE, dd-MMM-yy HH:mm:ss", - "EEE MMM dd HH:mm:ss yyyy", - "EEE, dd MMM yyyy HH:mm:ss", "EEE dd MMM yyyy HH:mm:ss zzz", - "EEE dd MMM yyyy HH:mm:ss", "EEE MMM dd yyyy HH:mm:ss zzz", "EEE MMM dd yyyy HH:mm:ss", - "EEE MMM-dd-yyyy HH:mm:ss zzz", "EEE MMM-dd-yyyy HH:mm:ss", "dd MMM yyyy HH:mm:ss zzz", - "dd MMM yyyy HH:mm:ss", "dd-MMM-yy HH:mm:ss zzz", "dd-MMM-yy HH:mm:ss", "MMM dd HH:mm:ss yyyy zzz", - "MMM dd HH:mm:ss yyyy", "EEE MMM dd HH:mm:ss yyyy zzz", - "EEE, MMM dd HH:mm:ss yyyy zzz", "EEE, MMM dd HH:mm:ss yyyy", "EEE, dd-MMM-yy HH:mm:ss zzz", - "EEE dd-MMM-yy HH:mm:ss zzz", "EEE dd-MMM-yy HH:mm:ss", - }; + static final String[] __dateReceiveFmt = + { + "EEE, dd MMM yyyy HH:mm:ss zzz", + "EEE, dd-MMM-yy HH:mm:ss", + "EEE MMM dd HH:mm:ss yyyy", + + "EEE, dd MMM yyyy HH:mm:ss", "EEE dd MMM yyyy HH:mm:ss zzz", + "EEE dd MMM yyyy HH:mm:ss", "EEE MMM dd yyyy HH:mm:ss zzz", "EEE MMM dd yyyy HH:mm:ss", + "EEE MMM-dd-yyyy HH:mm:ss zzz", "EEE MMM-dd-yyyy HH:mm:ss", "dd MMM yyyy HH:mm:ss zzz", + "dd MMM yyyy HH:mm:ss", "dd-MMM-yy HH:mm:ss zzz", "dd-MMM-yy HH:mm:ss", "MMM dd HH:mm:ss yyyy zzz", + "MMM dd HH:mm:ss yyyy", "EEE MMM dd HH:mm:ss yyyy zzz", + "EEE, MMM dd HH:mm:ss yyyy zzz", "EEE, MMM dd HH:mm:ss yyyy", "EEE, dd-MMM-yy HH:mm:ss zzz", + "EEE dd-MMM-yy HH:mm:ss zzz", "EEE dd-MMM-yy HH:mm:ss" + }; public static long parseDate(String date) { return __dateParser.get().parse(date); } - private static final ThreadLocal __dateParser =new ThreadLocal() + private static final ThreadLocal __dateParser = new ThreadLocal() { @Override protected DateParser initialValue() @@ -63,8 +63,8 @@ public class DateParser return new DateParser(); } }; - - final SimpleDateFormat _dateReceive[]= new SimpleDateFormat[__dateReceiveFmt.length]; + + final SimpleDateFormat[] _dateReceive = new SimpleDateFormat[__dateReceiveFmt.length]; private long parse(final String dateVal) { @@ -78,7 +78,7 @@ public class DateParser try { - Date date = (Date) _dateReceive[i].parseObject(dateVal); + Date date = (Date)_dateReceive[i].parseObject(dateVal); return date.getTime(); } catch (java.lang.Exception e) @@ -95,7 +95,7 @@ public class DateParser { try { - Date date = (Date) element.parseObject(val); + Date date = (Date)element.parseObject(val); return date.getTime(); } catch (java.lang.Exception e) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/GZIPContentDecoder.java b/jetty-http/src/main/java/org/eclipse/jetty/http/GZIPContentDecoder.java index e3e0401fbee..6ca334aba29 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/GZIPContentDecoder.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/GZIPContentDecoder.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,7 +18,10 @@ package org.eclipse.jetty.http; +import java.nio.Buffer; import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; import java.util.zip.DataFormatException; import java.util.zip.Inflater; import java.util.zip.ZipException; @@ -28,13 +31,13 @@ import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.component.Destroyable; /** - * Decoder for the "gzip" encoding. - *

      - * A decoder that inflates gzip compressed data that has been - * optimized for async usage with minimal data copies. + *

      Decoder for the "gzip" content encoding.

      + *

      This decoder inflates gzip compressed data, and has + * been optimized for async usage with minimal data copies.

      */ public class GZIPContentDecoder implements Destroyable { + private final List _inflateds = new ArrayList<>(); private final Inflater _inflater = new Inflater(true); private final ByteBufferPool _pool; private final int _bufferSize; @@ -46,14 +49,14 @@ public class GZIPContentDecoder implements Destroyable public GZIPContentDecoder() { - this(null,2048); + this(null, 2048); } public GZIPContentDecoder(int bufferSize) { - this(null,bufferSize); + this(null, bufferSize); } - + public GZIPContentDecoder(ByteBufferPool pool, int bufferSize) { _bufferSize = bufferSize; @@ -61,68 +64,95 @@ public class GZIPContentDecoder implements Destroyable reset(); } - /** Inflate compressed data from a buffer. - * - * @param compressed Buffer containing compressed data. - * @return Buffer containing inflated data. + /** + *

      Inflates compressed data from a buffer.

      + *

      The buffers returned by this method should be released + * via {@link #release(ByteBuffer)}.

      + *

      This method may fully consume the input buffer, but return + * only a chunk of the inflated bytes, to allow applications to + * consume the inflated chunk before performing further inflation, + * applying backpressure. In this case, this method should be + * invoked again with the same input buffer (even if + * it's already fully consumed) and that will produce another + * chunk of inflated bytes. Termination happens when the input + * buffer is fully consumed, and the returned buffer is empty.

      + *

      See {@link #decodedChunk(ByteBuffer)} to perform inflating + * in a non-blocking way that allows to apply backpressure.

      + * + * @param compressed the buffer containing compressed data. + * @return a buffer containing inflated data. */ public ByteBuffer decode(ByteBuffer compressed) { decodeChunks(compressed); - if (BufferUtil.isEmpty(_inflated) || _state==State.CRC || _state==State.ISIZE ) - return BufferUtil.EMPTY_BUFFER; - - ByteBuffer result = _inflated; - _inflated = null; - return result; - } - /** Called when a chunk of data is inflated. - *

      The default implementation aggregates all the chunks - * into a single buffer returned from {@link #decode(ByteBuffer)}. - * Derived implementations may choose to consume chunks individually - * and return false to prevent further inflation until a subsequent - * call to {@link #decode(ByteBuffer)} or {@link #decodeChunks(ByteBuffer)}. - * - * @param chunk The inflated chunk of data - * @return False if inflating should continue, or True if the call - * to {@link #decodeChunks(ByteBuffer)} or {@link #decode(ByteBuffer)} - * should return, allowing back pressure of compressed data. - */ - protected boolean decodedChunk(ByteBuffer chunk) - { - if (_inflated==null) + if (_inflateds.isEmpty()) { - _inflated=chunk; + if (BufferUtil.isEmpty(_inflated) || _state == State.CRC || _state == State.ISIZE) + return BufferUtil.EMPTY_BUFFER; + ByteBuffer result = _inflated; + _inflated = null; + return result; } else { - int size = _inflated.remaining() + chunk.remaining(); - if (size<=_inflated.capacity()) + _inflateds.add(_inflated); + _inflated = null; + int length = _inflateds.stream().mapToInt(Buffer::remaining).sum(); + ByteBuffer result = acquire(length); + for (ByteBuffer buffer : _inflateds) { - BufferUtil.append(_inflated,chunk); + BufferUtil.append(result, buffer); + release(buffer); + } + _inflateds.clear(); + return result; + } + } + + /** + *

      Called when a chunk of data is inflated.

      + *

      The default implementation aggregates all the chunks + * into a single buffer returned from {@link #decode(ByteBuffer)}.

      + *

      Derived implementations may choose to consume inflated chunks + * individually and return {@code true} from this method to prevent + * further inflation until a subsequent call to {@link #decode(ByteBuffer)} + * or {@link #decodeChunks(ByteBuffer)} is made. + * + * @param chunk the inflated chunk of data + * @return false if inflating should continue, or true if the call + * to {@link #decodeChunks(ByteBuffer)} or {@link #decode(ByteBuffer)} + * should return, allowing to consume the inflated chunk and apply + * backpressure + */ + protected boolean decodedChunk(ByteBuffer chunk) + { + if (_inflated == null) + { + _inflated = chunk; + } + else + { + if (BufferUtil.space(_inflated) >= chunk.remaining()) + { + BufferUtil.append(_inflated, chunk); release(chunk); } else { - ByteBuffer bigger=acquire(size); - int pos=BufferUtil.flipToFill(bigger); - BufferUtil.put(_inflated,bigger); - BufferUtil.put(chunk,bigger); - BufferUtil.flipToFlush(bigger,pos); - release(_inflated); - release(chunk); - _inflated = bigger; + _inflateds.add(_inflated); + _inflated = chunk; } } return false; } /** - * Inflate compressed data. - *

      Inflation continues until the compressed block end is reached, there is no - * more compressed data or a call to {@link #decodedChunk(ByteBuffer)} returns true. - * @param compressed Buffer of compressed data to inflate + *

      Inflates compressed data.

      + *

      Inflation continues until the compressed block end is reached, there is no + * more compressed data or a call to {@link #decodedChunk(ByteBuffer)} returns true.

      + * + * @param compressed the buffer of compressed data to inflate */ protected void decodeChunks(ByteBuffer compressed) { @@ -164,24 +194,24 @@ public class GZIPContentDecoder implements Destroyable } break; } - + case DATA: { while (true) { - if (buffer==null) + if (buffer == null) buffer = acquire(_bufferSize); - + try { - int length = _inflater.inflate(buffer.array(),buffer.arrayOffset(),buffer.capacity()); + int length = _inflater.inflate(buffer.array(), buffer.arrayOffset(), buffer.capacity()); buffer.limit(length); } catch (DataFormatException x) { throw new ZipException(x.getMessage()); } - + if (buffer.hasRemaining()) { ByteBuffer chunk = buffer; @@ -195,7 +225,7 @@ public class GZIPContentDecoder implements Destroyable return; if (compressed.hasArray()) { - _inflater.setInput(compressed.array(),compressed.arrayOffset()+compressed.position(),compressed.remaining()); + _inflater.setInput(compressed.array(), compressed.arrayOffset() + compressed.position(), compressed.remaining()); compressed.position(compressed.limit()); } else @@ -204,7 +234,7 @@ public class GZIPContentDecoder implements Destroyable byte[] input = new byte[compressed.remaining()]; compressed.get(input); _inflater.setInput(input); - } + } } else if (_inflater.finished()) { @@ -218,14 +248,14 @@ public class GZIPContentDecoder implements Destroyable } continue; } - + default: break; } - + if (!compressed.hasRemaining()) break; - + byte currByte = compressed.get(); switch (_state) { @@ -354,7 +384,7 @@ public class GZIPContentDecoder implements Destroyable // TODO ByteBuffer result = output == null ? BufferUtil.EMPTY_BUFFER : ByteBuffer.wrap(output); reset(); - return ; + return; } break; } @@ -369,7 +399,7 @@ public class GZIPContentDecoder implements Destroyable } finally { - if (buffer!=null) + if (buffer != null) release(buffer); } } @@ -398,28 +428,28 @@ public class GZIPContentDecoder implements Destroyable { INITIAL, ID, CM, FLG, MTIME, XFL, OS, FLAGS, EXTRA_LENGTH, EXTRA, NAME, COMMENT, HCRC, DATA, CRC, ISIZE } - + /** - * @param capacity capacity capacity of the allocated ByteBuffer - * @return An indirect buffer of the configured buffersize either from the pool or freshly allocated. + * @param capacity capacity of the ByteBuffer to acquire + * @return a heap buffer of the configured capacity either from the pool or freshly allocated. */ public ByteBuffer acquire(int capacity) { - return _pool==null?BufferUtil.allocate(capacity):_pool.acquire(capacity,false); + return _pool == null ? BufferUtil.allocate(capacity) : _pool.acquire(capacity, false); } - + /** - * Release an allocated buffer. - *

      This method will called {@link ByteBufferPool#release(ByteBuffer)} if a buffer pool has - * been configured. This method should be called once for all buffers returned from {@link #decode(ByteBuffer)} - * or passed to {@link #decodedChunk(ByteBuffer)}. - * @param buffer The buffer to release. + *

      Releases an allocated buffer.

      + *

      This method calls {@link ByteBufferPool#release(ByteBuffer)} if a buffer pool has + * been configured.

      + *

      This method should be called once for all buffers returned from {@link #decode(ByteBuffer)} + * or passed to {@link #decodedChunk(ByteBuffer)}.

      + * + * @param buffer the buffer to release. */ public void release(ByteBuffer buffer) { - @SuppressWarnings("ReferenceEquality") - boolean isTheEmptyBuffer = (buffer==BufferUtil.EMPTY_BUFFER); - if (_pool!=null && !isTheEmptyBuffer) + if (_pool != null && !BufferUtil.isTheEmptyBuffer(buffer)) _pool.release(buffer); } } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java index 47cfb9e5390..4b6128182fc 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,15 +16,14 @@ // ======================================================================== // - package org.eclipse.jetty.http; import org.eclipse.jetty.util.HostPort; - - -/* ------------------------------------------------------------ */ /** + * An HttpField holding a preparsed Host and port number + * + * @see HostPort */ public class HostPortHttpField extends HttpField { @@ -32,25 +31,36 @@ public class HostPortHttpField extends HttpField public HostPortHttpField(String authority) { - this(HttpHeader.HOST,HttpHeader.HOST.asString(),authority); + this(HttpHeader.HOST, HttpHeader.HOST.asString(), authority); } - /* ------------------------------------------------------------ */ protected HostPortHttpField(HttpHeader header, String name, String authority) { - super(header,name,authority); + super(header, name, authority); try { - _hostPort=new HostPort(authority); + _hostPort = new HostPort(authority); } - catch(Exception e) + catch (Exception e) { - throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad HostPort",e); + throw new BadMessageException(HttpStatus.BAD_REQUEST_400, "Bad HostPort", e); } } - /* ------------------------------------------------------------ */ - /** Get the host. + public HostPortHttpField(String host, int port) + { + this(new HostPort(host, port)); + } + + public HostPortHttpField(HostPort hostport) + { + super(HttpHeader.HOST, HttpHeader.HOST.asString(), hostport.toString()); + _hostPort = hostport; + } + + /** + * Get the host. + * * @return the host */ public String getHost() @@ -58,17 +68,19 @@ public class HostPortHttpField extends HttpField return _hostPort.getHost(); } - /* ------------------------------------------------------------ */ - /** Get the port. + /** + * Get the port. + * * @return the port */ public int getPort() { return _hostPort.getPort(); } - - /* ------------------------------------------------------------ */ - /** Get the port. + + /** + * Get the port. + * * @param defaultPort The default port to return if no port set * @return the port */ @@ -76,4 +88,9 @@ public class HostPortHttpField extends HttpField { return _hostPort.getPort(defaultPort); } + + public HostPort getHostPort() + { + return _hostPort; + } } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/Http1FieldPreEncoder.java b/jetty-http/src/main/java/org/eclipse/jetty/http/Http1FieldPreEncoder.java index f8951b44155..41f80514143 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/Http1FieldPreEncoder.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/Http1FieldPreEncoder.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,20 +16,18 @@ // ======================================================================== // - package org.eclipse.jetty.http; -import static java.nio.charset.StandardCharsets.ISO_8859_1; - import java.util.Arrays; +import static java.nio.charset.StandardCharsets.ISO_8859_1; -/* ------------------------------------------------------------ */ /** + * */ public class Http1FieldPreEncoder implements HttpFieldPreEncoder { - /* ------------------------------------------------------------ */ + /** * @see org.eclipse.jetty.http.HttpFieldPreEncoder#getHttpVersion() */ @@ -39,30 +37,30 @@ public class Http1FieldPreEncoder implements HttpFieldPreEncoder return HttpVersion.HTTP_1_0; } - /* ------------------------------------------------------------ */ /** * @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 headerString, String value) { - if (header!=null) + if (header != null) { - int cbl=header.getBytesColonSpace().length; - byte[] bytes=Arrays.copyOf(header.getBytesColonSpace(), cbl+value.length()+2); - System.arraycopy(value.getBytes(ISO_8859_1),0,bytes,cbl,value.length()); - bytes[bytes.length-2]=(byte)'\r'; - bytes[bytes.length-1]=(byte)'\n'; + int cbl = header.getBytesColonSpace().length; + byte[] bytes = Arrays.copyOf(header.getBytesColonSpace(), cbl + value.length() + 2); + System.arraycopy(value.getBytes(ISO_8859_1), 0, bytes, cbl, value.length()); + bytes[bytes.length - 2] = (byte)'\r'; + bytes[bytes.length - 1] = (byte)'\n'; return bytes; } - byte[] n=headerString.getBytes(ISO_8859_1); - byte[] v=value.getBytes(ISO_8859_1); - byte[] bytes=Arrays.copyOf(n,n.length+2+v.length+2); - bytes[n.length]=(byte)':'; - bytes[n.length]=(byte)' '; - bytes[bytes.length-2]=(byte)'\r'; - bytes[bytes.length-1]=(byte)'\n'; + byte[] n = headerString.getBytes(ISO_8859_1); + byte[] v = value.getBytes(ISO_8859_1); + byte[] bytes = Arrays.copyOf(n, n.length + 2 + v.length + 2); + bytes[n.length] = (byte)':'; + bytes[n.length + 1] = (byte)' '; + System.arraycopy(v, 0, bytes, n.length + 2, v.length); + bytes[bytes.length - 2] = (byte)'\r'; + bytes[bytes.length - 1] = (byte)'\n'; return bytes; } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpCompliance.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpCompliance.java index 1c5d92c8ebe..c179555f241 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpCompliance.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpCompliance.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -42,82 +42,99 @@ import org.eclipse.jetty.util.log.Logger; * * The remainder of the list can contain then names of {@link HttpComplianceSection}s to include them in the mode, or prefixed * with a '-' to exclude thm from the mode. Note that Jetty's modes may have some historic minor differences from the strict - * RFC compliance, for example the RFC2616_LEGACY HttpCompliance is defined as + * RFC compliance, for example the RFC2616_LEGACY HttpCompliance is defined as * RFC2616,-FIELD_COLON,-METHOD_CASE_SENSITIVE. *

      - * Note also that the {@link EnumSet} return by {@link HttpCompliance#sections()} is mutable, so that modes may + * Note also that the {@link EnumSet} return by {@link HttpCompliance#sections()} is mutable, so that modes may * be altered in code and will affect all usages of the mode. */ public enum HttpCompliance // TODO in Jetty-10 convert this enum to a class so that extra custom modes can be defined dynamically { - /** A Legacy compliance mode to match jetty's behavior prior to RFC2616 and RFC7230. + /** + * A Legacy compliance mode to match jetty's behavior prior to RFC2616 and RFC7230. */ - LEGACY(sectionsBySpec("0,METHOD_CASE_SENSITIVE")), - - /** The legacy RFC2616 support, which incorrectly excludes - * {@link HttpComplianceSection#METHOD_CASE_SENSITIVE}, + LEGACY(sectionsBySpec("0,METHOD_CASE_SENSITIVE")), + + /** + * The legacy RFC2616 support, which incorrectly excludes + * {@link HttpComplianceSection#METHOD_CASE_SENSITIVE}, * {@link HttpComplianceSection#FIELD_COLON}, * {@link HttpComplianceSection#TRANSFER_ENCODING_WITH_CONTENT_LENGTH}, * {@link HttpComplianceSection#MULTIPLE_CONTENT_LENGTHS}, */ - RFC2616_LEGACY(sectionsBySpec("RFC2616,-FIELD_COLON,-METHOD_CASE_SENSITIVE,-TRANSFER_ENCODING_WITH_CONTENT_LENGTH,-MULTIPLE_CONTENT_LENGTHS")), - - /** The strict RFC2616 support mode */ - RFC2616(sectionsBySpec("RFC2616")), - - /** Jetty's current RFC7230 support, which incorrectly excludes {@link HttpComplianceSection#METHOD_CASE_SENSITIVE} */ + RFC2616_LEGACY(sectionsBySpec("RFC2616,-FIELD_COLON,-METHOD_CASE_SENSITIVE,-TRANSFER_ENCODING_WITH_CONTENT_LENGTH,-MULTIPLE_CONTENT_LENGTHS")), + + /** + * The strict RFC2616 support mode + */ + RFC2616(sectionsBySpec("RFC2616")), + + /** + * Jetty's current RFC7230 support, which incorrectly excludes {@link HttpComplianceSection#METHOD_CASE_SENSITIVE} + */ RFC7230_LEGACY(sectionsBySpec("RFC7230,-METHOD_CASE_SENSITIVE")), - /** The RFC7230 support mode */ + /** + * The RFC7230 support mode + */ RFC7230(sectionsBySpec("RFC7230")), - - /** Custom compliance mode that can be defined with System property org.eclipse.jetty.http.HttpCompliance.CUSTOM0 */ + + /** + * Custom compliance mode that can be defined with System property org.eclipse.jetty.http.HttpCompliance.CUSTOM0 + */ @Deprecated CUSTOM0(sectionsByProperty("CUSTOM0")), - /** Custom compliance mode that can be defined with System property org.eclipse.jetty.http.HttpCompliance.CUSTOM1 */ + /** + * Custom compliance mode that can be defined with System property org.eclipse.jetty.http.HttpCompliance.CUSTOM1 + */ @Deprecated CUSTOM1(sectionsByProperty("CUSTOM1")), - /** Custom compliance mode that can be defined with System property org.eclipse.jetty.http.HttpCompliance.CUSTOM2 */ + /** + * Custom compliance mode that can be defined with System property org.eclipse.jetty.http.HttpCompliance.CUSTOM2 + */ @Deprecated CUSTOM2(sectionsByProperty("CUSTOM2")), - /** Custom compliance mode that can be defined with System property org.eclipse.jetty.http.HttpCompliance.CUSTOM3 */ + /** + * Custom compliance mode that can be defined with System property org.eclipse.jetty.http.HttpCompliance.CUSTOM3 + */ @Deprecated CUSTOM3(sectionsByProperty("CUSTOM3")); - + public static final String VIOLATIONS_ATTR = "org.eclipse.jetty.http.compliance.violations"; private static final Logger LOG = Log.getLogger(HttpParser.class); + private static EnumSet sectionsByProperty(String property) { - String s = System.getProperty(HttpCompliance.class.getName()+property); - return sectionsBySpec(s==null?"*":s); + String s = System.getProperty(HttpCompliance.class.getName() + property); + return sectionsBySpec(s == null ? "*" : s); } static EnumSet sectionsBySpec(String spec) { EnumSet sections; String[] elements = spec.split("\\s*,\\s*"); - int i=0; - - switch(elements[i]) - { + int i = 0; + + switch (elements[i]) + { case "0": sections = EnumSet.noneOf(HttpComplianceSection.class); i++; break; - + case "*": i++; sections = EnumSet.allOf(HttpComplianceSection.class); break; - + case "RFC2616": sections = EnumSet.complementOf(EnumSet.of( - HttpComplianceSection.NO_FIELD_FOLDING, - HttpComplianceSection.NO_HTTP_0_9)); + HttpComplianceSection.NO_FIELD_FOLDING, + HttpComplianceSection.NO_HTTP_0_9)); i++; break; - + case "RFC7230": i++; sections = EnumSet.allOf(HttpComplianceSection.class); @@ -128,29 +145,29 @@ public enum HttpCompliance // TODO in Jetty-10 convert this enum to a class so t break; } - while(i __required = new HashMap<>(); + + private static final Map __required = new HashMap<>(); + static { for (HttpComplianceSection section : HttpComplianceSection.values()) @@ -159,13 +176,13 @@ public enum HttpCompliance // TODO in Jetty-10 convert this enum to a class so t { if (compliance.sections().contains(section)) { - __required.put(section,compliance); + __required.put(section, compliance); break; } } } } - + /** * @param section The section to query * @return The minimum compliance required to enable the section. @@ -174,23 +191,23 @@ public enum HttpCompliance // TODO in Jetty-10 convert this enum to a class so t { return __required.get(section); } - + private final EnumSet _sections; - - private HttpCompliance(EnumSet sections) + + HttpCompliance(EnumSet sections) { _sections = sections; } - + /** * Get the set of {@link HttpComplianceSection}s supported by this compliance mode. This set * is mutable, so it can be modified. Any modification will affect all usages of the mode * within the same {@link ClassLoader}. + * * @return The set of {@link HttpComplianceSection}s supported by this compliance mode. */ public EnumSet sections() { return _sections; } - -} \ No newline at end of file +} diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpComplianceSection.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpComplianceSection.java index 190a4dea7aa..8a735f9c9c9 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpComplianceSection.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpComplianceSection.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,36 +19,36 @@ package org.eclipse.jetty.http; /** + * */ -public enum HttpComplianceSection -{ - CASE_INSENSITIVE_FIELD_VALUE_CACHE("","Use case insensitive field value cache"), - METHOD_CASE_SENSITIVE("https://tools.ietf.org/html/rfc7230#section-3.1.1","Method is case-sensitive"), - FIELD_COLON("https://tools.ietf.org/html/rfc7230#section-3.2","Fields must have a Colon"), - FIELD_NAME_CASE_INSENSITIVE("https://tools.ietf.org/html/rfc7230#section-3.2","Field name is case-insensitive"), - NO_WS_AFTER_FIELD_NAME("https://tools.ietf.org/html/rfc7230#section-3.2.4","Whitespace not allowed after field name"), - NO_FIELD_FOLDING("https://tools.ietf.org/html/rfc7230#section-3.2.4","No line Folding"), - NO_HTTP_0_9("https://tools.ietf.org/html/rfc7230#appendix-A.2","No HTTP/0.9"), - TRANSFER_ENCODING_WITH_CONTENT_LENGTH("https://tools.ietf.org/html/rfc7230#section-3.3.1","Transfer-Encoding and Content-Length"), - MULTIPLE_CONTENT_LENGTHS("https://tools.ietf.org/html/rfc7230#section-3.3.1","Multiple Content-Lengths"); +public enum HttpComplianceSection +{ + CASE_INSENSITIVE_FIELD_VALUE_CACHE("", "Use case insensitive field value cache"), + METHOD_CASE_SENSITIVE("https://tools.ietf.org/html/rfc7230#section-3.1.1", "Method is case-sensitive"), + FIELD_COLON("https://tools.ietf.org/html/rfc7230#section-3.2", "Fields must have a Colon"), + FIELD_NAME_CASE_INSENSITIVE("https://tools.ietf.org/html/rfc7230#section-3.2", "Field name is case-insensitive"), + NO_WS_AFTER_FIELD_NAME("https://tools.ietf.org/html/rfc7230#section-3.2.4", "Whitespace not allowed after field name"), + NO_FIELD_FOLDING("https://tools.ietf.org/html/rfc7230#section-3.2.4", "No line Folding"), + NO_HTTP_0_9("https://tools.ietf.org/html/rfc7230#appendix-A.2", "No HTTP/0.9"), + TRANSFER_ENCODING_WITH_CONTENT_LENGTH("https://tools.ietf.org/html/rfc7230#section-3.3.1", "Transfer-Encoding and Content-Length"), + MULTIPLE_CONTENT_LENGTHS("https://tools.ietf.org/html/rfc7230#section-3.3.1", "Multiple Content-Lengths"); final String url; final String description; - - HttpComplianceSection(String url,String description) + + HttpComplianceSection(String url, String description) { this.url = url; this.description = description; } - + public String getURL() { return url; } - + public String getDescription() { return description; } - } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpContent.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpContent.java index 53822a4aca2..689bc9c301d 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpContent.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpContent.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -27,47 +27,57 @@ import java.util.Map; import org.eclipse.jetty.http.MimeTypes.Type; import org.eclipse.jetty.util.resource.Resource; -/* ------------------------------------------------------------ */ -/** HttpContent interface. - *

      This information represents all the information about a +/** + * HttpContent interface. + *

      This information represents all the information about a * static resource that is needed to evaluate conditional headers * and to serve the content if need be. It can be implemented - * either transiently (values and fields generated on demand) or + * either transiently (values and fields generated on demand) or * persistently (values and fields pre-generated in anticipation of * reuse in from a cache). - *

      - * + *

      */ public interface HttpContent { HttpField getContentType(); + String getContentTypeValue(); + String getCharacterEncoding(); + Type getMimeType(); HttpField getContentEncoding(); + String getContentEncodingValue(); - + HttpField getContentLength(); + long getContentLengthValue(); - + HttpField getLastModified(); + String getLastModifiedValue(); - + HttpField getETag(); + String getETagValue(); - + ByteBuffer getIndirectBuffer(); + ByteBuffer getDirectBuffer(); + Resource getResource(); + InputStream getInputStream() throws IOException; + ReadableByteChannel getReadableByteChannel() throws IOException; + void release(); - Map getPrecompressedContents(); - - - public interface ContentFactory + Map getPrecompressedContents(); + + interface ContentFactory { /** * @param path The path within the context to the resource @@ -76,6 +86,6 @@ public interface HttpContent * @return A {@link HttpContent} * @throws IOException if unable to get content */ - HttpContent getContent(String path,int maxBuffer) throws IOException; + HttpContent getContent(String path, int maxBuffer) throws IOException; } } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpCookie.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpCookie.java index 33517ccfd2d..736a18473d1 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpCookie.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpCookie.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,10 +18,47 @@ package org.eclipse.jetty.http; +import java.util.List; import java.util.concurrent.TimeUnit; +import org.eclipse.jetty.util.QuotedStringTokenizer; +import org.eclipse.jetty.util.StringUtil; + +// TODO consider replacing this with java.net.HttpCookie public class HttpCookie { + private static final String __COOKIE_DELIM = "\",;\\ \t"; + private static final String __01Jan1970_COOKIE = DateGenerator.formatCookieDate(0).trim(); + + /** + *If this string is found within the comment parsed with {@link #isHttpOnlyInComment(String)} the check will return true + **/ + private static final String HTTP_ONLY_COMMENT = "__HTTP_ONLY__"; + /** + *These strings are used by {@link #getSameSiteFromComment(String)} to check for a SameSite specifier in the comment + **/ + private static final String SAME_SITE_COMMENT = "__SAME_SITE_"; + private static final String SAME_SITE_NONE_COMMENT = SAME_SITE_COMMENT + "NONE__"; + private static final String SAME_SITE_LAX_COMMENT = SAME_SITE_COMMENT + "LAX__"; + private static final String SAME_SITE_STRICT_COMMENT = SAME_SITE_COMMENT + "STRICT__"; + + public enum SameSite + { + NONE("None"), STRICT("Strict"), LAX("Lax"); + + private String attributeValue; + + SameSite(String attributeValue) + { + this.attributeValue = attributeValue; + } + + public String getAttributeValue() + { + return this.attributeValue; + } + } + private final String _name; private final String _value; private final String _comment; @@ -32,6 +69,7 @@ public class HttpCookie private final int _version; private final boolean _httpOnly; private final long _expiration; + private final SameSite _sameSite; public HttpCookie(String name, String value) { @@ -54,6 +92,11 @@ public class HttpCookie } public HttpCookie(String name, String value, String domain, String path, long maxAge, boolean httpOnly, boolean secure, String comment, int version) + { + this(name, value, domain, path, maxAge, httpOnly, secure, comment, version, null); + } + + public HttpCookie(String name, String value, String domain, String path, long maxAge, boolean httpOnly, boolean secure, String comment, int version, SameSite sameSite) { _name = name; _value = value; @@ -65,6 +108,29 @@ public class HttpCookie _comment = comment; _version = version; _expiration = maxAge < 0 ? -1 : System.nanoTime() + TimeUnit.SECONDS.toNanos(maxAge); + _sameSite = sameSite; + } + + public HttpCookie(String setCookie) + { + List cookies = java.net.HttpCookie.parse(setCookie); + if (cookies.size() != 1) + throw new IllegalStateException(); + + java.net.HttpCookie cookie = cookies.get(0); + + _name = cookie.getName(); + _value = cookie.getValue(); + _domain = cookie.getDomain(); + _path = cookie.getPath(); + _maxAge = cookie.getMaxAge(); + _httpOnly = cookie.isHttpOnly(); + _secure = cookie.getSecure(); + _comment = cookie.getComment(); + _version = cookie.getVersion(); + _expiration = _maxAge < 0 ? -1 : System.nanoTime() + TimeUnit.SECONDS.toNanos(_maxAge); + // support for SameSite values has not yet been added to java.net.HttpCookie + _sameSite = getSameSiteFromComment(cookie.getComment()); } /** @@ -131,6 +197,14 @@ public class HttpCookie return _version; } + /** + * @return the cookie SameSite enum attribute + */ + public SameSite getSameSite() + { + return _sameSite; + } + /** * @return whether the cookie is valid for the http protocol only */ @@ -161,4 +235,249 @@ public class HttpCookie builder.append(";$Path=").append(getPath()); return builder.toString(); } + + private static void quoteOnlyOrAppend(StringBuilder buf, String s, boolean quote) + { + if (quote) + QuotedStringTokenizer.quoteOnly(buf, s); + else + buf.append(s); + } + + /** + * Does a cookie value need to be quoted? + * + * @param s value string + * @return true if quoted; + * @throws IllegalArgumentException If there a control characters in the string + */ + private static boolean isQuoteNeededForCookie(String s) + { + if (s == null || s.length() == 0) + return true; + + if (QuotedStringTokenizer.isQuoted(s)) + return false; + + for (int i = 0; i < s.length(); i++) + { + char c = s.charAt(i); + if (__COOKIE_DELIM.indexOf(c) >= 0) + return true; + + if (c < 0x20 || c >= 0x7f) + throw new IllegalArgumentException("Illegal character in cookie value"); + } + + return false; + } + + public String getSetCookie(CookieCompliance compliance) + { + switch (compliance) + { + case RFC2965: + return getRFC2965SetCookie(); + case RFC6265: + return getRFC6265SetCookie(); + default: + throw new IllegalStateException(); + } + } + + public String getRFC2965SetCookie() + { + // Check arguments + if (_name == null || _name.length() == 0) + throw new IllegalArgumentException("Bad cookie name"); + + // Format value and params + StringBuilder buf = new StringBuilder(); + + // Name is checked for legality by servlet spec, but can also be passed directly so check again for quoting + boolean quoteName = isQuoteNeededForCookie(_name); + quoteOnlyOrAppend(buf, _name, quoteName); + + buf.append('='); + + // Append the value + boolean quoteValue = isQuoteNeededForCookie(_value); + quoteOnlyOrAppend(buf, _value, quoteValue); + + // Look for domain and path fields and check if they need to be quoted + boolean hasDomain = _domain != null && _domain.length() > 0; + boolean quoteDomain = hasDomain && isQuoteNeededForCookie(_domain); + boolean hasPath = _path != null && _path.length() > 0; + boolean quotePath = hasPath && isQuoteNeededForCookie(_path); + + // Upgrade the version if we have a comment or we need to quote value/path/domain or if they were already quoted + int version = _version; + if (version == 0 && (_comment != null || quoteName || quoteValue || quoteDomain || quotePath || + QuotedStringTokenizer.isQuoted(_name) || QuotedStringTokenizer.isQuoted(_value) || + QuotedStringTokenizer.isQuoted(_path) || QuotedStringTokenizer.isQuoted(_domain))) + version = 1; + + // Append version + if (version == 1) + buf.append(";Version=1"); + else if (version > 1) + buf.append(";Version=").append(version); + + // Append path + if (hasPath) + { + buf.append(";Path="); + quoteOnlyOrAppend(buf, _path, quotePath); + } + + // Append domain + if (hasDomain) + { + buf.append(";Domain="); + quoteOnlyOrAppend(buf, _domain, quoteDomain); + } + + // Handle max-age and/or expires + if (_maxAge >= 0) + { + // Always use expires + // This is required as some browser (M$ this means you!) don't handle max-age even with v1 cookies + buf.append(";Expires="); + if (_maxAge == 0) + buf.append(__01Jan1970_COOKIE); + else + DateGenerator.formatCookieDate(buf, System.currentTimeMillis() + 1000L * _maxAge); + + // for v1 cookies, also send max-age + if (version >= 1) + { + buf.append(";Max-Age="); + buf.append(_maxAge); + } + } + + // add the other fields + if (_secure) + buf.append(";Secure"); + if (_httpOnly) + buf.append(";HttpOnly"); + if (_comment != null) + { + buf.append(";Comment="); + quoteOnlyOrAppend(buf, _comment, isQuoteNeededForCookie(_comment)); + } + return buf.toString(); + } + + public String getRFC6265SetCookie() + { + // Check arguments + if (_name == null || _name.length() == 0) + throw new IllegalArgumentException("Bad cookie name"); + + // Name is checked for legality by servlet spec, but can also be passed directly so check again for quoting + // Per RFC6265, Cookie.name follows RFC2616 Section 2.2 token rules + Syntax.requireValidRFC2616Token(_name, "RFC6265 Cookie name"); + // Ensure that Per RFC6265, Cookie.value follows syntax rules + Syntax.requireValidRFC6265CookieValue(_value); + + // Format value and params + StringBuilder buf = new StringBuilder(); + buf.append(_name).append('=').append(_value == null ? "" : _value); + + // Append path + if (_path != null && _path.length() > 0) + buf.append("; Path=").append(_path); + + // Append domain + if (_domain != null && _domain.length() > 0) + buf.append("; Domain=").append(_domain); + + // Handle max-age and/or expires + if (_maxAge >= 0) + { + // Always use expires + // This is required as some browser (M$ this means you!) don't handle max-age even with v1 cookies + buf.append("; Expires="); + if (_maxAge == 0) + buf.append(__01Jan1970_COOKIE); + else + DateGenerator.formatCookieDate(buf, System.currentTimeMillis() + 1000L * _maxAge); + + buf.append("; Max-Age="); + buf.append(_maxAge); + } + + // add the other fields + if (_secure) + buf.append("; Secure"); + if (_httpOnly) + buf.append("; HttpOnly"); + if (_sameSite != null) + { + buf.append("; SameSite="); + buf.append(_sameSite.getAttributeValue()); + } + + return buf.toString(); + } + + public static boolean isHttpOnlyInComment(String comment) + { + return comment != null && comment.contains(HTTP_ONLY_COMMENT); + } + + public static SameSite getSameSiteFromComment(String comment) + { + if (comment != null) + { + if (comment.contains(SAME_SITE_NONE_COMMENT)) + { + return SameSite.NONE; + } + if (comment.contains(SAME_SITE_LAX_COMMENT)) + { + return SameSite.LAX; + } + if (comment.contains(SAME_SITE_STRICT_COMMENT)) + { + return SameSite.STRICT; + } + } + + return null; + } + + public static String getCommentWithoutAttributes(String comment) + { + if (comment == null) + { + return null; + } + + String strippedComment = comment.trim(); + + strippedComment = StringUtil.strip(strippedComment, HTTP_ONLY_COMMENT); + strippedComment = StringUtil.strip(strippedComment, SAME_SITE_NONE_COMMENT); + strippedComment = StringUtil.strip(strippedComment, SAME_SITE_LAX_COMMENT); + strippedComment = StringUtil.strip(strippedComment, SAME_SITE_STRICT_COMMENT); + + return strippedComment.length() == 0 ? null : strippedComment; + } + + public static class SetCookieHttpField extends HttpField + { + final HttpCookie _cookie; + + public SetCookieHttpField(HttpCookie cookie, CookieCompliance compliance) + { + super(HttpHeader.SET_COOKIE, cookie.getSetCookie(compliance)); + this._cookie = cookie; + } + + public HttpCookie getHttpCookie() + { + return _cookie; + } + } } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java index 58bd7f7e547..05a2783dfdb 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -22,11 +22,12 @@ import java.util.Objects; import org.eclipse.jetty.util.StringUtil; -/** A HTTP Field +/** + * An HTTP Field */ public class HttpField { - private final static String __zeroquality="q=0"; + private static final String ZEROQUALITY = "q=0"; private final HttpHeader _header; private final String _name; private final String _value; @@ -36,23 +37,26 @@ public class HttpField public HttpField(HttpHeader header, String name, String value) { _header = header; - _name = name; + if (_header != null && name == null) + _name = _header.asString(); + else + _name = Objects.requireNonNull(name); _value = value; } public HttpField(HttpHeader header, String value) { - this(header,header.asString(),value); + this(header, header.asString(), value); } public HttpField(HttpHeader header, HttpHeaderValue value) { - this(header,header.asString(),value.asString()); + this(header, header.asString(), value.asString()); } public HttpField(String name, String value) { - this(HttpHeader.CACHE.get(name),name,value); + this(HttpHeader.CACHE.get(name), name, value); } public HttpHeader getHeader() @@ -84,13 +88,14 @@ public class HttpField { if (_value == null) return null; - - QuotedCSV list = new QuotedCSV(false,_value); + + QuotedCSV list = new QuotedCSV(false, _value); return list.getValues().toArray(new String[list.size()]); } /** * Look for a value in a possible multi valued field + * * @param search Values to search for (case insensitive) * @return True iff the value is contained in the field value entirely or * as an element of a quoted comma separated list. List element parameters (eg qualities) are ignored, @@ -98,41 +103,41 @@ public class HttpField */ public boolean contains(String search) { - if (search==null) - return _value==null; - if (search.length()==0) + if (search == null) + return _value == null; + if (search.isEmpty()) return false; - if (_value==null) + if (_value == null) return false; if (search.equals(_value)) return true; search = StringUtil.asciiToLowerCase(search); - int state=0; - int match=0; - int param=0; + int state = 0; + int match = 0; + int param = 0; - for (int i=0;i<_value.length();i++) + for (int i = 0; i < _value.length(); i++) { char c = _value.charAt(i); - switch(state) + switch (state) { case 0: // initial white space - switch(c) + switch (c) { case '"': // open quote - match=0; - state=2; + match = 0; + state = 2; break; case ',': // ignore leading empty field break; case ';': // ignore leading empty field parameter - param=-1; - match=-1; - state=5; + param = -1; + match = -1; + state = 5; break; case ' ': // more white space @@ -140,106 +145,105 @@ public class HttpField break; default: // character - match = Character.toLowerCase(c)==search.charAt(0)?1:-1; - state=1; + match = Character.toLowerCase(c) == search.charAt(0) ? 1 : -1; + state = 1; break; } break; case 1: // In token - switch(c) + switch (c) { case ',': // next field // Have we matched the token? - if (match==search.length()) + if (match == search.length()) return true; - state=0; + state = 0; break; case ';': - param=match>=0?0:-1; - state=5; // parameter + param = match >= 0 ? 0 : -1; + state = 5; // parameter break; default: - if (match>0) + if (match > 0) { - if (match=0) + if (match >= 0) { - if (match=0) + if (match >= 0) { - if (match=0) + if (param >= 0) { - if (param<__zeroquality.length()) - param=Character.toLowerCase(c)==__zeroquality.charAt(param)?(param+1):-1; - else if (c!='0'&&c!='.') - param=-1; + if (param < ZEROQUALITY.length()) + param = Character.toLowerCase(c) == ZEROQUALITY.charAt(param) ? (param + 1) : -1; + else if (c != '0' && c != '.') + param = -1; } - } break; @@ -263,31 +266,25 @@ public class HttpField } } - return param!=__zeroquality.length() && match==search.length(); + return param != ZEROQUALITY.length() && match == search.length(); } - @Override public String toString() { - String v=getValue(); - return getName() + ": " + (v==null?"":v); + String v = getValue(); + return getName() + ": " + (v == null ? "" : v); } public boolean isSameName(HttpField field) { - @SuppressWarnings("ReferenceEquality") - boolean sameObject = (field==this); - - if (field==null) + if (field == null) return false; - if (sameObject) + if (field == this) return true; - if (_header!=null && _header==field.getHeader()) + if (_header != null && _header == field.getHeader()) return true; - if (_name.equalsIgnoreCase(field.getName())) - return true; - return false; + return _name.equalsIgnoreCase(field.getName()); } private int nameHashCode() @@ -314,7 +311,7 @@ public class HttpField public int hashCode() { int vhc = Objects.hashCode(_value); - if (_header==null) + if (_header == null) return vhc ^ nameHashCode(); return vhc ^ _header.hashCode(); } @@ -322,18 +319,16 @@ public class HttpField @Override public boolean equals(Object o) { - if (o==this) + if (o == this) return true; if (!(o instanceof HttpField)) return false; - HttpField field=(HttpField)o; - if (_header!=field.getHeader()) + HttpField field = (HttpField)o; + if (_header != field.getHeader()) return false; if (!_name.equalsIgnoreCase(field.getName())) return false; - if (_value==null && field.getValue()!=null) - return false; - return Objects.equals(_value,field.getValue()); + return Objects.equals(_value, field.getValue()); } public static class IntValueHttpField extends HttpField @@ -342,23 +337,23 @@ public class HttpField public IntValueHttpField(HttpHeader header, String name, String value, int intValue) { - super(header,name,value); - _int=intValue; + super(header, name, value); + _int = intValue; } public IntValueHttpField(HttpHeader header, String name, String value) { - this(header,name,value,Integer.parseInt(value)); + this(header, name, value, Integer.parseInt(value)); } public IntValueHttpField(HttpHeader header, String name, int intValue) { - this(header,name,Integer.toString(intValue),intValue); + this(header, name, Integer.toString(intValue), intValue); } public IntValueHttpField(HttpHeader header, int value) { - this(header,header.asString(),value); + this(header, header.asString(), value); } @Override @@ -380,23 +375,23 @@ public class HttpField public LongValueHttpField(HttpHeader header, String name, String value, long longValue) { - super(header,name,value); - _long=longValue; + super(header, name, value); + _long = longValue; } public LongValueHttpField(HttpHeader header, String name, String value) { - this(header,name,value,Long.parseLong(value)); + this(header, name, value, Long.parseLong(value)); } public LongValueHttpField(HttpHeader header, String name, long value) { - this(header,name,Long.toString(value),value); + this(header, name, Long.toString(value), value); } - public LongValueHttpField(HttpHeader header,long value) + public LongValueHttpField(HttpHeader header, long value) { - this(header,header.asString(),value); + this(header, header.asString(), value); } @Override diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFieldPreEncoder.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFieldPreEncoder.java index 8961932fd3a..c22fc7ae960 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFieldPreEncoder.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFieldPreEncoder.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,21 +16,22 @@ // ======================================================================== // - package org.eclipse.jetty.http; - -/* ------------------------------------------------------------ */ -/** Interface to pre-encode HttpFields. Used by {@link PreEncodedHttpField} +/** + * Interface to pre-encode HttpFields. Used by {@link PreEncodedHttpField} */ public interface HttpFieldPreEncoder { - /* ------------------------------------------------------------ */ - /** The major version this encoder is for. Both HTTP/1.0 and HTTP/1.1 + + /** + * The major version this encoder is for. Both HTTP/1.0 and HTTP/1.1 * use the same field encoding, so the {@link HttpVersion#HTTP_1_0} should * be return for all HTTP/1.x encodings. + * * @return The major version this encoder is for. */ HttpVersion getHttpVersion(); + byte[] getEncodedField(HttpHeader header, String headerString, String value); -} \ No newline at end of file +} diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java index 19b77a84883..dd314a33dbe 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -31,8 +31,8 @@ import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; import java.util.StringTokenizer; +import java.util.function.ToIntFunction; import java.util.stream.Stream; -import java.util.stream.StreamSupport; import org.eclipse.jetty.util.ArrayTernaryTrie; import org.eclipse.jetty.util.QuotedStringTokenizer; @@ -40,15 +40,13 @@ import org.eclipse.jetty.util.Trie; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; - /** * HTTP Fields. A collection of HTTP header and or Trailer fields. * *

      This class is not synchronized as it is expected that modifications will only be performed by a * single thread. - * - *

      The cookie handling provided by this class is guided by the Servlet specification and RFC6265. * + *

      The cookie handling provided by this class is guided by the Servlet specification and RFC6265. */ public class HttpFields implements Iterable { @@ -59,76 +57,79 @@ public class HttpFields implements Iterable private HttpField[] _fields; private int _size; - + /** * Initialize an empty HttpFields. */ public HttpFields() { - _fields=new HttpField[20]; + this(16); // Based on small sample of Chrome requests. } - + /** * Initialize an empty HttpFields. - * + * * @param capacity the capacity of the http fields */ public HttpFields(int capacity) { - _fields=new HttpField[capacity]; + _fields = new HttpField[capacity]; } - + /** * Initialize HttpFields from copy. - * + * * @param fields the fields to copy data from */ public HttpFields(HttpFields fields) { - _fields=Arrays.copyOf(fields._fields,fields._fields.length+10); - _size=fields._size; + _fields = Arrays.copyOf(fields._fields, fields._fields.length); + _size = fields._size; } public int size() { return _size; } - + @Override public Iterator iterator() { - return new Itr(); + return new ListItr(); } public ListIterator listIterator() { - return new Itr(); + return new ListItr(); } - - + public Stream stream() { - return StreamSupport.stream(Arrays.spliterator(_fields,0,_size),false); + return Arrays.stream(_fields).limit(_size); } /** * Get Collection of header names. + * * @return the unique set of field names. */ public Set getFieldNamesCollection() { - final Set set = new HashSet<>(_size); - for (HttpField f : this) + Set set = null; + for (int i = 0; i < _size; i++) { - if (f!=null) - set.add(f.getName()); + HttpField f = _fields[i]; + if (set == null) + set = new HashSet<>(); + set.add(f.getName()); } - return set; + return set == null ? Collections.emptySet() : set; } /** * Get enumeration of header _names. Returns an enumeration of strings representing the header * _names for this request. + * * @return an enumeration of field names */ public Enumeration getFieldNames() @@ -138,22 +139,23 @@ public class HttpFields implements Iterable /** * Get a Field by index. - * @param index the field index + * + * @param index the field index * @return A Field value or null if the Field value has not been set */ public HttpField getField(int index) { - if (index>=_size) + if (index >= _size) throw new NoSuchElementException(); return _fields[index]; } public HttpField getField(HttpHeader header) { - for (int i=0;i<_size;i++) + for (int i = 0; i < _size; i++) { - HttpField f=_fields[i]; - if (f.getHeader()==header) + HttpField f = _fields[i]; + if (f.getHeader() == header) return f; } return null; @@ -161,21 +163,37 @@ public class HttpFields implements Iterable public HttpField getField(String name) { - for (int i=0;i<_size;i++) + for (int i = 0; i < _size; i++) { - HttpField f=_fields[i]; + HttpField f = _fields[i]; if (f.getName().equalsIgnoreCase(name)) return f; } return null; } + public List getFields(HttpHeader header) + { + List fields = null; + for (int i = 0; i < _size; i++) + { + HttpField f = _fields[i]; + if (f.getHeader() == header) + { + if (fields == null) + fields = new ArrayList<>(); + fields.add(f); + } + } + return fields == null ? Collections.emptyList() : fields; + } + public boolean contains(HttpField field) { - for (int i=_size;i-->0;) + for (int i = _size; i-- > 0; ) { - HttpField f=_fields[i]; - if (f.isSameName(field) && (f.equals(field)||f.contains(field.getValue()))) + HttpField f = _fields[i]; + if (f.isSameName(field) && (f.equals(field) || f.contains(field.getValue()))) return true; } return false; @@ -183,20 +201,20 @@ public class HttpFields implements Iterable public boolean contains(HttpHeader header, String value) { - for (int i=_size;i-->0;) + for (int i = _size; i-- > 0; ) { - HttpField f=_fields[i]; - if (f.getHeader()==header && f.contains(value)) + HttpField f = _fields[i]; + if (f.getHeader() == header && f.contains(value)) return true; } return false; } - + public boolean contains(String name, String value) { - for (int i=_size;i-->0;) + for (int i = _size; i-- > 0; ) { - HttpField f=_fields[i]; + HttpField f = _fields[i]; if (f.getName().equalsIgnoreCase(name) && f.contains(value)) return true; } @@ -205,20 +223,20 @@ public class HttpFields implements Iterable public boolean contains(HttpHeader header) { - for (int i=_size;i-->0;) + for (int i = _size; i-- > 0; ) { - HttpField f=_fields[i]; - if (f.getHeader()==header) + HttpField f = _fields[i]; + if (f.getHeader() == header) return true; } return false; } - + public boolean containsKey(String name) { - for (int i=_size;i-->0;) + for (int i = _size; i-- > 0; ) { - HttpField f=_fields[i]; + HttpField f = _fields[i]; if (f.getName().equalsIgnoreCase(name)) return true; } @@ -230,13 +248,13 @@ public class HttpFields implements Iterable { return get(header); } - + public String get(HttpHeader header) { - for (int i=0;i<_size;i++) + for (int i = 0; i < _size; i++) { - HttpField f=_fields[i]; - if (f.getHeader()==header) + HttpField f = _fields[i]; + if (f.getHeader() == header) return f.getValue(); } return null; @@ -247,12 +265,12 @@ public class HttpFields implements Iterable { return get(name); } - + public String get(String header) { - for (int i=0;i<_size;i++) + for (int i = 0; i < _size; i++) { - HttpField f=_fields[i]; + HttpField f = _fields[i]; if (f.getName().equalsIgnoreCase(header)) return f.getValue(); } @@ -262,100 +280,109 @@ public class HttpFields implements Iterable /** * Get multiple header of the same name * - * @return List the values * @param header the header + * @return List the values */ public List getValuesList(HttpHeader header) { final List list = new ArrayList<>(); - for (HttpField f : this) - if (f.getHeader()==header) + for (int i = 0; i < _size; i++) + { + HttpField f = _fields[i]; + if (f.getHeader() == header) list.add(f.getValue()); + } return list; } - + /** * Get multiple header of the same name - * - * @return List the header values + * * @param name the case-insensitive field name + * @return List the header values */ public List getValuesList(String name) { final List list = new ArrayList<>(); - for (HttpField f : this) + for (int i = 0; i < _size; i++) + { + HttpField f = _fields[i]; if (f.getName().equalsIgnoreCase(name)) list.add(f.getValue()); + } return list; } - /** * Add comma separated values, but only if not already * present. + * * @param header The header to add the value(s) to * @param values The value(s) to add * @return True if headers were modified */ - public boolean addCSV(HttpHeader header,String... values) + public boolean addCSV(HttpHeader header, String... values) { QuotedCSV existing = null; - for (HttpField f : this) + for (int i = 0; i < _size; i++) { - if (f.getHeader()==header) + HttpField f = _fields[i]; + if (f.getHeader() == header) { - if (existing==null) + if (existing == null) existing = new QuotedCSV(false); existing.addValue(f.getValue()); } } - - String value = addCSV(existing,values); - if (value!=null) + + String value = addCSV(existing, values); + if (value != null) { - add(header,value); - return true; - } - return false; - } - - /** - * Add comma separated values, but only if not already - * present. - * @param name The header to add the value(s) to - * @param values The value(s) to add - * @return True if headers were modified - */ - public boolean addCSV(String name,String... values) - { - QuotedCSV existing = null; - for (HttpField f : this) - { - if (f.getName().equalsIgnoreCase(name)) - { - if (existing==null) - existing = new QuotedCSV(false); - existing.addValue(f.getValue()); - } - } - String value = addCSV(existing,values); - if (value!=null) - { - add(name,value); + add(header, value); return true; } return false; } - protected String addCSV(QuotedCSV existing,String... values) + /** + * Add comma separated values, but only if not already + * present. + * + * @param name The header to add the value(s) to + * @param values The value(s) to add + * @return True if headers were modified + */ + public boolean addCSV(String name, String... values) + { + QuotedCSV existing = null; + for (int i = 0; i < _size; i++) + { + HttpField f = _fields[i]; + if (f.getName().equalsIgnoreCase(name)) + { + if (existing == null) + existing = new QuotedCSV(false); + existing.addValue(f.getValue()); + } + } + String value = addCSV(existing, values); + if (value != null) + { + add(name, value); + return true; + } + return false; + } + + protected String addCSV(QuotedCSV existing, String... values) { // remove any existing values from the new values boolean add = true; - if (existing!=null && !existing.isEmpty()) + if (existing != null && !existing.isEmpty()) { add = false; - - for (int i=values.length;i-->0;) + + for (int i = values.length; i-- > 0; ) { String unquoted = QuotedCSV.unquote(values[i]); if (existing.getValues().contains(unquoted)) @@ -364,100 +391,113 @@ public class HttpFields implements Iterable add = true; } } - + if (add) { StringBuilder value = new StringBuilder(); - for (String v:values) + for (String v : values) { - if (v==null) + if (v == null) continue; - if (value.length()>0) + if (value.length() > 0) value.append(", "); value.append(v); } - if (value.length()>0) + if (value.length() > 0) return value.toString(); } - + return null; } - + /** - * Get multiple field values of the same name, split + * Get multiple field values of the same name, split * as a {@link QuotedCSV} * - * @return List the values with OWS stripped * @param header The header * @param keepQuotes True if the fields are kept quoted + * @return List the values with OWS stripped */ - public List getCSV(HttpHeader header,boolean keepQuotes) + public List getCSV(HttpHeader header, boolean keepQuotes) { QuotedCSV values = null; for (HttpField f : this) { - if (f.getHeader()==header) + if (f.getHeader() == header) { - if (values==null) + if (values == null) values = new QuotedCSV(keepQuotes); values.addValue(f.getValue()); } } - return values==null?Collections.emptyList():values.getValues(); + return values == null ? Collections.emptyList() : values.getValues(); } /** * Get multiple field values of the same name * as a {@link QuotedCSV} * - * @return List the values with OWS stripped * @param name the case-insensitive field name * @param keepQuotes True if the fields are kept quoted + * @return List the values with OWS stripped */ - public List getCSV(String name,boolean keepQuotes) + public List getCSV(String name, boolean keepQuotes) { QuotedCSV values = null; for (HttpField f : this) { if (f.getName().equalsIgnoreCase(name)) { - if (values==null) + if (values == null) values = new QuotedCSV(keepQuotes); values.addValue(f.getValue()); } } - return values==null?Collections.emptyList():values.getValues(); + return values == null ? Collections.emptyList() : values.getValues(); } /** * Get multiple field values of the same name, split and * sorted as a {@link QuotedQualityCSV} * - * @return List the values in quality order with the q param and OWS stripped * @param header The header + * @return List the values in quality order with the q param and OWS stripped */ public List getQualityCSV(HttpHeader header) + { + return getQualityCSV(header, null); + } + + /** + * Get multiple field values of the same name, split and + * sorted as a {@link QuotedQualityCSV} + * + * @param header The header + * @param secondaryOrdering Function to apply an ordering other than specified by quality + * @return List the values in quality order with the q param and OWS stripped + */ + public List getQualityCSV(HttpHeader header, ToIntFunction secondaryOrdering) { QuotedQualityCSV values = null; for (HttpField f : this) { - if (f.getHeader()==header) + if (f.getHeader() == header) { - if (values==null) - values = new QuotedQualityCSV(); + if (values == null) + values = new QuotedQualityCSV(secondaryOrdering); values.addValue(f.getValue()); } } - return values==null?Collections.emptyList():values.getValues(); + return values == null ? Collections.emptyList() : values.getValues(); } /** * Get multiple field values of the same name, split and * sorted as a {@link QuotedQualityCSV} * - * @return List the values in quality order with the q param and OWS stripped * @param name the case-insensitive field name + * @return List the values in quality order with the q param and OWS stripped */ public List getQualityCSV(String name) { @@ -466,46 +506,46 @@ public class HttpFields implements Iterable { if (f.getName().equalsIgnoreCase(name)) { - if (values==null) + if (values == null) values = new QuotedQualityCSV(); values.addValue(f.getValue()); } } - return values==null?Collections.emptyList():values.getValues(); + return values == null ? Collections.emptyList() : values.getValues(); } /** * Get multi headers * - * @return Enumeration of the values * @param name the case-insensitive field name + * @return Enumeration of the values */ public Enumeration getValues(final String name) { - for (int i=0;i<_size;i++) + for (int i = 0; i < _size; i++) { final HttpField f = _fields[i]; - - if (f.getName().equalsIgnoreCase(name) && f.getValue()!=null) + + if (f.getName().equalsIgnoreCase(name) && f.getValue() != null) { - final int first=i; + final int first = i; return new Enumeration() { - HttpField field=f; - int i = first+1; + HttpField field = f; + int i = first + 1; @Override public boolean hasMoreElements() { - if (field==null) + if (field == null) { - while (i<_size) + while (i < _size) { - field=_fields[i++]; - if (field.getName().equalsIgnoreCase(name) && field.getValue()!=null) + field = _fields[i++]; + if (field.getName().equalsIgnoreCase(name) && field.getValue() != null) return true; } - field=null; + field = null; return false; } return true; @@ -516,8 +556,8 @@ public class HttpFields implements Iterable { if (hasMoreElements()) { - String value=field.getValue(); - field=null; + String value = field.getValue(); + field = null; return value; } throw new NoSuchElementException(); @@ -526,7 +566,7 @@ public class HttpFields implements Iterable } } - List empty=Collections.emptyList(); + List empty = Collections.emptyList(); return Collections.enumeration(empty); } @@ -552,14 +592,16 @@ public class HttpFields implements Iterable @Override public boolean hasMoreElements() { - if (tok != null && tok.hasMoreElements()) return true; + if (tok != null && tok.hasMoreElements()) + return true; while (e.hasMoreElements()) { String value = e.nextElement(); - if (value!=null) + if (value != null) { tok = new QuotedStringTokenizer(value, separators, false, false); - if (tok.hasMoreElements()) return true; + if (tok.hasMoreElements()) + return true; } } tok = null; @@ -569,9 +611,11 @@ public class HttpFields implements Iterable @Override public String nextElement() throws NoSuchElementException { - if (!hasMoreElements()) throw new NoSuchElementException(); - String next = (String) tok.nextElement(); - if (next != null) next = next.trim(); + if (!hasMoreElements()) + throw new NoSuchElementException(); + String next = (String)tok.nextElement(); + if (next != null) + next = next.trim(); return next; } }; @@ -579,27 +623,27 @@ public class HttpFields implements Iterable public void put(HttpField field) { - boolean put=false; - for (int i=_size;i-->0;) + boolean put = false; + for (int i = _size; i-- > 0; ) { - HttpField f=_fields[i]; + HttpField f = _fields[i]; if (f.isSameName(field)) { if (put) { - System.arraycopy(_fields,i+1,_fields,i,--_size-i); + System.arraycopy(_fields, i + 1, _fields, i, --_size - i); } else { - _fields[i]=field; - put=true; + _fields[i] = field; + put = true; } } } if (!put) add(field); } - + /** * Set a field. * @@ -616,7 +660,7 @@ public class HttpFields implements Iterable public void put(HttpHeader header, HttpHeaderValue value) { - put(header,value.toString()); + put(header, value.toString()); } /** @@ -643,8 +687,10 @@ public class HttpFields implements Iterable { remove(name); for (String v : list) - if (v!=null) - add(name,v); + { + if (v != null) + add(name, v); + } } /** @@ -665,7 +711,7 @@ public class HttpFields implements Iterable public void add(HttpHeader header, HttpHeaderValue value) { - add(header,value.toString()); + add(header, value.toString()); } /** @@ -677,7 +723,8 @@ public class HttpFields implements Iterable */ public void add(HttpHeader header, String value) { - if (value == null) throw new IllegalArgumentException("null value"); + if (value == null) + throw new IllegalArgumentException("null value"); HttpField field = new HttpField(header, value); add(field); @@ -691,14 +738,14 @@ public class HttpFields implements Iterable */ public HttpField remove(HttpHeader name) { - HttpField removed=null; - for (int i=_size;i-->0;) + HttpField removed = null; + for (int i = _size; i-- > 0; ) { - HttpField f=_fields[i]; - if (f.getHeader()==name) + HttpField f = _fields[i]; + if (f.getHeader() == name) { - removed=f; - System.arraycopy(_fields,i+1,_fields,i,--_size-i); + removed = f; + System.arraycopy(_fields, i + 1, _fields, i, --_size - i); } } return removed; @@ -712,14 +759,14 @@ public class HttpFields implements Iterable */ public HttpField remove(String name) { - HttpField removed=null; - for (int i=_size;i-->0;) + HttpField removed = null; + for (int i = _size; i-- > 0; ) { - HttpField f=_fields[i]; + HttpField f = _fields[i]; if (f.getName().equalsIgnoreCase(name)) { - removed=f; - System.arraycopy(_fields,i+1,_fields,i,--_size-i); + removed = f; + System.arraycopy(_fields, i + 1, _fields, i, --_size - i); } } return removed; @@ -731,12 +778,12 @@ public class HttpFields implements Iterable * * @param name the case-insensitive field name * @return the value of the field as a long - * @exception NumberFormatException If bad long found + * @throws NumberFormatException If bad long found */ public long getLongField(String name) throws NumberFormatException { HttpField field = getField(name); - return field==null?-1L:field.getLongValue(); + return field == null ? -1L : field.getLongValue(); } /** @@ -757,12 +804,11 @@ public class HttpFields implements Iterable return -1; final long date = DateParser.parseDate(val); - if (date==-1) + if (date == -1) throw new IllegalArgumentException("Cannot convert date: " + val); return date; } - /** * Sets the value of an long field. * @@ -787,7 +833,6 @@ public class HttpFields implements Iterable put(name, v); } - /** * Sets the value of a date field. * @@ -796,7 +841,7 @@ public class HttpFields implements Iterable */ public void putDateField(HttpHeader name, long date) { - String d=DateGenerator.formatDate(date); + String d = DateGenerator.formatDate(date); put(name, d); } @@ -808,7 +853,7 @@ public class HttpFields implements Iterable */ public void putDateField(String name, long date) { - String d=DateGenerator.formatDate(date); + String d = DateGenerator.formatDate(date); put(name, d); } @@ -820,16 +865,18 @@ public class HttpFields implements Iterable */ public void addDateField(String name, long date) { - String d=DateGenerator.formatDate(date); - add(name,d); + String d = DateGenerator.formatDate(date); + add(name, d); } @Override public int hashCode() { - int hash=0; - for (HttpField field:_fields) - hash+=field.hashCode(); + int hash = 0; + for (HttpField field : _fields) + { + hash += field.hashCode(); + } return hash; } @@ -847,7 +894,8 @@ public class HttpFields implements Iterable if (size() != that.size()) return false; - loop: for (HttpField fi : this) + loop: + for (HttpField fi : this) { for (HttpField fa : that) { @@ -870,10 +918,12 @@ public class HttpFields implements Iterable if (field != null) { String tmp = field.getName(); - if (tmp != null) buffer.append(tmp); + if (tmp != null) + buffer.append(tmp); buffer.append(": "); tmp = field.getValue(); - if (tmp != null) buffer.append(tmp); + if (tmp != null) + buffer.append(tmp); buffer.append("\r\n"); } } @@ -889,23 +939,25 @@ public class HttpFields implements Iterable public void clear() { - _size=0; + _size = 0; } - + public void add(HttpField field) { - if (field!=null) + if (field != null) { - if (_size==_fields.length) - _fields=Arrays.copyOf(_fields,_size*2); - _fields[_size++]=field; + if (_size == _fields.length) + _fields = Arrays.copyOf(_fields, _size * 2); + _fields[_size++] = field; } } public void addAll(HttpFields fields) { - for (int i=0;i */ public void add(HttpFields fields) { - if (fields == null) return; + if (fields == null) + return; Enumeration e = fields.getFieldNames(); while (e.hasMoreElements()) @@ -924,7 +977,9 @@ public class HttpFields implements Iterable String name = e.nextElement(); Enumeration values = fields.getValues(name); while (values.hasMoreElements()) + { add(name, values.nextElement()); + } } } @@ -943,10 +998,12 @@ public class HttpFields implements Iterable */ public static String stripParameters(String value) { - if (value == null) return null; + if (value == null) + return null; int i = value.indexOf(';'); - if (i < 0) return value; + if (i < 0) + return value; return value.substring(0, i).trim(); } @@ -964,13 +1021,16 @@ public class HttpFields implements Iterable * @param parameters A map to populate with the parameters, or null * @return The value. */ - public static String valueParameters(String value, Map parameters) + public static String valueParameters(String value, Map parameters) { - if (value == null) return null; + if (value == null) + return null; int i = value.indexOf(';'); - if (i < 0) return value; - if (parameters == null) return value.substring(0, i).trim(); + if (i < 0) + return value; + if (parameters == null) + return value.substring(0, i).trim(); StringTokenizer tok1 = new QuotedStringTokenizer(value.substring(i), ";", false, true); while (tok1.hasMoreTokens()) @@ -981,7 +1041,8 @@ public class HttpFields implements Iterable { String paramName = tok2.nextToken(); String paramVal = null; - if (tok2.hasMoreTokens()) paramVal = tok2.nextToken(); + if (tok2.hasMoreTokens()) + paramVal = tok2.nextToken(); parameters.put(paramName, paramVal); } } @@ -995,6 +1056,7 @@ public class HttpFields implements Iterable private static final Float __zero = new Float("0.0"); @Deprecated private static final Trie __qualities = new ArrayTernaryTrie<>(); + static { __qualities.put("*", __one); @@ -1018,10 +1080,12 @@ public class HttpFields implements Iterable @Deprecated public static Float getQuality(String value) { - if (value == null) return __zero; + if (value == null) + return __zero; int qe = value.indexOf(";"); - if (qe++ < 0 || qe == value.length()) return __one; + if (qe++ < 0 || qe == value.length()) + return __one; if (value.charAt(qe++) == 'q') { @@ -1031,11 +1095,11 @@ public class HttpFields implements Iterable return q; } - Map params = new HashMap<>(4); + Map params = new HashMap<>(4); valueParameters(value, params); String qs = params.get("q"); - if (qs==null) - qs="*"; + if (qs == null) + qs = "*"; Float q = __qualities.get(qs); if (q == null) { @@ -1064,48 +1128,49 @@ public class HttpFields implements Iterable return Collections.emptyList(); QuotedQualityCSV values = new QuotedQualityCSV(); - while(e.hasMoreElements()) + while (e.hasMoreElements()) + { values.addValue(e.nextElement()); + } return values.getValues(); } - - private class Itr implements ListIterator + private class ListItr implements ListIterator { int _cursor; // index of next element to return - int _last=-1; + int _current = -1; @Override - public boolean hasNext() + public boolean hasNext() { return _cursor != _size; } @Override - public HttpField next() + public HttpField next() { - int i = _cursor; - if (i >= _size) + if (_cursor == _size) throw new NoSuchElementException(); - _cursor = i + 1; - return _fields[_last=i]; + _current = _cursor++; + return _fields[_current]; } @Override - public void remove() + public void remove() { - if (_last<0) + if (_current < 0) throw new IllegalStateException(); - - System.arraycopy(_fields,_last+1,_fields,_last,--_size-_last); - _cursor=_last; - _last=-1; + _size--; + System.arraycopy(_fields, _current + 1, _fields, _current, _size - _current); + _fields[_size] = null; + _cursor = _current; + _current = -1; } @Override public boolean hasPrevious() { - return _cursor>0; + return _cursor > 0; } @Override @@ -1113,37 +1178,37 @@ public class HttpFields implements Iterable { if (_cursor == 0) throw new NoSuchElementException(); - return _fields[_last=--_cursor]; + _current = --_cursor; + return _fields[_current]; } @Override public int nextIndex() { - return _cursor+1; + return _cursor + 1; } @Override public int previousIndex() { - return _cursor-1; + return _cursor - 1; } @Override public void set(HttpField field) - { - if (_last<0) + { + if (_current < 0) throw new IllegalStateException(); - _fields[_last] = field; + _fields[_current] = field; } @Override public void add(HttpField field) { - _fields = Arrays.copyOf(_fields,_fields.length+1); - System.arraycopy(_fields,_cursor,_fields,_cursor+1,_size++); + _fields = Arrays.copyOf(_fields, _fields.length + 1); + System.arraycopy(_fields, _cursor, _fields, _cursor + 1, _size++); _fields[_cursor++] = field; - _last=-1; + _current = -1; } } - } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java index 58ff3c68649..e23bb1bad04 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -44,27 +44,33 @@ import static org.eclipse.jetty.http.HttpStatus.INTERNAL_SERVER_ERROR_500; */ public class HttpGenerator { - private final static Logger LOG = Log.getLogger(HttpGenerator.class); + private static final Logger LOG = Log.getLogger(HttpGenerator.class); - public final static boolean __STRICT=Boolean.getBoolean("org.eclipse.jetty.http.HttpGenerator.STRICT"); + public static final boolean __STRICT = Boolean.getBoolean("org.eclipse.jetty.http.HttpGenerator.STRICT"); - private final static byte[] __colon_space = new byte[] {':',' '}; - public static final MetaData.Response CONTINUE_100_INFO = new MetaData.Response(HttpVersion.HTTP_1_1,100,null,null,-1); - public static final MetaData.Response PROGRESS_102_INFO = new MetaData.Response(HttpVersion.HTTP_1_1,102,null,null,-1); - public final static MetaData.Response RESPONSE_500_INFO = - new MetaData.Response(HttpVersion.HTTP_1_1,INTERNAL_SERVER_ERROR_500,null,new HttpFields(){{put(HttpHeader.CONNECTION,HttpHeaderValue.CLOSE);}},0); + private static final byte[] __colon_space = new byte[]{':', ' '}; + public static final MetaData.Response CONTINUE_100_INFO = new MetaData.Response(HttpVersion.HTTP_1_1, 100, null, null, -1); + public static final MetaData.Response PROGRESS_102_INFO = new MetaData.Response(HttpVersion.HTTP_1_1, 102, null, null, -1); + public static final MetaData.Response RESPONSE_500_INFO = + new MetaData.Response(HttpVersion.HTTP_1_1, INTERNAL_SERVER_ERROR_500, null, new HttpFields() + { + { + put(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE); + } + }, 0); // states - public enum State - { + public enum State + { START, COMMITTED, COMPLETING, COMPLETING_1XX, END } - public enum Result - { + + public enum Result + { NEED_CHUNK, // Need a small chunk buffer of CHUNK_SIZE NEED_INFO, // Need the request/response metadata info NEED_HEADER, // Need a buffer to build HTTP headers into @@ -84,118 +90,102 @@ public class HttpGenerator private long _contentPrepared = 0; private boolean _noContentResponse = false; private Boolean _persistent = null; - private Supplier _trailers = null; + private Supplier _trailers = null; private final int _send; - private final static int SEND_SERVER = 0x01; - private final static int SEND_XPOWEREDBY = 0x02; - private final static Trie __assumedContentMethods = new ArrayTrie<>(8); + private static final int SEND_SERVER = 0x01; + private static final int SEND_XPOWEREDBY = 0x02; + private static final Trie ASSUMED_CONTENT_METHODS = new ArrayTrie<>(8); + static { - __assumedContentMethods.put(HttpMethod.POST.asString(),Boolean.TRUE); - __assumedContentMethods.put(HttpMethod.PUT.asString(),Boolean.TRUE); - } - - /* ------------------------------------------------------------------------------- */ - public static void setJettyVersion(String serverVersion) - { - SEND[SEND_SERVER] = StringUtil.getBytes("Server: " + serverVersion + "\015\012"); - SEND[SEND_XPOWEREDBY] = StringUtil.getBytes("X-Powered-By: " + serverVersion + "\015\012"); - SEND[SEND_SERVER | SEND_XPOWEREDBY] = StringUtil.getBytes("Server: " + serverVersion + "\015\012X-Powered-By: " + - serverVersion + "\015\012"); + ASSUMED_CONTENT_METHODS.put(HttpMethod.POST.asString(), Boolean.TRUE); + ASSUMED_CONTENT_METHODS.put(HttpMethod.PUT.asString(), Boolean.TRUE); + } + + public static void setJettyVersion(String serverVersion) + { + SEND[SEND_SERVER] = StringUtil.getBytes("Server: " + serverVersion + "\r\n"); + SEND[SEND_XPOWEREDBY] = StringUtil.getBytes("X-Powered-By: " + serverVersion + "\r\n"); + SEND[SEND_SERVER | SEND_XPOWEREDBY] = StringUtil.getBytes("Server: " + serverVersion + "\r\nX-Powered-By: " + serverVersion + "\r\n"); } - /* ------------------------------------------------------------------------------- */ // data private boolean _needCRLF = false; - /* ------------------------------------------------------------------------------- */ public HttpGenerator() { - this(false,false); + this(false, false); } - /* ------------------------------------------------------------------------------- */ - public HttpGenerator(boolean sendServerVersion,boolean sendXPoweredBy) + public HttpGenerator(boolean sendServerVersion, boolean sendXPoweredBy) { - _send=(sendServerVersion?SEND_SERVER:0) | (sendXPoweredBy?SEND_XPOWEREDBY:0); + _send = (sendServerVersion ? SEND_SERVER : 0) | (sendXPoweredBy ? SEND_XPOWEREDBY : 0); } - /* ------------------------------------------------------------------------------- */ public void reset() { _state = State.START; _endOfContent = EndOfContent.UNKNOWN_CONTENT; - _noContentResponse=false; + _noContentResponse = false; _persistent = null; _contentPrepared = 0; _needCRLF = false; _trailers = null; } - /* ------------------------------------------------------------ */ @Deprecated - public boolean getSendServerVersion () + public boolean getSendServerVersion() { - return (_send&SEND_SERVER)!=0; + return (_send & SEND_SERVER) != 0; } - /* ------------------------------------------------------------ */ @Deprecated - public void setSendServerVersion (boolean sendServerVersion) + public void setSendServerVersion(boolean sendServerVersion) { throw new UnsupportedOperationException(); } - /* ------------------------------------------------------------ */ public State getState() { return _state; } - /* ------------------------------------------------------------ */ public boolean isState(State state) { return _state == state; } - /* ------------------------------------------------------------ */ public boolean isIdle() { return _state == State.START; } - /* ------------------------------------------------------------ */ public boolean isEnd() { return _state == State.END; } - /* ------------------------------------------------------------ */ public boolean isCommitted() { return _state.ordinal() >= State.COMMITTED.ordinal(); } - /* ------------------------------------------------------------ */ public boolean isChunking() { - return _endOfContent==EndOfContent.CHUNKED_CONTENT; + return _endOfContent == EndOfContent.CHUNKED_CONTENT; } - /* ------------------------------------------------------------ */ public boolean isNoContent() { return _noContentResponse; } - /* ------------------------------------------------------------ */ public void setPersistent(boolean persistent) { - _persistent=persistent; + _persistent = persistent; } - /* ------------------------------------------------------------ */ /** * @return true if known to be persistent */ @@ -204,50 +194,46 @@ public class HttpGenerator return Boolean.TRUE.equals(_persistent); } - /* ------------------------------------------------------------ */ public boolean isWritten() { - return _contentPrepared>0; + return _contentPrepared > 0; } - /* ------------------------------------------------------------ */ public long getContentPrepared() { return _contentPrepared; } - /* ------------------------------------------------------------ */ public void abort() { - _persistent=false; - _state=State.END; - _endOfContent=null; + _persistent = false; + _state = State.END; + _endOfContent = null; } - /* ------------------------------------------------------------ */ public Result generateRequest(MetaData.Request info, ByteBuffer header, ByteBuffer chunk, ByteBuffer content, boolean last) throws IOException { - switch(_state) + switch (_state) { case START: { - if (info==null) + if (info == null) return Result.NEED_INFO; - if (header==null) + if (header == null) return Result.NEED_HEADER; // prepare the header - int pos=BufferUtil.flipToFill(header); + int pos = BufferUtil.flipToFill(header); try { // generate ResponseLine - generateRequestLine(info,header); + generateRequestLine(info, header); - if (info.getHttpVersion()==HttpVersion.HTTP_0_9) - throw new BadMessageException(INTERNAL_SERVER_ERROR_500,"HTTP/0.9 not supported"); - - generateHeaders(info,header,content,last); + if (info.getHttpVersion() == HttpVersion.HTTP_0_9) + throw new BadMessageException(INTERNAL_SERVER_ERROR_500, "HTTP/0.9 not supported"); + + generateHeaders(info, header, content, last); boolean expect100 = info.getFields().contains(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE.asString()); @@ -259,43 +245,43 @@ public class HttpGenerator { // handle the content. int len = BufferUtil.length(content); - if (len>0) + if (len > 0) { - _contentPrepared+=len; + _contentPrepared += len; if (isChunking()) - prepareChunk(header,len); + prepareChunk(header, len); } - _state = last?State.COMPLETING:State.COMMITTED; + _state = last ? State.COMPLETING : State.COMMITTED; } return Result.FLUSH; } - catch(BadMessageException e) + catch (BadMessageException e) { throw e; } - catch(BufferOverflowException e) + catch (BufferOverflowException e) { - throw new BadMessageException(INTERNAL_SERVER_ERROR_500,"Request header too large",e); + throw new BadMessageException(INTERNAL_SERVER_ERROR_500, "Request header too large", e); } - catch(Exception e) + catch (Exception e) { - throw new BadMessageException(INTERNAL_SERVER_ERROR_500,e.getMessage(),e); + throw new BadMessageException(INTERNAL_SERVER_ERROR_500, e.getMessage(), e); } finally { - BufferUtil.flipToFlush(header,pos); + BufferUtil.flipToFlush(header, pos); } } case COMMITTED: { - return committed(chunk,content,last); + return committed(chunk, content, last); } case COMPLETING: { - return completing(chunk,content); + return completing(chunk, content); } case END: @@ -312,33 +298,33 @@ public class HttpGenerator } } - private Result committed( ByteBuffer chunk, ByteBuffer content, boolean last) + private Result committed(ByteBuffer chunk, ByteBuffer content, boolean last) { int len = BufferUtil.length(content); // handle the content. - if (len>0) + if (len > 0) { if (isChunking()) { - if (chunk==null) + if (chunk == null) return Result.NEED_CHUNK; BufferUtil.clearToFill(chunk); - prepareChunk(chunk,len); - BufferUtil.flipToFlush(chunk,0); + prepareChunk(chunk, len); + BufferUtil.flipToFlush(chunk, 0); } - _contentPrepared+=len; + _contentPrepared += len; } if (last) { - _state=State.COMPLETING; - return len>0?Result.FLUSH:Result.CONTINUE; + _state = State.COMPLETING; + return len > 0 ? Result.FLUSH : Result.CONTINUE; } - return len>0?Result.FLUSH:Result.DONE; + return len > 0 ? Result.FLUSH : Result.DONE; } - - private Result completing( ByteBuffer chunk, ByteBuffer content) + + private Result completing(ByteBuffer chunk, ByteBuffer content) { if (BufferUtil.hasContent(content)) { @@ -349,129 +335,125 @@ public class HttpGenerator if (isChunking()) { - if (_trailers!=null) + if (_trailers != null) { // Do we need a chunk buffer? - if (chunk==null || chunk.capacity()<=CHUNK_SIZE) + if (chunk == null || chunk.capacity() <= CHUNK_SIZE) return Result.NEED_CHUNK_TRAILER; - + HttpFields trailers = _trailers.get(); - if (trailers!=null) + if (trailers != null) { // Write the last chunk BufferUtil.clearToFill(chunk); - generateTrailers(chunk,trailers); - BufferUtil.flipToFlush(chunk,0); - _endOfContent=EndOfContent.UNKNOWN_CONTENT; + generateTrailers(chunk, trailers); + BufferUtil.flipToFlush(chunk, 0); + _endOfContent = EndOfContent.UNKNOWN_CONTENT; return Result.FLUSH; } } // Do we need a chunk buffer? - if (chunk==null) + if (chunk == null) return Result.NEED_CHUNK; // Write the last chunk BufferUtil.clearToFill(chunk); - prepareChunk(chunk,0); - BufferUtil.flipToFlush(chunk,0); - _endOfContent=EndOfContent.UNKNOWN_CONTENT; - return Result.FLUSH; + prepareChunk(chunk, 0); + BufferUtil.flipToFlush(chunk, 0); + _endOfContent = EndOfContent.UNKNOWN_CONTENT; + return Result.FLUSH; } - _state=State.END; - return Boolean.TRUE.equals(_persistent)?Result.DONE:Result.SHUTDOWN_OUT; - + _state = State.END; + return Boolean.TRUE.equals(_persistent) ? Result.DONE : Result.SHUTDOWN_OUT; } - - - /* ------------------------------------------------------------ */ + @Deprecated public Result generateResponse(MetaData.Response info, ByteBuffer header, ByteBuffer chunk, ByteBuffer content, boolean last) throws IOException { - return generateResponse(info,false,header,chunk,content,last); + return generateResponse(info, false, header, chunk, content, last); } - /* ------------------------------------------------------------ */ public Result generateResponse(MetaData.Response info, boolean head, ByteBuffer header, ByteBuffer chunk, ByteBuffer content, boolean last) throws IOException { - switch(_state) + switch (_state) { case START: { - if (info==null) + if (info == null) return Result.NEED_INFO; - HttpVersion version=info.getHttpVersion(); - if (version==null) - throw new BadMessageException(INTERNAL_SERVER_ERROR_500,"No version"); - - if (version==HttpVersion.HTTP_0_9) + HttpVersion version = info.getHttpVersion(); + if (version == null) + throw new BadMessageException(INTERNAL_SERVER_ERROR_500, "No version"); + + if (version == HttpVersion.HTTP_0_9) { _persistent = false; - _endOfContent=EndOfContent.EOF_CONTENT; + _endOfContent = EndOfContent.EOF_CONTENT; if (BufferUtil.hasContent(content)) - _contentPrepared+=content.remaining(); - _state = last?State.COMPLETING:State.COMMITTED; + _contentPrepared += content.remaining(); + _state = last ? State.COMPLETING : State.COMMITTED; return Result.FLUSH; } - + // Do we need a response header - if (header==null) + if (header == null) return Result.NEED_HEADER; // prepare the header - int pos=BufferUtil.flipToFill(header); + int pos = BufferUtil.flipToFill(header); try - { + { // generate ResponseLine - generateResponseLine(info,header); + generateResponseLine(info, header); // Handle 1xx and no content responses - int status=info.getStatus(); - if (status>=100 && status<200 ) + int status = info.getStatus(); + if (status >= 100 && status < 200) { - _noContentResponse=true; + _noContentResponse = true; - if (status!=HttpStatus.SWITCHING_PROTOCOLS_101 ) + if (status != HttpStatus.SWITCHING_PROTOCOLS_101) { header.put(HttpTokens.CRLF); - _state=State.COMPLETING_1XX; + _state = State.COMPLETING_1XX; return Result.FLUSH; } } - else if (status==HttpStatus.NO_CONTENT_204 || status==HttpStatus.NOT_MODIFIED_304) + else if (status == HttpStatus.NO_CONTENT_204 || status == HttpStatus.NOT_MODIFIED_304) { - _noContentResponse=true; + _noContentResponse = true; } - generateHeaders(info,header,content,last); + generateHeaders(info, header, content, last); // handle the content. int len = BufferUtil.length(content); - if (len>0) + if (len > 0) { - _contentPrepared+=len; + _contentPrepared += len; if (isChunking() && !head) - prepareChunk(header,len); + prepareChunk(header, len); } - _state = last?State.COMPLETING:State.COMMITTED; + _state = last ? State.COMPLETING : State.COMMITTED; } - catch(BadMessageException e) + catch (BadMessageException e) { throw e; } - catch(BufferOverflowException e) + catch (BufferOverflowException e) { - throw new BadMessageException(INTERNAL_SERVER_ERROR_500,"Response header too large",e); + throw new BadMessageException(INTERNAL_SERVER_ERROR_500, "Response header too large", e); } - catch(Exception e) + catch (Exception e) { - throw new BadMessageException(INTERNAL_SERVER_ERROR_500,e.getMessage(),e); + throw new BadMessageException(INTERNAL_SERVER_ERROR_500, e.getMessage(), e); } finally { - BufferUtil.flipToFlush(header,pos); + BufferUtil.flipToFlush(header, pos); } return Result.FLUSH; @@ -479,7 +461,7 @@ public class HttpGenerator case COMMITTED: { - return committed(chunk,content,last); + return committed(chunk, content, last); } case COMPLETING_1XX: @@ -490,7 +472,7 @@ public class HttpGenerator case COMPLETING: { - return completing(chunk,content); + return completing(chunk, content); } case END: @@ -507,7 +489,6 @@ public class HttpGenerator } } - /* ------------------------------------------------------------ */ private void prepareChunk(ByteBuffer chunk, int remaining) { // if we need CRLF add this to header @@ -515,20 +496,19 @@ public class HttpGenerator BufferUtil.putCRLF(chunk); // Add the chunk size to the header - if (remaining>0) + if (remaining > 0) { BufferUtil.putHexInt(chunk, remaining); BufferUtil.putCRLF(chunk); - _needCRLF=true; + _needCRLF = true; } else { chunk.put(LAST_CHUNK); - _needCRLF=false; + _needCRLF = false; } } - - /* ------------------------------------------------------------ */ + private void generateTrailers(ByteBuffer buffer, HttpFields trailer) { // if we need CRLF add this to header @@ -538,18 +518,17 @@ public class HttpGenerator // Add the chunk size to the header buffer.put(ZERO_CHUNK); - int n=trailer.size(); - for (int f=0;f1024) - reason=reason.substring(0,1024); - byte[] _bytes = StringUtil.getBytes(reason); + if (reason.length() > 1024) + reason = reason.substring(0, 1024); + byte[] bytes = StringUtil.getBytes(reason); - for (int i=_bytes.length;i-->0;) - if (_bytes[i]=='\r' || _bytes[i]=='\n') - _bytes[i]='?'; - return _bytes; + for (int i = bytes.length; i-- > 0; ) + { + if (bytes[i] == '\r' || bytes[i] == '\n') + bytes[i] = '?'; + } + return bytes; } - /* ------------------------------------------------------------ */ - private void generateHeaders(MetaData info,ByteBuffer header,ByteBuffer content,boolean last) + private void generateHeaders(MetaData info, ByteBuffer header, ByteBuffer content, boolean last) { - final MetaData.Request request=(info instanceof MetaData.Request)?(MetaData.Request)info:null; - final MetaData.Response response=(info instanceof MetaData.Response)?(MetaData.Response)info:null; - + final MetaData.Request request = (info instanceof MetaData.Request) ? (MetaData.Request)info : null; + final MetaData.Response response = (info instanceof MetaData.Response) ? (MetaData.Response)info : null; + if (LOG.isDebugEnabled()) { - LOG.debug("generateHeaders {} last={} content={}",info,last,BufferUtil.toDetailString(content)); + LOG.debug("generateHeaders {} last={} content={}", info, last, BufferUtil.toDetailString(content)); LOG.debug(info.getFields().toString()); } - + // default field values - int send=_send; - HttpField transfer_encoding=null; + int send = _send; + HttpField transferEncoding = null; boolean http11 = info.getHttpVersion() == HttpVersion.HTTP_1_1; boolean close = false; - _trailers = http11?info.getTrailerSupplier():null; - boolean chunked_hint = _trailers!=null; - boolean content_type = false; - long content_length = info.getContentLength(); - boolean content_length_field = false; + _trailers = http11 ? info.getTrailerSupplier() : null; + boolean chunkedHint = _trailers != null; + boolean contentType = false; + long contentLength = info.getContentLength(); + boolean contentLengthField = false; // Generate fields HttpFields fields = info.getFields(); if (fields != null) { - int n=fields.size(); - for (int f=0;f0 || content_length>0) + if (_contentPrepared > 0 || contentLength > 0) { - if (_contentPrepared==0 && last) + if (_contentPrepared == 0 && last) { // TODO discard content for backward compatibility with 9.3 releases // TODO review if it is still needed in 9.4 or can we just throw. content.clear(); - content_length=0; + contentLength = 0; } else - throw new BadMessageException(INTERNAL_SERVER_ERROR_500,"Content for no content response"); + throw new BadMessageException(INTERNAL_SERVER_ERROR_500, "Content for no content response"); } } // Else if we are HTTP/1.1 and the content length is unknown and we are either persistent // or it is a request with content (which cannot EOF) or the app has requested chunking - else if (http11 && (chunked_hint || content_length<0 && (_persistent || assumed_content_request))) + else if (http11 && (chunkedHint || contentLength < 0 && (_persistent || assumedContentRequest))) { // we use chunking _endOfContent = EndOfContent.CHUNKED_CONTENT; // try to use user supplied encoding as it may have other values. - if (transfer_encoding == null) + if (transferEncoding == null) header.put(TRANSFER_ENCODING_CHUNKED); - else if (transfer_encoding.toString().endsWith(HttpHeaderValue.CHUNKED.toString())) + else if (transferEncoding.toString().endsWith(HttpHeaderValue.CHUNKED.toString())) { - putTo(transfer_encoding,header); - transfer_encoding = null; + putTo(transferEncoding, header); + transferEncoding = null; } - else if (!chunked_hint) + else if (!chunkedHint) { - putTo(new HttpField(HttpHeader.TRANSFER_ENCODING,transfer_encoding.getValue()+",chunked"),header); - transfer_encoding = null; + putTo(new HttpField(HttpHeader.TRANSFER_ENCODING, transferEncoding.getValue() + ",chunked"), header); + transferEncoding = null; } else - throw new BadMessageException(INTERNAL_SERVER_ERROR_500,"Bad Transfer-Encoding"); + throw new BadMessageException(INTERNAL_SERVER_ERROR_500, "Bad Transfer-Encoding"); } // Else if we known the content length and are a request or a persistent response, - else if (content_length>=0 && (request!=null || _persistent)) + else if (contentLength >= 0 && (request != null || _persistent)) { // Use the content length _endOfContent = EndOfContent.CONTENT_LENGTH; - putContentLength(header,content_length); + putContentLength(header, contentLength); } // Else if we are a response - else if (response!=null) + else if (response != null) { // We must use EOF - even if we were trying to be persistent _endOfContent = EndOfContent.EOF_CONTENT; - _persistent=false; - if (content_length>=0 && ( content_length> 0 || assumed_content || content_length_field )) - putContentLength(header,content_length); - + _persistent = false; + if (contentLength >= 0 && (contentLength > 0 || assumedContent || contentLengthField)) + putContentLength(header, contentLength); + if (http11 && !close) header.put(CONNECTION_CLOSE); } @@ -785,41 +763,40 @@ public class HttpGenerator else { // with no way to indicate body length - throw new BadMessageException(INTERNAL_SERVER_ERROR_500,"Unknown content length for request"); + throw new BadMessageException(INTERNAL_SERVER_ERROR_500, "Unknown content length for request"); } if (LOG.isDebugEnabled()) LOG.debug(_endOfContent.toString()); - + // Add transfer encoding if it is not chunking - if (transfer_encoding!=null) + if (transferEncoding != null) { - if (chunked_hint) + if (chunkedHint) { - String v = transfer_encoding.getValue(); + String v = transferEncoding.getValue(); int c = v.lastIndexOf(','); - if (c>0 && v.lastIndexOf(HttpHeaderValue.CHUNKED.toString(),c)>c) - putTo(new HttpField(HttpHeader.TRANSFER_ENCODING,v.substring(0,c).trim()),header); + if (c > 0 && v.lastIndexOf(HttpHeaderValue.CHUNKED.toString(), c) > c) + putTo(new HttpField(HttpHeader.TRANSFER_ENCODING, v.substring(0, c).trim()), header); } else { - putTo(transfer_encoding,header); + putTo(transferEncoding, header); } } - + // Send server? - int status=response!=null?response.getStatus():-1; - if (status>199) + int status = response != null ? response.getStatus() : -1; + if (status > 199) header.put(SEND[send]); // end the header. - header.put(HttpTokens.CRLF); + header.put(HttpTokens.CRLF); } - /* ------------------------------------------------------------------------------- */ - private static void putContentLength(ByteBuffer header,long contentLength) + private static void putContentLength(ByteBuffer header, long contentLength) { - if (contentLength==0) + if (contentLength == 0) header.put(CONTENT_LENGTH_0); else { @@ -828,46 +805,38 @@ public class HttpGenerator header.put(HttpTokens.CRLF); } } - - /* ------------------------------------------------------------------------------- */ + public static byte[] getReasonBuffer(int code) { - PreparedResponse status = code<__preprepared.length?__preprepared[code]:null; - if (status!=null) + PreparedResponse status = code < __preprepared.length ? __preprepared[code] : null; + if (status != null) return status._reason; return null; } - /* ------------------------------------------------------------------------------- */ @Override public String toString() { return String.format("%s@%x{s=%s}", - getClass().getSimpleName(), - hashCode(), - _state); + getClass().getSimpleName(), + hashCode(), + _state); } - /* ------------------------------------------------------------------------------- */ - /* ------------------------------------------------------------------------------- */ - /* ------------------------------------------------------------------------------- */ // common _content - private static final byte[] ZERO_CHUNK = { (byte) '0', (byte) '\015', (byte) '\012'}; - private static final byte[] LAST_CHUNK = { (byte) '0', (byte) '\015', (byte) '\012', (byte) '\015', (byte) '\012'}; - private static final byte[] CONTENT_LENGTH_0 = StringUtil.getBytes("Content-Length: 0\015\012"); - private static final byte[] CONNECTION_CLOSE = StringUtil.getBytes("Connection: close\015\012"); - private static final byte[] HTTP_1_1_SPACE = StringUtil.getBytes(HttpVersion.HTTP_1_1+" "); - private static final byte[] TRANSFER_ENCODING_CHUNKED = StringUtil.getBytes("Transfer-Encoding: chunked\015\012"); + private static final byte[] ZERO_CHUNK = {(byte)'0', (byte)'\r', (byte)'\n'}; + private static final byte[] LAST_CHUNK = {(byte)'0', (byte)'\r', (byte)'\n', (byte)'\r', (byte)'\n'}; + private static final byte[] CONTENT_LENGTH_0 = StringUtil.getBytes("Content-Length: 0\r\n"); + private static final byte[] CONNECTION_CLOSE = StringUtil.getBytes("Connection: close\r\n"); + private static final byte[] HTTP_1_1_SPACE = StringUtil.getBytes(HttpVersion.HTTP_1_1 + " "); + private static final byte[] TRANSFER_ENCODING_CHUNKED = StringUtil.getBytes("Transfer-Encoding: chunked\r\n"); private static final byte[][] SEND = new byte[][]{ - new byte[0], - StringUtil.getBytes("Server: Jetty(9.x.x)\015\012"), - StringUtil.getBytes("X-Powered-By: Jetty(9.x.x)\015\012"), - StringUtil.getBytes("Server: Jetty(9.x.x)\015\012X-Powered-By: Jetty(9.x.x)\015\012") + new byte[0], + StringUtil.getBytes("Server: Jetty(9.x.x)\r\n"), + StringUtil.getBytes("X-Powered-By: Jetty(9.x.x)\r\n"), + StringUtil.getBytes("Server: Jetty(9.x.x)\r\nX-Powered-By: Jetty(9.x.x)\r\n") }; - /* ------------------------------------------------------------------------------- */ - /* ------------------------------------------------------------------------------- */ - /* ------------------------------------------------------------------------------- */ // Build cache of response lines for status private static class PreparedResponse { @@ -875,61 +844,65 @@ public class HttpGenerator byte[] _schemeCode; byte[] _responseLine; } - private static final PreparedResponse[] __preprepared = new PreparedResponse[HttpStatus.MAX_CODE+1]; + + private static final PreparedResponse[] __preprepared = new PreparedResponse[HttpStatus.MAX_CODE + 1]; + static { - int versionLength=HttpVersion.HTTP_1_1.toString().length(); + int versionLength = HttpVersion.HTTP_1_1.toString().length(); - for (int i=0;i<__preprepared.length;i++) + for (int i = 0; i < __preprepared.length; i++) { HttpStatus.Code code = HttpStatus.getCode(i); - if (code==null) + if (code == null) continue; - String reason=code.getMessage(); - byte[] line=new byte[versionLength+5+reason.length()+2]; - HttpVersion.HTTP_1_1.toBuffer().get(line,0,versionLength); - line[versionLength+0]=' '; - line[versionLength+1]=(byte)('0'+i/100); - line[versionLength+2]=(byte)('0'+(i%100)/10); - line[versionLength+3]=(byte)('0'+(i%10)); - line[versionLength+4]=' '; - for (int j=0;j0xff || c=='\r' || c=='\n'|| c==':') + if (c < 0 || c > 0xff || c == '\r' || c == '\n' || c == ':') buffer.put((byte)'?'); else - buffer.put((byte)(0xff&c)); + buffer.put((byte)(0xff & c)); } } - private static void putSanitisedValue(String s,ByteBuffer buffer) + private static void putSanitisedValue(String s, ByteBuffer buffer) { - int l=s.length(); - for (int i=0;i0xff || c=='\r' || c=='\n') + if (c < 0 || c > 0xff || c == '\r' || c == '\n') buffer.put((byte)' '); else - buffer.put((byte)(0xff&c)); + buffer.put((byte)(0xff & c)); } } @@ -937,21 +910,21 @@ public class HttpGenerator { if (field instanceof PreEncodedHttpField) { - ((PreEncodedHttpField)field).putTo(bufferInFillMode,HttpVersion.HTTP_1_0); + ((PreEncodedHttpField)field).putTo(bufferInFillMode, HttpVersion.HTTP_1_0); } else { - HttpHeader header=field.getHeader(); - if (header!=null) + HttpHeader header = field.getHeader(); + if (header != null) { bufferInFillMode.put(header.getBytesColonSpace()); - putSanitisedValue(field.getValue(),bufferInFillMode); + putSanitisedValue(field.getValue(), bufferInFillMode); } else { - putSanitisedName(field.getName(),bufferInFillMode); + putSanitisedName(field.getName(), bufferInFillMode); bufferInFillMode.put(__colon_space); - putSanitisedValue(field.getValue(),bufferInFillMode); + putSanitisedValue(field.getValue(), bufferInFillMode); } BufferUtil.putCRLF(bufferInFillMode); @@ -963,7 +936,7 @@ public class HttpGenerator for (HttpField field : fields) { if (field != null) - putTo(field,bufferInFillMode); + putTo(field, bufferInFillMode); } BufferUtil.putCRLF(bufferInFillMode); } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeader.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeader.java index 3be15acc258..826e0cc3d45 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeader.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeader.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -24,17 +24,17 @@ import org.eclipse.jetty.util.ArrayTrie; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.Trie; - public enum HttpHeader { - /* ------------------------------------------------------------ */ - /** General Fields. + + /** + * General Fields. */ CONNECTION("Connection"), CACHE_CONTROL("Cache-Control"), DATE("Date"), PRAGMA("Pragma"), - PROXY_CONNECTION ("Proxy-Connection"), + PROXY_CONNECTION("Proxy-Connection"), TRAILER("Trailer"), TRANSFER_ENCODING("Transfer-Encoding"), UPGRADE("Upgrade"), @@ -42,8 +42,8 @@ public enum HttpHeader WARNING("Warning"), NEGOTIATE("Negotiate"), - /* ------------------------------------------------------------ */ - /** Entity Fields. + /** + * Entity Fields. */ ALLOW("Allow"), CONTENT_ENCODING("Content-Encoding"), @@ -56,8 +56,8 @@ public enum HttpHeader EXPIRES("Expires"), LAST_MODIFIED("Last-Modified"), - /* ------------------------------------------------------------ */ - /** Request Fields. + /** + * Request Fields. */ ACCEPT("Accept"), ACCEPT_CHARSET("Accept-Charset"), @@ -82,12 +82,13 @@ public enum HttpHeader TE("TE"), USER_AGENT("User-Agent"), X_FORWARDED_FOR("X-Forwarded-For"), + X_FORWARDED_PORT("X-Forwarded-Port"), X_FORWARDED_PROTO("X-Forwarded-Proto"), X_FORWARDED_SERVER("X-Forwarded-Server"), X_FORWARDED_HOST("X-Forwarded-Host"), - /* ------------------------------------------------------------ */ - /** Response Fields. + /** + * Response Fields. */ ACCEPT_RANGES("Accept-Ranges"), AGE("Age"), @@ -100,8 +101,8 @@ public enum HttpHeader VARY("Vary"), WWW_AUTHENTICATE("WWW-Authenticate"), - /* ------------------------------------------------------------ */ - /** WebSocket Fields. + /** + * WebSocket Fields. */ ORIGIN("Origin"), SEC_WEBSOCKET_KEY("Sec-WebSocket-Key"), @@ -110,92 +111,85 @@ public enum HttpHeader SEC_WEBSOCKET_SUBPROTOCOL("Sec-WebSocket-Protocol"), SEC_WEBSOCKET_ACCEPT("Sec-WebSocket-Accept"), - /* ------------------------------------------------------------ */ - /** Other Fields. + /** + * Other Fields. */ COOKIE("Cookie"), SET_COOKIE("Set-Cookie"), SET_COOKIE2("Set-Cookie2"), MIME_VERSION("MIME-Version"), IDENTITY("identity"), - + X_POWERED_BY("X-Powered-By"), HTTP2_SETTINGS("HTTP2-Settings"), STRICT_TRANSPORT_SECURITY("Strict-Transport-Security"), - - /* ------------------------------------------------------------ */ - /** HTTP2 Fields. + + /** + * HTTP2 Fields. */ C_METHOD(":method"), C_SCHEME(":scheme"), C_AUTHORITY(":authority"), C_PATH(":path"), C_STATUS(":status"), - + UNKNOWN("::UNKNOWN::"); + public static final Trie CACHE = new ArrayTrie<>(630); - /* ------------------------------------------------------------ */ - public final static Trie CACHE= new ArrayTrie<>(630); static { for (HttpHeader header : HttpHeader.values()) - if (header!=UNKNOWN) - if (!CACHE.put(header.toString(),header)) + { + if (header != UNKNOWN) + if (!CACHE.put(header.toString(), header)) throw new IllegalStateException(); + } } - + private final String _string; private final byte[] _bytes; private final byte[] _bytesColonSpace; private final ByteBuffer _buffer; - /* ------------------------------------------------------------ */ HttpHeader(String s) { - _string=s; - _bytes=StringUtil.getBytes(s); - _bytesColonSpace=StringUtil.getBytes(s+": "); - _buffer=ByteBuffer.wrap(_bytes); + _string = s; + _bytes = StringUtil.getBytes(s); + _bytesColonSpace = StringUtil.getBytes(s + ": "); + _buffer = ByteBuffer.wrap(_bytes); } - /* ------------------------------------------------------------ */ public ByteBuffer toBuffer() { return _buffer.asReadOnlyBuffer(); } - /* ------------------------------------------------------------ */ public byte[] getBytes() { return _bytes; } - /* ------------------------------------------------------------ */ public byte[] getBytesColonSpace() { return _bytesColonSpace; } - /* ------------------------------------------------------------ */ public boolean is(String s) { - return _string.equalsIgnoreCase(s); + return _string.equalsIgnoreCase(s); } - /* ------------------------------------------------------------ */ public String asString() { return _string; } - - /* ------------------------------------------------------------ */ + @Override public String toString() { return _string; } - } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeaderValue.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeaderValue.java index 97ba411c79f..996b070cdd5 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeaderValue.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeaderValue.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -25,9 +25,8 @@ import org.eclipse.jetty.util.ArrayTrie; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Trie; - /** - * + * */ public enum HttpHeaderValue { @@ -44,60 +43,55 @@ public enum HttpHeaderValue UPGRADE("Upgrade"), UNKNOWN("::UNKNOWN::"); - /* ------------------------------------------------------------ */ - public final static Trie CACHE= new ArrayTrie(); + public static final Trie CACHE = new ArrayTrie(); + static { for (HttpHeaderValue value : HttpHeaderValue.values()) - if (value!=UNKNOWN) - CACHE.put(value.toString(),value); + { + if (value != UNKNOWN) + CACHE.put(value.toString(), value); + } } private final String _string; private final ByteBuffer _buffer; - /* ------------------------------------------------------------ */ HttpHeaderValue(String s) { - _string=s; - _buffer=BufferUtil.toBuffer(s); + _string = s; + _buffer = BufferUtil.toBuffer(s); } - /* ------------------------------------------------------------ */ public ByteBuffer toBuffer() { return _buffer.asReadOnlyBuffer(); } - /* ------------------------------------------------------------ */ public boolean is(String s) { return _string.equalsIgnoreCase(s); } - - /* ------------------------------------------------------------ */ + public String asString() { return _string; } - /* ------------------------------------------------------------ */ @Override public String toString() { return _string; } - /* ------------------------------------------------------------ */ private static EnumSet __known = - EnumSet.of(HttpHeader.CONNECTION, - HttpHeader.TRANSFER_ENCODING, - HttpHeader.CONTENT_ENCODING); + EnumSet.of(HttpHeader.CONNECTION, + HttpHeader.TRANSFER_ENCODING, + HttpHeader.CONTENT_ENCODING); - /* ------------------------------------------------------------ */ public static boolean hasKnownValues(HttpHeader header) { - if (header==null) + if (header == null) return false; return __known.contains(header); } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpMethod.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpMethod.java index f99f66e8a79..016f3dcbbee 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpMethod.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpMethod.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -25,9 +25,8 @@ import org.eclipse.jetty.util.ArrayTrie; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.Trie; - -/* ------------------------------------------------------------------------------- */ /** + * */ public enum HttpMethod { @@ -43,61 +42,61 @@ public enum HttpMethod PROXY, PRI; - /* ------------------------------------------------------------ */ /** * Optimized lookup to find a method name and trailing space in a byte array. + * * @param bytes Array containing ISO-8859-1 characters * @param position The first valid index * @param limit The first non valid index - * @return A HttpMethod if a match or null if no easy match. + * @return An HttpMethod if a match or null if no easy match. */ public static HttpMethod lookAheadGet(byte[] bytes, final int position, int limit) { - int length=limit-position; - if (length<4) + int length = limit - position; + if (length < 4) return null; - switch(bytes[position]) + switch (bytes[position]) { case 'G': - if (bytes[position+1]=='E' && bytes[position+2]=='T' && bytes[position+3]==' ') + if (bytes[position + 1] == 'E' && bytes[position + 2] == 'T' && bytes[position + 3] == ' ') return GET; break; case 'P': - if (bytes[position+1]=='O' && bytes[position+2]=='S' && bytes[position+3]=='T' && length>=5 && bytes[position+4]==' ') + if (bytes[position + 1] == 'O' && bytes[position + 2] == 'S' && bytes[position + 3] == 'T' && length >= 5 && bytes[position + 4] == ' ') return POST; - if (bytes[position+1]=='R' && bytes[position+2]=='O' && bytes[position+3]=='X' && length>=6 && bytes[position+4]=='Y' && bytes[position+5]==' ') + if (bytes[position + 1] == 'R' && bytes[position + 2] == 'O' && bytes[position + 3] == 'X' && length >= 6 && bytes[position + 4] == 'Y' && bytes[position + 5] == ' ') return PROXY; - if (bytes[position+1]=='U' && bytes[position+2]=='T' && bytes[position+3]==' ') + if (bytes[position + 1] == 'U' && bytes[position + 2] == 'T' && bytes[position + 3] == ' ') return PUT; - if (bytes[position+1]=='R' && bytes[position+2]=='I' && bytes[position+3]==' ') + if (bytes[position + 1] == 'R' && bytes[position + 2] == 'I' && bytes[position + 3] == ' ') return PRI; break; case 'H': - if (bytes[position+1]=='E' && bytes[position+2]=='A' && bytes[position+3]=='D' && length>=5 && bytes[position+4]==' ') + if (bytes[position + 1] == 'E' && bytes[position + 2] == 'A' && bytes[position + 3] == 'D' && length >= 5 && bytes[position + 4] == ' ') return HEAD; break; case 'O': - if (bytes[position+1]=='P' && bytes[position+2]=='T' && bytes[position+3]=='I' && length>=8 && - bytes[position+4]=='O' && bytes[position+5]=='N' && bytes[position+6]=='S' && bytes[position+7]==' ' ) + if (bytes[position + 1] == 'P' && bytes[position + 2] == 'T' && bytes[position + 3] == 'I' && length >= 8 && + bytes[position + 4] == 'O' && bytes[position + 5] == 'N' && bytes[position + 6] == 'S' && bytes[position + 7] == ' ') return OPTIONS; break; case 'D': - if (bytes[position+1]=='E' && bytes[position+2]=='L' && bytes[position+3]=='E' && length>=7 && - bytes[position+4]=='T' && bytes[position+5]=='E' && bytes[position+6]==' ' ) + if (bytes[position + 1] == 'E' && bytes[position + 2] == 'L' && bytes[position + 3] == 'E' && length >= 7 && + bytes[position + 4] == 'T' && bytes[position + 5] == 'E' && bytes[position + 6] == ' ') return DELETE; break; case 'T': - if (bytes[position+1]=='R' && bytes[position+2]=='A' && bytes[position+3]=='C' && length>=6 && - bytes[position+4]=='E' && bytes[position+5]==' ' ) + if (bytes[position + 1] == 'R' && bytes[position + 2] == 'A' && bytes[position + 3] == 'C' && length >= 6 && + bytes[position + 4] == 'E' && bytes[position + 5] == ' ') return TRACE; break; case 'C': - if (bytes[position+1]=='O' && bytes[position+2]=='N' && bytes[position+3]=='N' && length>=8 && - bytes[position+4]=='E' && bytes[position+5]=='C' && bytes[position+6]=='T' && bytes[position+7]==' ' ) + if (bytes[position + 1] == 'O' && bytes[position + 2] == 'N' && bytes[position + 3] == 'N' && length >= 8 && + bytes[position + 4] == 'E' && bytes[position + 5] == 'C' && bytes[position + 6] == 'T' && bytes[position + 7] == ' ') return CONNECT; break; case 'M': - if (bytes[position+1]=='O' && bytes[position+2]=='V' && bytes[position+3]=='E' && length>=5 && bytes[position+4]==' ') + if (bytes[position + 1] == 'O' && bytes[position + 2] == 'V' && bytes[position + 3] == 'E' && length >= 5 && bytes[position + 4] == ' ') return MOVE; break; @@ -107,85 +106,83 @@ public enum HttpMethod return null; } - /* ------------------------------------------------------------ */ /** * Optimized lookup to find a method name and trailing space in a byte array. + * * @param buffer buffer containing ISO-8859-1 characters, it is not modified. - * @return A HttpMethod if a match or null if no easy match. + * @return An HttpMethod if a match or null if no easy match. */ public static HttpMethod lookAheadGet(ByteBuffer buffer) { if (buffer.hasArray()) - return lookAheadGet(buffer.array(),buffer.arrayOffset()+buffer.position(),buffer.arrayOffset()+buffer.limit()); - + return lookAheadGet(buffer.array(), buffer.arrayOffset() + buffer.position(), buffer.arrayOffset() + buffer.limit()); + int l = buffer.remaining(); - if (l>=4) + if (l >= 4) { - HttpMethod m = CACHE.getBest(buffer,0,l); - if (m!=null) + HttpMethod m = CACHE.getBest(buffer, 0, l); + if (m != null) { int ml = m.asString().length(); - if (l>ml && buffer.get(buffer.position()+ml)==' ') + if (l > ml && buffer.get(buffer.position() + ml) == ' ') return m; } } return null; } - /* ------------------------------------------------------------ */ - public final static Trie INSENSITIVE_CACHE= new ArrayTrie<>(); + public static final Trie INSENSITIVE_CACHE = new ArrayTrie<>(); + static { for (HttpMethod method : HttpMethod.values()) - INSENSITIVE_CACHE.put(method.toString(),method); + { + INSENSITIVE_CACHE.put(method.toString(), method); + } } - /* ------------------------------------------------------------ */ - public final static Trie CACHE= new ArrayTernaryTrie<>(false); + public static final Trie CACHE = new ArrayTernaryTrie<>(false); + static { for (HttpMethod method : HttpMethod.values()) - CACHE.put(method.toString(),method); + { + CACHE.put(method.toString(), method); + } } - /* ------------------------------------------------------------ */ private final ByteBuffer _buffer; private final byte[] _bytes; - /* ------------------------------------------------------------ */ HttpMethod() { - _bytes=StringUtil.getBytes(toString()); - _buffer=ByteBuffer.wrap(_bytes); + _bytes = StringUtil.getBytes(toString()); + _buffer = ByteBuffer.wrap(_bytes); } - /* ------------------------------------------------------------ */ public byte[] getBytes() { return _bytes; } - /* ------------------------------------------------------------ */ public boolean is(String s) { return toString().equalsIgnoreCase(s); } - /* ------------------------------------------------------------ */ public ByteBuffer asBuffer() { return _buffer.asReadOnlyBuffer(); } - /* ------------------------------------------------------------ */ public String asString() { return toString(); } - /* ------------------------------------------------------------ */ /** * Converts the given String parameter to an HttpMethod + * * @param method the String to get the equivalent HttpMethod from * @return the HttpMethod or null if the parameter method is unknown */ diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java index 9284f75b81e..435579c9df0 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -28,6 +28,7 @@ import org.eclipse.jetty.http.HttpTokens.EndOfContent; import org.eclipse.jetty.util.ArrayTernaryTrie; import org.eclipse.jetty.util.ArrayTrie; import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.Trie; import org.eclipse.jetty.util.Utf8StringBuilder; import org.eclipse.jetty.util.log.Log; @@ -36,9 +37,8 @@ import org.eclipse.jetty.util.log.Logger; import static org.eclipse.jetty.http.HttpComplianceSection.MULTIPLE_CONTENT_LENGTHS; import static org.eclipse.jetty.http.HttpComplianceSection.TRANSFER_ENCODING_WITH_CONTENT_LENGTH; - -/* ------------------------------------------------------------ */ -/** A Parser for 1.0 and 1.1 as defined by RFC7230 +/** + * A Parser for 1.0 and 1.1 as defined by RFC7230 *

      * This parser parses HTTP client and server messages from buffers * passed in the {@link #parseNext(ByteBuffer)} method. The parsed @@ -79,29 +79,30 @@ import static org.eclipse.jetty.http.HttpComplianceSection.TRANSFER_ENCODING_WIT * exact case of header names, bypassing the header caches, which are case insensitive, * otherwise equivalent to RFC2616 * + * * @see RFC 7230 */ public class HttpParser { public static final Logger LOG = Log.getLogger(HttpParser.class); @Deprecated - public final static String __STRICT="org.eclipse.jetty.http.HttpParser.STRICT"; - public final static int INITIAL_URI_LENGTH=256; - private final static int MAX_CHUNK_LENGTH=Integer.MAX_VALUE/16-16; + public static final String __STRICT = "org.eclipse.jetty.http.HttpParser.STRICT"; + public static final int INITIAL_URI_LENGTH = 256; + private static final int MAX_CHUNK_LENGTH = Integer.MAX_VALUE / 16 - 16; /** * Cache of common {@link HttpField}s including:

        *
      • Common static combinations such as:
          - *
        • Connection: close - *
        • Accept-Encoding: gzip - *
        • Content-Length: 0 + *
        • Connection: close + *
        • Accept-Encoding: gzip + *
        • Content-Length: 0 *
        *
      • Combinations of Content-Type header for common mime types by common charsets *
      • Most common headers with null values so that a lookup will at least * determine the header name even if the name:value combination is not cached *
      */ - public final static Trie CACHE = new ArrayTrie<>(2048); + public static final Trie CACHE = new ArrayTrie<>(2048); // States public enum FieldState @@ -112,7 +113,7 @@ public class HttpParser IN_VALUE, WS_AFTER_NAME, } - + // States public enum State { @@ -139,10 +140,10 @@ public class HttpParser CLOSED // The associated stream/endpoint is at EOF } - private final static EnumSet __idleStates = EnumSet.of(State.START,State.END,State.CLOSE,State.CLOSED); - private final static EnumSet __completeStates = EnumSet.of(State.END,State.CLOSE,State.CLOSED); + private static final EnumSet __idleStates = EnumSet.of(State.START, State.END, State.CLOSE, State.CLOSED); + private static final EnumSet __completeStates = EnumSet.of(State.END, State.CLOSE, State.CLOSED); - private final boolean DEBUG=LOG.isDebugEnabled(); // Cache debug to help branch prediction + private final boolean debug = LOG.isDebugEnabled(); // Cache debug to help branch prediction private final HttpHandler _handler; private final RequestHandler _requestHandler; private final ResponseHandler _responseHandler; @@ -159,14 +160,13 @@ public class HttpParser private boolean _host; private boolean _headerComplete; - /* ------------------------------------------------------------------------------- */ - private volatile State _state=State.START; - private volatile FieldState _fieldState=FieldState.FIELD; + private volatile State _state = State.START; + private volatile FieldState _fieldState = FieldState.FIELD; private volatile boolean _eof; private HttpMethod _method; private String _methodString; private HttpVersion _version; - private Utf8StringBuilder _uri=new Utf8StringBuilder(INITIAL_URI_LENGTH); // Tune? + private Utf8StringBuilder _uri = new Utf8StringBuilder(INITIAL_URI_LENGTH); // Tune? private EndOfContent _endOfContent; private boolean _hasContentLength; private long _contentLength = -1; @@ -179,55 +179,59 @@ public class HttpParser private Trie _fieldCache; private int _length; - private final StringBuilder _string=new StringBuilder(); + private final StringBuilder _string = new StringBuilder(); static { - CACHE.put(new HttpField(HttpHeader.CONNECTION,HttpHeaderValue.CLOSE)); - CACHE.put(new HttpField(HttpHeader.CONNECTION,HttpHeaderValue.KEEP_ALIVE)); - CACHE.put(new HttpField(HttpHeader.CONNECTION,HttpHeaderValue.UPGRADE)); - CACHE.put(new HttpField(HttpHeader.ACCEPT_ENCODING,"gzip")); - CACHE.put(new HttpField(HttpHeader.ACCEPT_ENCODING,"gzip, deflate")); - CACHE.put(new HttpField(HttpHeader.ACCEPT_ENCODING,"gzip, deflate, br")); - CACHE.put(new HttpField(HttpHeader.ACCEPT_ENCODING,"gzip,deflate,sdch")); - CACHE.put(new HttpField(HttpHeader.ACCEPT_LANGUAGE,"en-US,en;q=0.5")); - CACHE.put(new HttpField(HttpHeader.ACCEPT_LANGUAGE,"en-GB,en-US;q=0.8,en;q=0.6")); - CACHE.put(new HttpField(HttpHeader.ACCEPT_LANGUAGE,"en-AU,en;q=0.9,it-IT;q=0.8,it;q=0.7,en-GB;q=0.6,en-US;q=0.5")); - CACHE.put(new HttpField(HttpHeader.ACCEPT_CHARSET,"ISO-8859-1,utf-8;q=0.7,*;q=0.3")); - CACHE.put(new HttpField(HttpHeader.ACCEPT,"*/*")); - CACHE.put(new HttpField(HttpHeader.ACCEPT,"image/png,image/*;q=0.8,*/*;q=0.5")); - CACHE.put(new HttpField(HttpHeader.ACCEPT,"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")); - CACHE.put(new HttpField(HttpHeader.ACCEPT,"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8")); - CACHE.put(new HttpField(HttpHeader.ACCEPT_RANGES,HttpHeaderValue.BYTES)); - CACHE.put(new HttpField(HttpHeader.PRAGMA,"no-cache")); - CACHE.put(new HttpField(HttpHeader.CACHE_CONTROL,"private, no-cache, no-cache=Set-Cookie, proxy-revalidate")); - CACHE.put(new HttpField(HttpHeader.CACHE_CONTROL,"no-cache")); - CACHE.put(new HttpField(HttpHeader.CACHE_CONTROL,"max-age=0")); - CACHE.put(new HttpField(HttpHeader.CONTENT_LENGTH,"0")); - CACHE.put(new HttpField(HttpHeader.CONTENT_ENCODING,"gzip")); - CACHE.put(new HttpField(HttpHeader.CONTENT_ENCODING,"deflate")); - CACHE.put(new HttpField(HttpHeader.TRANSFER_ENCODING,"chunked")); - CACHE.put(new HttpField(HttpHeader.EXPIRES,"Fri, 01 Jan 1990 00:00:00 GMT")); + CACHE.put(new HttpField(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE)); + CACHE.put(new HttpField(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE)); + CACHE.put(new HttpField(HttpHeader.CONNECTION, HttpHeaderValue.UPGRADE)); + CACHE.put(new HttpField(HttpHeader.ACCEPT_ENCODING, "gzip")); + CACHE.put(new HttpField(HttpHeader.ACCEPT_ENCODING, "gzip, deflate")); + CACHE.put(new HttpField(HttpHeader.ACCEPT_ENCODING, "gzip, deflate, br")); + CACHE.put(new HttpField(HttpHeader.ACCEPT_ENCODING, "gzip,deflate,sdch")); + CACHE.put(new HttpField(HttpHeader.ACCEPT_LANGUAGE, "en-US,en;q=0.5")); + CACHE.put(new HttpField(HttpHeader.ACCEPT_LANGUAGE, "en-GB,en-US;q=0.8,en;q=0.6")); + CACHE.put(new HttpField(HttpHeader.ACCEPT_LANGUAGE, "en-AU,en;q=0.9,it-IT;q=0.8,it;q=0.7,en-GB;q=0.6,en-US;q=0.5")); + CACHE.put(new HttpField(HttpHeader.ACCEPT_CHARSET, "ISO-8859-1,utf-8;q=0.7,*;q=0.3")); + CACHE.put(new HttpField(HttpHeader.ACCEPT, "*/*")); + CACHE.put(new HttpField(HttpHeader.ACCEPT, "image/png,image/*;q=0.8,*/*;q=0.5")); + CACHE.put(new HttpField(HttpHeader.ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")); + CACHE.put(new HttpField(HttpHeader.ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8")); + CACHE.put(new HttpField(HttpHeader.ACCEPT_RANGES, HttpHeaderValue.BYTES)); + CACHE.put(new HttpField(HttpHeader.PRAGMA, "no-cache")); + CACHE.put(new HttpField(HttpHeader.CACHE_CONTROL, "private, no-cache, no-cache=Set-Cookie, proxy-revalidate")); + CACHE.put(new HttpField(HttpHeader.CACHE_CONTROL, "no-cache")); + CACHE.put(new HttpField(HttpHeader.CACHE_CONTROL, "max-age=0")); + CACHE.put(new HttpField(HttpHeader.CONTENT_LENGTH, "0")); + CACHE.put(new HttpField(HttpHeader.CONTENT_ENCODING, "gzip")); + CACHE.put(new HttpField(HttpHeader.CONTENT_ENCODING, "deflate")); + CACHE.put(new HttpField(HttpHeader.TRANSFER_ENCODING, "chunked")); + CACHE.put(new HttpField(HttpHeader.EXPIRES, "Fri, 01 Jan 1990 00:00:00 GMT")); // Add common Content types as fields - for (String type : new String[]{"text/plain","text/html","text/xml","text/json","application/json","application/x-www-form-urlencoded"}) + for (String type : new String[]{ + "text/plain", "text/html", "text/xml", "text/json", "application/json", "application/x-www-form-urlencoded" + }) { - HttpField field=new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,type); + HttpField field = new PreEncodedHttpField(HttpHeader.CONTENT_TYPE, type); CACHE.put(field); - for (String charset : new String[]{"utf-8","iso-8859-1"}) + for (String charset : new String[]{"utf-8", "iso-8859-1"}) { - CACHE.put(new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,type+";charset="+charset)); - CACHE.put(new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,type+"; charset="+charset)); - CACHE.put(new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,type+";charset="+charset.toUpperCase(Locale.ENGLISH))); - CACHE.put(new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,type+"; charset="+charset.toUpperCase(Locale.ENGLISH))); + CACHE.put(new PreEncodedHttpField(HttpHeader.CONTENT_TYPE, type + ";charset=" + charset)); + CACHE.put(new PreEncodedHttpField(HttpHeader.CONTENT_TYPE, type + "; charset=" + charset)); + CACHE.put(new PreEncodedHttpField(HttpHeader.CONTENT_TYPE, type + ";charset=" + charset.toUpperCase(Locale.ENGLISH))); + CACHE.put(new PreEncodedHttpField(HttpHeader.CONTENT_TYPE, type + "; charset=" + charset.toUpperCase(Locale.ENGLISH))); } } // Add headers with null values so HttpParser can avoid looking up name again for unknown values - for (HttpHeader h:HttpHeader.values()) - if (!CACHE.put(new HttpField(h,(String)null))) + for (HttpHeader h : HttpHeader.values()) + { + if (!CACHE.put(new HttpField(h, (String)null))) throw new IllegalStateException("CACHE FULL"); + } } private static HttpCompliance compliance() @@ -235,98 +239,89 @@ public class HttpParser Boolean strict = Boolean.getBoolean(__STRICT); if (strict) { - LOG.warn("Deprecated property used: "+__STRICT); + LOG.warn("Deprecated property used: " + __STRICT); return HttpCompliance.LEGACY; } return HttpCompliance.RFC7230; } - /* ------------------------------------------------------------------------------- */ public HttpParser(RequestHandler handler) { - this(handler,-1,compliance()); + this(handler, -1, compliance()); } - /* ------------------------------------------------------------------------------- */ public HttpParser(ResponseHandler handler) { - this(handler,-1,compliance()); + this(handler, -1, compliance()); } - /* ------------------------------------------------------------------------------- */ - public HttpParser(RequestHandler handler,int maxHeaderBytes) + public HttpParser(RequestHandler handler, int maxHeaderBytes) { - this(handler,maxHeaderBytes,compliance()); + this(handler, maxHeaderBytes, compliance()); } - /* ------------------------------------------------------------------------------- */ - public HttpParser(ResponseHandler handler,int maxHeaderBytes) + public HttpParser(ResponseHandler handler, int maxHeaderBytes) { - this(handler,maxHeaderBytes,compliance()); + this(handler, maxHeaderBytes, compliance()); } - /* ------------------------------------------------------------------------------- */ @Deprecated - public HttpParser(RequestHandler handler,int maxHeaderBytes,boolean strict) + public HttpParser(RequestHandler handler, int maxHeaderBytes, boolean strict) { - this(handler,maxHeaderBytes,strict?HttpCompliance.LEGACY:compliance()); + this(handler, maxHeaderBytes, strict ? HttpCompliance.LEGACY : compliance()); } - /* ------------------------------------------------------------------------------- */ @Deprecated - public HttpParser(ResponseHandler handler,int maxHeaderBytes,boolean strict) + public HttpParser(ResponseHandler handler, int maxHeaderBytes, boolean strict) { - this(handler,maxHeaderBytes,strict?HttpCompliance.LEGACY:compliance()); + this(handler, maxHeaderBytes, strict ? HttpCompliance.LEGACY : compliance()); } - /* ------------------------------------------------------------------------------- */ - public HttpParser(RequestHandler handler,HttpCompliance compliance) + public HttpParser(RequestHandler handler, HttpCompliance compliance) { - this(handler,-1,compliance); + this(handler, -1, compliance); } - /* ------------------------------------------------------------------------------- */ - public HttpParser(RequestHandler handler,int maxHeaderBytes,HttpCompliance compliance) + public HttpParser(RequestHandler handler, int maxHeaderBytes, HttpCompliance compliance) { - this(handler,null,maxHeaderBytes,compliance==null?compliance():compliance); + this(handler, null, maxHeaderBytes, compliance == null ? compliance() : compliance); } - /* ------------------------------------------------------------------------------- */ - public HttpParser(ResponseHandler handler,int maxHeaderBytes,HttpCompliance compliance) + public HttpParser(ResponseHandler handler, int maxHeaderBytes, HttpCompliance compliance) { - this(null,handler,maxHeaderBytes,compliance==null?compliance():compliance); + this(null, handler, maxHeaderBytes, compliance == null ? compliance() : compliance); } - /* ------------------------------------------------------------------------------- */ - private HttpParser(RequestHandler requestHandler,ResponseHandler responseHandler,int maxHeaderBytes,HttpCompliance compliance) + private HttpParser(RequestHandler requestHandler, ResponseHandler responseHandler, int maxHeaderBytes, HttpCompliance compliance) { - _handler=requestHandler!=null?requestHandler:responseHandler; - _requestHandler=requestHandler; - _responseHandler=responseHandler; - _maxHeaderBytes=maxHeaderBytes; - _compliance=compliance; - _compliances=compliance.sections(); - _complianceHandler=(ComplianceHandler)(_handler instanceof ComplianceHandler?_handler:null); + _handler = requestHandler != null ? requestHandler : responseHandler; + _requestHandler = requestHandler; + _responseHandler = responseHandler; + _maxHeaderBytes = maxHeaderBytes; + _compliance = compliance; + _compliances = compliance.sections(); + _complianceHandler = (ComplianceHandler)(_handler instanceof ComplianceHandler ? _handler : null); } - /* ------------------------------------------------------------------------------- */ public HttpHandler getHandler() { return _handler; } - /* ------------------------------------------------------------------------------- */ - /** Check RFC compliance violation + /** + * Check RFC compliance violation + * * @param violation The compliance section violation * @return True if the current compliance level is set so as to Not allow this violation */ protected boolean complianceViolation(HttpComplianceSection violation) { - return complianceViolation(violation,null); + return complianceViolation(violation, null); } - - /* ------------------------------------------------------------------------------- */ - /** Check RFC compliance violation + + /** + * Check RFC compliance violation + * * @param violation The compliance section violation * @param reason The reason for the violation * @return True if the current compliance level is set so as to Not allow this violation @@ -335,143 +330,128 @@ public class HttpParser { if (_compliances.contains(violation)) return true; - if (reason==null) - reason=violation.description; - if (_complianceHandler!=null) - _complianceHandler.onComplianceViolation(_compliance,violation,reason); - + if (reason == null) + reason = violation.description; + if (_complianceHandler != null) + _complianceHandler.onComplianceViolation(_compliance, violation, reason); + return false; } - /* ------------------------------------------------------------------------------- */ - protected void handleViolation(HttpComplianceSection section,String reason) + protected void handleViolation(HttpComplianceSection section, String reason) { - if (_complianceHandler!=null) - _complianceHandler.onComplianceViolation(_compliance,section,reason); + if (_complianceHandler != null) + _complianceHandler.onComplianceViolation(_compliance, section, reason); } - /* ------------------------------------------------------------------------------- */ protected String caseInsensitiveHeader(String orig, String normative) - { + { if (_compliances.contains(HttpComplianceSection.FIELD_NAME_CASE_INSENSITIVE)) return normative; if (!orig.equals(normative)) - handleViolation(HttpComplianceSection.FIELD_NAME_CASE_INSENSITIVE,orig); + handleViolation(HttpComplianceSection.FIELD_NAME_CASE_INSENSITIVE, orig); return orig; } - - /* ------------------------------------------------------------------------------- */ + public long getContentLength() { return _contentLength; } - /* ------------------------------------------------------------ */ public long getContentRead() { return _contentPosition; } - /* ------------------------------------------------------------ */ - /** Set if a HEAD response is expected + /** + * Set if a HEAD response is expected + * * @param head true if head response is expected */ public void setHeadResponse(boolean head) { - _headResponse=head; + _headResponse = head; } - /* ------------------------------------------------------------------------------- */ protected void setResponseStatus(int status) { - _responseStatus=status; + _responseStatus = status; } - /* ------------------------------------------------------------------------------- */ public State getState() { return _state; } - /* ------------------------------------------------------------------------------- */ public boolean inContentState() { - return _state.ordinal()>=State.CONTENT.ordinal() && _state.ordinal()= State.CONTENT.ordinal() && _state.ordinal() < State.END.ordinal(); } - /* ------------------------------------------------------------------------------- */ public boolean inHeaderState() { return _state.ordinal() < State.CONTENT.ordinal(); } - /* ------------------------------------------------------------------------------- */ public boolean isChunking() { - return _endOfContent==EndOfContent.CHUNKED_CONTENT; + return _endOfContent == EndOfContent.CHUNKED_CONTENT; } - /* ------------------------------------------------------------ */ public boolean isStart() { return isState(State.START); } - /* ------------------------------------------------------------ */ public boolean isClose() { return isState(State.CLOSE); } - /* ------------------------------------------------------------ */ public boolean isClosed() { return isState(State.CLOSED); } - /* ------------------------------------------------------------ */ public boolean isIdle() { return __idleStates.contains(_state); } - /* ------------------------------------------------------------ */ public boolean isComplete() { return __completeStates.contains(_state); } - /* ------------------------------------------------------------------------------- */ public boolean isState(State state) { return _state == state; } - /* ------------------------------------------------------------------------------- */ private HttpTokens.Token next(ByteBuffer buffer) { byte ch = buffer.get(); HttpTokens.Token t = HttpTokens.TOKENS[0xff & ch]; - - switch(t.getType()) + + switch (t.getType()) { case CNTL: - throw new IllegalCharacterException(_state,t,buffer); + throw new IllegalCharacterException(_state, t, buffer); case LF: - _cr=false; + _cr = false; break; case CR: if (_cr) throw new BadMessageException("Bad EOL"); - _cr=true; + _cr = true; if (buffer.hasRemaining()) { // Don't count the CRs and LFs of the chunked encoding. - if (_maxHeaderBytes>0 && (_state == State.HEADER || _state == State.TRAILER)) + if (_maxHeaderBytes > 0 && (_state == State.HEADER || _state == State.TRAILER)) _headerBytes++; return next(buffer); } @@ -489,7 +469,7 @@ public class HttpParser if (_cr) throw new BadMessageException("Bad EOL"); break; - + default: break; } @@ -497,43 +477,42 @@ public class HttpParser return t; } - /* ------------------------------------------------------------------------------- */ - /* Quick lookahead for the start state looking for a request method or a HTTP version, + /* 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) { - if (_requestHandler!=null) + if (_requestHandler != null) { _method = HttpMethod.lookAheadGet(buffer); - if (_method!=null) + if (_method != null) { _methodString = _method.asString(); - buffer.position(buffer.position()+_methodString.length()+1); + buffer.position(buffer.position() + _methodString.length() + 1); setState(State.SPACE1); return false; } } - else if (_responseHandler!=null) + else if (_responseHandler != null) { _version = HttpVersion.lookAheadGet(buffer); - if (_version!=null) + if (_version != null) { - buffer.position(buffer.position()+_version.asString().length()+1); + buffer.position(buffer.position() + _version.asString().length() + 1); setState(State.SPACE1); return false; } } // Quick start look - while (_state==State.START && buffer.hasRemaining()) + while (_state == State.START && buffer.hasRemaining()) { HttpTokens.Token t = next(buffer); - if (t==null) + if (t == null) break; - - switch(t.getType()) + + switch (t.getType()) { case ALPHA: case DIGIT: @@ -542,92 +521,87 @@ public class HttpParser { _string.setLength(0); _string.append(t.getChar()); - setState(_requestHandler!=null?State.METHOD:State.RESPONSE_VERSION); + setState(_requestHandler != null ? State.METHOD : State.RESPONSE_VERSION); return false; } case OTEXT: case SPACE: case HTAB: - throw new IllegalCharacterException(_state,t,buffer); - + throw new IllegalCharacterException(_state, t, buffer); + default: break; } // count this white space as a header byte to avoid DOS - if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes) + if (_maxHeaderBytes > 0 && ++_headerBytes > _maxHeaderBytes) { - LOG.warn("padding is too large >"+_maxHeaderBytes); + LOG.warn("padding is too large >" + _maxHeaderBytes); throw new BadMessageException(HttpStatus.BAD_REQUEST_400); } } return false; } - /* ------------------------------------------------------------------------------- */ private void setString(String s) { _string.setLength(0); _string.append(s); - _length=s.length(); + _length = s.length(); } - /* ------------------------------------------------------------------------------- */ private String takeString() { _string.setLength(_length); - String s =_string.toString(); + String s = _string.toString(); _string.setLength(0); - _length=-1; + _length = -1; return s; } - - /* ------------------------------------------------------------------------------- */ + private boolean handleHeaderContentMessage() { - boolean handle_header = _handler.headerComplete(); + boolean handleHeader = _handler.headerComplete(); _headerComplete = true; - boolean handle_content = _handler.contentComplete(); - boolean handle_message = _handler.messageComplete(); - return handle_header || handle_content || handle_message; - } - - /* ------------------------------------------------------------------------------- */ - private boolean handleContentMessage() - { - boolean handle_content = _handler.contentComplete(); - boolean handle_message = _handler.messageComplete(); - return handle_content || handle_message; + boolean handleContent = _handler.contentComplete(); + boolean handleMessage = _handler.messageComplete(); + return handleHeader || handleContent || handleMessage; + } + + private boolean handleContentMessage() + { + boolean handleContent = _handler.contentComplete(); + boolean handleMessage = _handler.messageComplete(); + return handleContent || handleMessage; } - /* ------------------------------------------------------------------------------- */ /* Parse a request or response line */ private boolean parseLine(ByteBuffer buffer) { - boolean handle=false; + boolean handle = false; // Process headers - while (_state.ordinal()0 && ++_headerBytes>_maxHeaderBytes) + if (_maxHeaderBytes > 0 && ++_headerBytes > _maxHeaderBytes) { - if (_state==State.URI) + if (_state == State.URI) { - LOG.warn("URI is too large >"+_maxHeaderBytes); + LOG.warn("URI is too large >" + _maxHeaderBytes); throw new BadMessageException(HttpStatus.URI_TOO_LONG_414); } else { - if (_requestHandler!=null) - LOG.warn("request is too large >"+_maxHeaderBytes); + if (_requestHandler != null) + LOG.warn("request is too large >" + _maxHeaderBytes); else - LOG.warn("response is too large >"+_maxHeaderBytes); + LOG.warn("response is too large >" + _maxHeaderBytes); throw new BadMessageException(HttpStatus.REQUEST_HEADER_FIELDS_TOO_LARGE_431); } } @@ -635,33 +609,33 @@ public class HttpParser switch (_state) { case METHOD: - switch(t.getType()) + switch (t.getType()) { case SPACE: - _length=_string.length(); - _methodString=takeString(); + _length = _string.length(); + _methodString = takeString(); if (_compliances.contains(HttpComplianceSection.METHOD_CASE_SENSITIVE)) { - HttpMethod method=HttpMethod.CACHE.get(_methodString); - if (method!=null) + HttpMethod method = HttpMethod.CACHE.get(_methodString); + if (method != null) _methodString = method.asString(); } else { - HttpMethod method=HttpMethod.INSENSITIVE_CACHE.get(_methodString); + HttpMethod method = HttpMethod.INSENSITIVE_CACHE.get(_methodString); - if (method!=null) + if (method != null) { if (!method.asString().equals(_methodString)) - handleViolation(HttpComplianceSection.METHOD_CASE_SENSITIVE,_methodString); + handleViolation(HttpComplianceSection.METHOD_CASE_SENSITIVE, _methodString); _methodString = method.asString(); } } setState(State.SPACE1); break; - + case LF: throw new BadMessageException("No URI"); @@ -672,17 +646,17 @@ public class HttpParser break; default: - throw new IllegalCharacterException(_state,t,buffer); + throw new IllegalCharacterException(_state, t, buffer); } break; case RESPONSE_VERSION: - switch(t.getType()) + switch (t.getType()) { case SPACE: - _length=_string.length(); - String version=takeString(); - _version=HttpVersion.CACHE.get(version); + _length = _string.length(); + String version = takeString(); + _version = HttpVersion.CACHE.get(version); checkVersion(); setState(State.SPACE1); break; @@ -695,27 +669,27 @@ public class HttpParser _string.append(t.getChar()); break; default: - throw new IllegalCharacterException(_state,t,buffer); + throw new IllegalCharacterException(_state, t, buffer); } break; case SPACE1: - switch(t.getType()) + switch (t.getType()) { case SPACE: break; - + case ALPHA: case DIGIT: case TCHAR: case VCHAR: case COLON: - if (_responseHandler!=null) + if (_responseHandler != null) { - if (t.getType()!=HttpTokens.Type.DIGIT) - throw new IllegalCharacterException(_state,t,buffer); + if (t.getType() != HttpTokens.Type.DIGIT) + throw new IllegalCharacterException(_state, t, buffer); setState(State.STATUS); - setResponseStatus(t.getByte()-'0'); + setResponseStatus(t.getByte() - '0'); } else { @@ -724,23 +698,25 @@ public class HttpParser // quick scan for space or EoBuffer if (buffer.hasArray()) { - byte[] array=buffer.array(); - int p=buffer.arrayOffset()+buffer.position(); - int l=buffer.arrayOffset()+buffer.limit(); - int i=p; - while (iHttpTokens.SPACE) - i++; - - int len=i-p; - _headerBytes+=len; - - if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes) + byte[] array = buffer.array(); + int p = buffer.arrayOffset() + buffer.position(); + int l = buffer.arrayOffset() + buffer.limit(); + int i = p; + while (i < l && array[i] > HttpTokens.SPACE) { - LOG.warn("URI is too large >"+_maxHeaderBytes); + i++; + } + + int len = i - p; + _headerBytes += len; + + if (_maxHeaderBytes > 0 && ++_headerBytes > _maxHeaderBytes) + { + LOG.warn("URI is too large >" + _maxHeaderBytes); throw new BadMessageException(HttpStatus.URI_TOO_LONG_414); } - _uri.append(array,p-1,len+1); - buffer.position(i-buffer.arrayOffset()); + _uri.append(array, p - 1, len + 1); + buffer.position(i - buffer.arrayOffset()); } else _uri.append(t.getByte()); @@ -748,48 +724,48 @@ public class HttpParser break; default: - throw new BadMessageException(HttpStatus.BAD_REQUEST_400,_requestHandler!=null?"No URI":"No Status"); + throw new BadMessageException(HttpStatus.BAD_REQUEST_400, _requestHandler != null ? "No URI" : "No Status"); } break; case STATUS: - switch(t.getType()) + switch (t.getType()) { case SPACE: setState(State.SPACE2); break; - + case DIGIT: - _responseStatus=_responseStatus*10+(t.getByte()-'0'); - if (_responseStatus>=1000) + _responseStatus = _responseStatus * 10 + (t.getByte() - '0'); + if (_responseStatus >= 1000) throw new BadMessageException("Bad status"); break; - + case LF: setState(State.HEADER); - handle=_responseHandler.startResponse(_version, _responseStatus, null)||handle; + handle |= _responseHandler.startResponse(_version, _responseStatus, null); break; - + default: - throw new IllegalCharacterException(_state,t,buffer); + throw new IllegalCharacterException(_state, t, buffer); } break; case URI: - switch(t.getType()) + switch (t.getType()) { case SPACE: setState(State.SPACE2); break; - + case LF: // HTTP/0.9 - if (complianceViolation(HttpComplianceSection.NO_HTTP_0_9,"No request version")) + if (complianceViolation(HttpComplianceSection.NO_HTTP_0_9, "No request version")) throw new BadMessageException("HTTP/0.9 not supported"); - handle=_requestHandler.startRequest(_methodString,_uri.toString(), HttpVersion.HTTP_0_9); + handle = _requestHandler.startRequest(_methodString, _uri.toString(), HttpVersion.HTTP_0_9); setState(State.END); BufferUtil.clear(buffer); - handle= handleHeaderContentMessage() || handle; + handle |= handleHeaderContentMessage(); break; case ALPHA: @@ -800,14 +776,14 @@ public class HttpParser case OTEXT: _uri.append(t.getByte()); break; - + default: - throw new IllegalCharacterException(_state,t,buffer); + throw new IllegalCharacterException(_state, t, buffer); } break; case SPACE2: - switch(t.getType()) + switch (t.getType()) { case SPACE: break; @@ -819,9 +795,9 @@ public class HttpParser case COLON: _string.setLength(0); _string.append(t.getChar()); - if (_responseHandler!=null) + if (_responseHandler != null) { - _length=1; + _length = 1; setState(State.REASON); } else @@ -830,28 +806,28 @@ public class HttpParser // try quick look ahead for HTTP Version HttpVersion version; - if (buffer.position()>0 && buffer.hasArray()) - version=HttpVersion.lookAheadGet(buffer.array(),buffer.arrayOffset()+buffer.position()-1,buffer.arrayOffset()+buffer.limit()); + if (buffer.position() > 0 && buffer.hasArray()) + version = HttpVersion.lookAheadGet(buffer.array(), buffer.arrayOffset() + buffer.position() - 1, buffer.arrayOffset() + buffer.limit()); else - version=HttpVersion.CACHE.getBest(buffer,0,buffer.remaining()); + version = HttpVersion.CACHE.getBest(buffer, 0, buffer.remaining()); - if (version!=null) + if (version != null) { - int pos = buffer.position()+version.asString().length()-1; - if (pos=HttpVersion.HTTP_1_1.getVersion() && _handler.getHeaderCacheSize()>0) + if (_fieldCache == null && _version.getVersion() >= HttpVersion.HTTP_1_1.getVersion() && _handler.getHeaderCacheSize() > 0) { - int header_cache = _handler.getHeaderCacheSize(); - _fieldCache=new ArrayTernaryTrie<>(header_cache); + int headerCache = _handler.getHeaderCacheSize(); + _fieldCache = new ArrayTernaryTrie<>(headerCache); } setState(State.HEADER); - handle=_requestHandler.startRequest(_methodString,_uri.toString(), _version)||handle; + handle |= _requestHandler.startRequest(_methodString, _uri.toString(), _version); continue; case ALPHA: @@ -915,19 +891,19 @@ public class HttpParser case COLON: _string.append(t.getChar()); break; - + default: - throw new IllegalCharacterException(_state,t,buffer); + throw new IllegalCharacterException(_state, t, buffer); } break; case REASON: - switch(t.getType()) + switch (t.getType()) { case LF: - String reason=takeString(); + String reason = takeString(); setState(State.HEADER); - handle=_responseHandler.startResponse(_version, _responseStatus, reason)||handle; + handle |= _responseHandler.startResponse(_version, _responseStatus, reason); continue; case ALPHA: @@ -937,16 +913,16 @@ public class HttpParser case COLON: case OTEXT: // TODO should this be UTF8 _string.append(t.getChar()); - _length=_string.length(); + _length = _string.length(); break; - + case SPACE: case HTAB: _string.append(t.getChar()); break; - + default: - throw new IllegalCharacterException(_state,t,buffer); + throw new IllegalCharacterException(_state, t, buffer); } break; @@ -958,88 +934,87 @@ public class HttpParser return handle; } - private void checkVersion() + private void checkVersion() { - if (_version==null) - throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Unknown Version"); - - if (_version.getVersion()<10 || _version.getVersion()>20) - throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad Version"); + if (_version == null) + throw new BadMessageException(HttpStatus.BAD_REQUEST_400, "Unknown Version"); + + if (_version.getVersion() < 10 || _version.getVersion() > 20) + throw new BadMessageException(HttpStatus.BAD_REQUEST_400, "Bad Version"); } private void parsedHeader() { // handler last header if any. Delayed to here just in case there was a continuation line (above) - if (_headerString!=null || _valueString!=null) + if (_headerString != null || _valueString != null) { // Handle known headers - if (_header!=null) + if (_header != null) { - boolean add_to_connection_trie=false; + boolean addToConnectionTrie = false; switch (_header) { case CONTENT_LENGTH: 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 (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); } _hasContentLength = true; if (_endOfContent == EndOfContent.CHUNKED_CONTENT && complianceViolation(TRANSFER_ENCODING_WITH_CONTENT_LENGTH)) - throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad Content-Length"); + throw new BadMessageException(HttpStatus.BAD_REQUEST_400, "Bad Content-Length"); if (_endOfContent != EndOfContent.CHUNKED_CONTENT) { - _contentLength=convertContentLength(_valueString); + _contentLength = convertContentLength(_valueString); if (_contentLength <= 0) - _endOfContent=EndOfContent.NO_CONTENT; + _endOfContent = EndOfContent.NO_CONTENT; else - _endOfContent=EndOfContent.CONTENT_LENGTH; + _endOfContent = EndOfContent.CONTENT_LENGTH; } break; case TRANSFER_ENCODING: if (_hasContentLength && complianceViolation(TRANSFER_ENCODING_WITH_CONTENT_LENGTH)) - throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Transfer-Encoding and Content-Length"); + throw new BadMessageException(HttpStatus.BAD_REQUEST_400, "Transfer-Encoding and Content-Length"); if (HttpHeaderValue.CHUNKED.is(_valueString)) { - _endOfContent=EndOfContent.CHUNKED_CONTENT; - _contentLength=-1; + _endOfContent = EndOfContent.CHUNKED_CONTENT; + _contentLength = -1; } else { List values = new QuotedCSV(_valueString).getValues(); - if (values.size()>0 && HttpHeaderValue.CHUNKED.is(values.get(values.size()-1))) + if (!values.isEmpty() && HttpHeaderValue.CHUNKED.is(values.get(values.size() - 1))) { - _endOfContent=EndOfContent.CHUNKED_CONTENT; - _contentLength=-1; + _endOfContent = EndOfContent.CHUNKED_CONTENT; + _contentLength = -1; } else if (values.stream().anyMatch(HttpHeaderValue.CHUNKED::is)) - throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad chunking"); + throw new BadMessageException(HttpStatus.BAD_REQUEST_400, "Bad chunking"); } - - + break; case HOST: - _host=true; - if (!(_field instanceof HostPortHttpField) && _valueString!=null && !_valueString.isEmpty()) + _host = true; + if (!(_field instanceof HostPortHttpField) && _valueString != null && !_valueString.isEmpty()) { - _field=new HostPortHttpField(_header, - _compliances.contains(HttpComplianceSection.FIELD_NAME_CASE_INSENSITIVE)?_header.asString():_headerString, + _field = new HostPortHttpField(_header, + _compliances.contains(HttpComplianceSection.FIELD_NAME_CASE_INSENSITIVE) ? _header.asString() : _headerString, _valueString); - add_to_connection_trie=_fieldCache!=null; + addToConnectionTrie = _fieldCache != null; } - break; + break; case CONNECTION: // Don't cache headers if not persistent if (HttpHeaderValue.CLOSE.is(_valueString) || new QuotedCSV(_valueString).getValues().stream().anyMatch(HttpHeaderValue.CLOSE::is)) - _fieldCache=null; + _fieldCache = null; break; case AUTHORIZATION: @@ -1050,99 +1025,98 @@ public class HttpParser case COOKIE: case CACHE_CONTROL: case USER_AGENT: - add_to_connection_trie=_fieldCache!=null && _field==null; + addToConnectionTrie = _fieldCache != null && _field == null; break; - default: break; - + default: + break; } - if (add_to_connection_trie && !_fieldCache.isFull() && _header!=null && _valueString!=null) + if (addToConnectionTrie && !_fieldCache.isFull() && _header != null && _valueString != null) { - if (_field==null) - _field=new HttpField(_header,caseInsensitiveHeader(_headerString,_header.asString()),_valueString); + if (_field == null) + _field = new HttpField(_header, caseInsensitiveHeader(_headerString, _header.asString()), _valueString); _fieldCache.put(_field); } } - _handler.parsedHeader(_field!=null?_field:new HttpField(_header,_headerString,_valueString)); + _handler.parsedHeader(_field != null ? _field : new HttpField(_header, _headerString, _valueString)); } - _headerString=_valueString=null; - _header=null; - _field=null; + _headerString = _valueString = null; + _header = null; + _field = null; } private void parsedTrailer() { // handler last header if any. Delayed to here just in case there was a continuation line (above) - if (_headerString!=null || _valueString!=null) - _handler.parsedTrailer(_field!=null?_field:new HttpField(_header,_headerString,_valueString)); + if (_headerString != null || _valueString != null) + _handler.parsedTrailer(_field != null ? _field : new HttpField(_header, _headerString, _valueString)); - _headerString=_valueString=null; - _header=null; - _field=null; + _headerString = _valueString = null; + _header = null; + _field = null; } - + private long convertContentLength(String valueString) { try { return Long.parseLong(valueString); } - catch(NumberFormatException e) + catch (NumberFormatException e) { LOG.ignore(e); - throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Invalid Content-Length Value"); + throw new BadMessageException(HttpStatus.BAD_REQUEST_400, "Invalid Content-Length Value", e); } } - /* ------------------------------------------------------------------------------- */ /* * Parse the message headers and return true if the handler has signalled for a return */ protected boolean parseFields(ByteBuffer buffer) { // Process headers - while ((_state==State.HEADER || _state==State.TRAILER) && buffer.hasRemaining()) + while ((_state == State.HEADER || _state == State.TRAILER) && buffer.hasRemaining()) { // process each character HttpTokens.Token t = next(buffer); - if (t==null) + if (t == null) break; - if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes) + if (_maxHeaderBytes > 0 && ++_headerBytes > _maxHeaderBytes) { boolean header = _state == State.HEADER; LOG.warn("{} is too large {}>{}", header ? "Header" : "Trailer", _headerBytes, _maxHeaderBytes); - throw new BadMessageException(header ? - HttpStatus.REQUEST_HEADER_FIELDS_TOO_LARGE_431 : - HttpStatus.PAYLOAD_TOO_LARGE_413); + throw new BadMessageException(header + ? HttpStatus.REQUEST_HEADER_FIELDS_TOO_LARGE_431 + : HttpStatus.PAYLOAD_TOO_LARGE_413); } switch (_fieldState) { case FIELD: - switch(t.getType()) + switch (t.getType()) { case COLON: case SPACE: case HTAB: { - if (complianceViolation(HttpComplianceSection.NO_FIELD_FOLDING,_headerString)) - throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Header Folding"); + if (complianceViolation(HttpComplianceSection.NO_FIELD_FOLDING, _headerString)) + throw new BadMessageException(HttpStatus.BAD_REQUEST_400, "Header Folding"); // header value without name - continuation? - if (_valueString==null || _valueString.isEmpty()) + if (StringUtil.isEmpty(_valueString)) { _string.setLength(0); - _length=0; + _length = 0; } else { setString(_valueString); _string.append(' '); _length++; - _valueString=null; + _valueString = null; } setState(FieldState.VALUE); break; @@ -1151,43 +1125,43 @@ public class HttpParser case LF: { // process previous header - if (_state==State.HEADER) + if (_state == State.HEADER) parsedHeader(); else parsedTrailer(); - _contentPosition=0; + _contentPosition = 0; // End of headers or trailers? - if (_state==State.TRAILER) + if (_state == State.TRAILER) { setState(State.END); return _handler.messageComplete(); } - + // Was there a required host header? - if (!_host && _version==HttpVersion.HTTP_1_1 && _requestHandler!=null) + if (!_host && _version == HttpVersion.HTTP_1_1 && _requestHandler != null) { - throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"No Host"); + throw new BadMessageException(HttpStatus.BAD_REQUEST_400, "No Host"); } // is it a response that cannot have a body? - if (_responseHandler !=null && // response - (_responseStatus == 304 || // not-modified response + if (_responseHandler != null && // response + (_responseStatus == 304 || // not-modified response _responseStatus == 204 || // no-content response _responseStatus < 200)) // 1xx response - _endOfContent=EndOfContent.NO_CONTENT; // ignore any other headers set + _endOfContent = EndOfContent.NO_CONTENT; // ignore any other headers set - // else if we don't know framing + // else if we don't know framing else if (_endOfContent == EndOfContent.UNKNOWN_CONTENT) { - if (_responseStatus == 0 // request - || _responseStatus == 304 // not-modified response - || _responseStatus == 204 // no-content response - || _responseStatus < 200) // 1xx response - _endOfContent=EndOfContent.NO_CONTENT; + if (_responseStatus == 0 || // request + _responseStatus == 304 || // not-modified response + _responseStatus == 204 || // no-content response + _responseStatus < 200) // 1xx response + _endOfContent = EndOfContent.NO_CONTENT; else - _endOfContent=EndOfContent.EOF_CONTENT; + _endOfContent = EndOfContent.EOF_CONTENT; } // How is the message ended? @@ -1196,15 +1170,15 @@ public class HttpParser case EOF_CONTENT: { setState(State.EOF_CONTENT); - boolean handle=_handler.headerComplete(); - _headerComplete=true; + boolean handle = _handler.headerComplete(); + _headerComplete = true; return handle; } case CHUNKED_CONTENT: { setState(State.CHUNKED_CONTENT); - boolean handle=_handler.headerComplete(); - _headerComplete=true; + boolean handle = _handler.headerComplete(); + _headerComplete = true; return handle; } case NO_CONTENT: @@ -1215,8 +1189,8 @@ public class HttpParser default: { setState(State.CONTENT); - boolean handle=_handler.headerComplete(); - _headerComplete=true; + boolean handle = _handler.headerComplete(); + _headerComplete = true; return handle; } } @@ -1227,7 +1201,7 @@ public class HttpParser case TCHAR: { // process previous header - if (_state==State.HEADER) + if (_state == State.HEADER) parsedHeader(); else parsedTrailer(); @@ -1236,64 +1210,64 @@ public class HttpParser if (buffer.hasRemaining()) { // Try a look ahead for the known header name and value. - HttpField cached_field=_fieldCache==null?null:_fieldCache.getBest(buffer,-1,buffer.remaining()); - if (cached_field==null) - cached_field=CACHE.getBest(buffer,-1,buffer.remaining()); + HttpField cachedField = _fieldCache == null ? null : _fieldCache.getBest(buffer, -1, buffer.remaining()); + if (cachedField == null) + cachedField = CACHE.getBest(buffer, -1, buffer.remaining()); - if (cached_field!=null) + if (cachedField != null) { - String n = cached_field.getName(); - String v = cached_field.getValue(); + String n = cachedField.getName(); + String v = cachedField.getValue(); if (!_compliances.contains(HttpComplianceSection.FIELD_NAME_CASE_INSENSITIVE)) { // Have to get the fields exactly from the buffer to match case - String en = BufferUtil.toString(buffer,buffer.position()-1,n.length(),StandardCharsets.US_ASCII); + String en = BufferUtil.toString(buffer, buffer.position() - 1, n.length(), StandardCharsets.US_ASCII); if (!n.equals(en)) { - handleViolation(HttpComplianceSection.FIELD_NAME_CASE_INSENSITIVE,en); + handleViolation(HttpComplianceSection.FIELD_NAME_CASE_INSENSITIVE, en); n = en; - cached_field = new HttpField(cached_field.getHeader(),n,v); + cachedField = new HttpField(cachedField.getHeader(), n, v); } } - - if (v!=null && !_compliances.contains(HttpComplianceSection.CASE_INSENSITIVE_FIELD_VALUE_CACHE)) + + if (v != null && !_compliances.contains(HttpComplianceSection.CASE_INSENSITIVE_FIELD_VALUE_CACHE)) { - String ev = BufferUtil.toString(buffer,buffer.position()+n.length()+1,v.length(),StandardCharsets.ISO_8859_1); + String ev = BufferUtil.toString(buffer, buffer.position() + n.length() + 1, v.length(), StandardCharsets.ISO_8859_1); if (!v.equals(ev)) { - handleViolation(HttpComplianceSection.CASE_INSENSITIVE_FIELD_VALUE_CACHE,ev+"!="+v); + handleViolation(HttpComplianceSection.CASE_INSENSITIVE_FIELD_VALUE_CACHE, ev + "!=" + v); v = ev; - cached_field = new HttpField(cached_field.getHeader(),n,v); + cachedField = new HttpField(cachedField.getHeader(), n, v); } } - - _header=cached_field.getHeader(); - _headerString=n; - if (v==null) + _header = cachedField.getHeader(); + _headerString = n; + + if (v == null) { // Header only setState(FieldState.VALUE); _string.setLength(0); - _length=0; - buffer.position(buffer.position()+n.length()+1); + _length = 0; + buffer.position(buffer.position() + n.length() + 1); break; } // Header and value - int pos=buffer.position()+n.length()+v.length()+1; - byte peek=buffer.get(pos); - if (peek==HttpTokens.CARRIAGE_RETURN || peek==HttpTokens.LINE_FEED) + int pos = buffer.position() + n.length() + v.length() + 1; + byte peek = buffer.get(pos); + if (peek == HttpTokens.CARRIAGE_RETURN || peek == HttpTokens.LINE_FEED) { - _field=cached_field; - _valueString=v; + _field = cachedField; + _valueString = v; setState(FieldState.IN_VALUE); - if (peek==HttpTokens.CARRIAGE_RETURN) + if (peek == HttpTokens.CARRIAGE_RETURN) { - _cr=true; - buffer.position(pos+1); + _cr = true; + buffer.position(pos + 1); } else buffer.position(pos); @@ -1310,67 +1284,67 @@ public class HttpParser setState(FieldState.IN_NAME); _string.setLength(0); _string.append(t.getChar()); - _length=1; + _length = 1; + break; } - break; - + default: - throw new IllegalCharacterException(_state,t,buffer); + throw new IllegalCharacterException(_state, t, buffer); } break; case IN_NAME: - switch(t.getType()) + switch (t.getType()) { case SPACE: case HTAB: //Ignore trailing whitespaces ? - if (!complianceViolation(HttpComplianceSection.NO_WS_AFTER_FIELD_NAME,null)) + if (!complianceViolation(HttpComplianceSection.NO_WS_AFTER_FIELD_NAME, null)) { - _headerString=takeString(); - _header=HttpHeader.CACHE.get(_headerString); - _length=-1; + _headerString = takeString(); + _header = HttpHeader.CACHE.get(_headerString); + _length = -1; setState(FieldState.WS_AFTER_NAME); break; } - throw new IllegalCharacterException(_state,t,buffer); - + throw new IllegalCharacterException(_state, t, buffer); + case COLON: - _headerString=takeString(); - _header=HttpHeader.CACHE.get(_headerString); - _length=-1; + _headerString = takeString(); + _header = HttpHeader.CACHE.get(_headerString); + _length = -1; setState(FieldState.VALUE); break; - - case LF: - _headerString=takeString(); - _header=HttpHeader.CACHE.get(_headerString); - _string.setLength(0); - _valueString=""; - _length=-1; - if (!complianceViolation(HttpComplianceSection.FIELD_COLON,_headerString)) - { + case LF: + _headerString = takeString(); + _header = HttpHeader.CACHE.get(_headerString); + _string.setLength(0); + _valueString = ""; + _length = -1; + + if (!complianceViolation(HttpComplianceSection.FIELD_COLON, _headerString)) + { setState(FieldState.FIELD); break; - } - throw new IllegalCharacterException(_state,t,buffer); + } + throw new IllegalCharacterException(_state, t, buffer); case ALPHA: case DIGIT: case TCHAR: _string.append(t.getChar()); - _length=_string.length(); + _length = _string.length(); break; - + default: - throw new IllegalCharacterException(_state,t,buffer); + throw new IllegalCharacterException(_state, t, buffer); } break; case WS_AFTER_NAME: - switch(t.getType()) + switch (t.getType()) { case SPACE: case HTAB: @@ -1378,28 +1352,28 @@ public class HttpParser case COLON: setState(FieldState.VALUE); - break; - + break; + case LF: - if (!complianceViolation(HttpComplianceSection.FIELD_COLON,_headerString)) - { + if (!complianceViolation(HttpComplianceSection.FIELD_COLON, _headerString)) + { setState(FieldState.FIELD); break; - } - throw new IllegalCharacterException(_state,t,buffer); - + } + throw new IllegalCharacterException(_state, t, buffer); + default: - throw new IllegalCharacterException(_state,t,buffer); + throw new IllegalCharacterException(_state, t, buffer); } break; case VALUE: - switch(t.getType()) + switch (t.getType()) { case LF: _string.setLength(0); - _valueString=""; - _length=-1; + _valueString = ""; + _length = -1; setState(FieldState.FIELD); break; @@ -1415,27 +1389,27 @@ public class HttpParser case COLON: case OTEXT: // TODO review? should this be a utf8 string? _string.append(t.getChar()); - _length=_string.length(); + _length = _string.length(); setState(FieldState.IN_VALUE); break; - + default: - throw new IllegalCharacterException(_state,t,buffer); + throw new IllegalCharacterException(_state, t, buffer); } break; - + case IN_VALUE: - switch(t.getType()) + switch (t.getType()) { case LF: if (_length > 0) { - _valueString=takeString(); - _length=-1; + _valueString = takeString(); + _length = -1; } setState(FieldState.FIELD); break; - + case SPACE: case HTAB: _string.append(t.getChar()); @@ -1448,66 +1422,65 @@ public class HttpParser case COLON: case OTEXT: // TODO review? should this be a utf8 string? _string.append(t.getChar()); - _length=_string.length(); + _length = _string.length(); break; default: - throw new IllegalCharacterException(_state,t,buffer); + throw new IllegalCharacterException(_state, t, buffer); } break; - + default: throw new IllegalStateException(_state.toString()); - } } return false; } - /* ------------------------------------------------------------------------------- */ /** * Parse until next Event. + * * @param buffer the buffer to parse * @return True if an {@link RequestHandler} method was called and it returned true; */ public boolean parseNext(ByteBuffer buffer) { - if (DEBUG) - LOG.debug("parseNext s={} {}",_state,BufferUtil.toDetailString(buffer)); + if (debug) + LOG.debug("parseNext s={} {}", _state, BufferUtil.toDetailString(buffer)); try { // Start a request/response - if (_state==State.START) + if (_state == State.START) { - _version=null; - _method=null; - _methodString=null; - _endOfContent=EndOfContent.UNKNOWN_CONTENT; - _header=null; + _version = null; + _method = null; + _methodString = null; + _endOfContent = EndOfContent.UNKNOWN_CONTENT; + _header = null; if (quickStart(buffer)) return true; } // Request/response line - if (_state.ordinal()>= State.START.ordinal() && _state.ordinal()= State.START.ordinal() && _state.ordinal() < State.HEADER.ordinal()) { if (parseLine(buffer)) return true; } // parse headers - if (_state== State.HEADER) + if (_state == State.HEADER) { if (parseFields(buffer)) return true; } // parse content - if (_state.ordinal()>= State.CONTENT.ordinal() && _state.ordinal()= State.CONTENT.ordinal() && _state.ordinal() < State.TRAILER.ordinal()) { // Handle HEAD response - if (_responseStatus>0 && _headResponse) + if (_responseStatus > 0 && _headResponse) { setState(State.END); return handleContentMessage(); @@ -1520,18 +1493,20 @@ public class HttpParser } // parse headers - if (_state==State.TRAILER) + if (_state == State.TRAILER) { if (parseFields(buffer)) return true; } // handle end states - if (_state==State.END) + if (_state == State.END) { // eat white space - while (buffer.remaining()>0 && buffer.get(buffer.position())<=HttpTokens.SPACE) + while (buffer.remaining() > 0 && buffer.get(buffer.position()) <= HttpTokens.SPACE) + { buffer.get(); + } } else if (isClose() || isClosed()) { @@ -1541,7 +1516,7 @@ public class HttpParser // Handle EOF if (_eof && !buffer.hasRemaining()) { - switch(_state) + switch (_state) { case CLOSED: break; @@ -1558,7 +1533,7 @@ public class HttpParser case EOF_CONTENT: case TRAILER: - if (_fieldState==FieldState.FIELD) + if (_fieldState == FieldState.FIELD) { // Be forgiving of missing last CRLF setState(State.CLOSED); @@ -1567,7 +1542,7 @@ public class HttpParser setState(State.CLOSED); _handler.earlyEOF(); break; - + case CONTENT: case CHUNKED_CONTENT: case CHUNK_SIZE: @@ -1578,30 +1553,30 @@ public class HttpParser break; default: - if (DEBUG) - LOG.debug("{} EOF in {}",this,_state); + if (debug) + LOG.debug("{} EOF in {}", this, _state); setState(State.CLOSED); _handler.badMessage(new BadMessageException(HttpStatus.BAD_REQUEST_400)); break; } } } - catch(BadMessageException x) + catch (BadMessageException x) { BufferUtil.clear(buffer); badMessage(x); } - catch(Throwable x) + catch (Throwable x) { BufferUtil.clear(buffer); badMessage(new BadMessageException(HttpStatus.BAD_REQUEST_400, _requestHandler != null ? "Bad Request" : "Bad Response", x)); } return false; } - + protected void badMessage(BadMessageException x) { - if (DEBUG) + if (debug) LOG.debug("Parse exception: " + this + " for " + _handler, x); setState(State.CLOSE); if (_headerComplete) @@ -1612,10 +1587,10 @@ public class HttpParser protected boolean parseContent(ByteBuffer buffer) { - int remaining=buffer.remaining(); - if (remaining==0 && _state==State.CONTENT) + int remaining = buffer.remaining(); + if (remaining == 0 && _state == State.CONTENT) { - long content=_contentLength - _contentPosition; + long content = _contentLength - _contentPosition; if (content == 0) { setState(State.END); @@ -1625,21 +1600,21 @@ public class HttpParser // Handle _content byte ch; - while (_state.ordinal() < State.TRAILER.ordinal() && remaining>0) + while (_state.ordinal() < State.TRAILER.ordinal() && remaining > 0) { switch (_state) { case EOF_CONTENT: - _contentChunk=buffer.asReadOnlyBuffer(); + _contentChunk = buffer.asReadOnlyBuffer(); _contentPosition += remaining; - buffer.position(buffer.position()+remaining); + buffer.position(buffer.position() + remaining); if (_handler.content(_contentChunk)) return true; break; case CONTENT: { - long content=_contentLength - _contentPosition; + long content = _contentLength - _contentPosition; if (content == 0) { setState(State.END); @@ -1647,23 +1622,23 @@ public class HttpParser } else { - _contentChunk=buffer.asReadOnlyBuffer(); + _contentChunk = buffer.asReadOnlyBuffer(); // limit content by expected size if (remaining > content) { // We can cast remaining to an int as we know that it is smaller than // or equal to length which is already an int. - _contentChunk.limit(_contentChunk.position()+(int)content); + _contentChunk.limit(_contentChunk.position() + (int)content); } _contentPosition += _contentChunk.remaining(); - buffer.position(buffer.position()+_contentChunk.remaining()); + buffer.position(buffer.position() + _contentChunk.remaining()); if (_handler.content(_contentChunk)) return true; - if(_contentPosition == _contentLength) + if (_contentPosition == _contentLength) { setState(State.END); return handleContentMessage(); @@ -1675,31 +1650,31 @@ public class HttpParser case CHUNKED_CONTENT: { HttpTokens.Token t = next(buffer); - if (t==null) + if (t == null) break; - switch(t.getType()) + switch (t.getType()) { case LF: break; - + case DIGIT: - _chunkLength=t.getHexDigit(); - _chunkPosition=0; + _chunkLength = t.getHexDigit(); + _chunkPosition = 0; setState(State.CHUNK_SIZE); break; - + case ALPHA: if (t.isHexDigit()) { - _chunkLength=t.getHexDigit(); - _chunkPosition=0; + _chunkLength = t.getHexDigit(); + _chunkPosition = 0; setState(State.CHUNK_SIZE); break; } - throw new IllegalCharacterException(_state,t,buffer); - + throw new IllegalCharacterException(_state, t, buffer); + default: - throw new IllegalCharacterException(_state,t,buffer); + throw new IllegalCharacterException(_state, t, buffer); } break; } @@ -1707,10 +1682,10 @@ public class HttpParser case CHUNK_SIZE: { HttpTokens.Token t = next(buffer); - if (t==null) + if (t == null) break; - - switch(t.getType()) + + switch (t.getType()) { case LF: if (_chunkLength == 0) @@ -1722,17 +1697,17 @@ public class HttpParser else setState(State.CHUNK); break; - + case SPACE: setState(State.CHUNK_PARAMS); break; - + default: if (t.isHexDigit()) { - if (_chunkLength>MAX_CHUNK_LENGTH) + if (_chunkLength > MAX_CHUNK_LENGTH) throw new BadMessageException(HttpStatus.PAYLOAD_TOO_LARGE_413); - _chunkLength=_chunkLength * 16 + t.getHexDigit(); + _chunkLength = _chunkLength * 16 + t.getHexDigit(); } else { @@ -1745,10 +1720,10 @@ public class HttpParser case CHUNK_PARAMS: { HttpTokens.Token t = next(buffer); - if (t==null) + if (t == null) break; - switch(t.getType()) + switch (t.getType()) { case LF: if (_chunkLength == 0) @@ -1768,22 +1743,22 @@ public class HttpParser case CHUNK: { - int chunk=_chunkLength - _chunkPosition; + int chunk = _chunkLength - _chunkPosition; if (chunk == 0) { setState(State.CHUNKED_CONTENT); } else { - _contentChunk=buffer.asReadOnlyBuffer(); + _contentChunk = buffer.asReadOnlyBuffer(); if (remaining > chunk) - _contentChunk.limit(_contentChunk.position()+chunk); - chunk=_contentChunk.remaining(); + _contentChunk.limit(_contentChunk.position() + chunk); + chunk = _contentChunk.remaining(); _contentPosition += chunk; _chunkPosition += chunk; - buffer.position(buffer.position()+chunk); + buffer.position(buffer.position() + chunk); if (_handler.content(_contentChunk)) return true; } @@ -1798,99 +1773,88 @@ public class HttpParser default: break; - } - remaining=buffer.remaining(); + remaining = buffer.remaining(); } return false; } - /* ------------------------------------------------------------------------------- */ public boolean isAtEOF() - { return _eof; } - /* ------------------------------------------------------------------------------- */ - /** Signal that the associated data source is at EOF + /** + * Signal that the associated data source is at EOF */ public void atEOF() { - if (DEBUG) + if (debug) LOG.debug("atEOF {}", this); - _eof=true; + _eof = true; } - /* ------------------------------------------------------------------------------- */ - /** Request that the associated data source be closed + /** + * Request that the associated data source be closed */ public void close() { - if (DEBUG) + if (debug) LOG.debug("close {}", this); setState(State.CLOSE); } - /* ------------------------------------------------------------------------------- */ public void reset() { - if (DEBUG) + if (debug) LOG.debug("reset {}", this); // reset state - if (_state==State.CLOSE || _state==State.CLOSED) + if (_state == State.CLOSE || _state == State.CLOSED) return; setState(State.START); - _endOfContent=EndOfContent.UNKNOWN_CONTENT; - _contentLength=-1; - _hasContentLength=false; - _contentPosition=0; - _responseStatus=0; - _contentChunk=null; - _headerBytes=0; - _host=false; - _headerComplete=false; + _endOfContent = EndOfContent.UNKNOWN_CONTENT; + _contentLength = -1; + _hasContentLength = false; + _contentPosition = 0; + _responseStatus = 0; + _contentChunk = null; + _headerBytes = 0; + _host = false; + _headerComplete = false; } - /* ------------------------------------------------------------------------------- */ protected void setState(State state) { - if (DEBUG) - LOG.debug("{} --> {}",_state,state); - _state=state; + if (debug) + LOG.debug("{} --> {}", _state, state); + _state = state; } - /* ------------------------------------------------------------------------------- */ protected void setState(FieldState state) { - if (DEBUG) - LOG.debug("{}:{} --> {}",_state,_field!=null?_field:_headerString!=null?_headerString:_string,state); - _fieldState=state; + if (debug) + LOG.debug("{}:{} --> {}", _state, _field != null ? _field : _headerString != null ? _headerString : _string, state); + _fieldState = state; } - /* ------------------------------------------------------------------------------- */ public Trie getFieldCache() { return _fieldCache; } - /* ------------------------------------------------------------------------------- */ @Override public String toString() { return String.format("%s{s=%s,%d of %d}", - getClass().getSimpleName(), - _state, - _contentPosition, - _contentLength); + getClass().getSimpleName(), + _state, + _contentPosition, + _contentLength); } - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ /* Event Handler interface * These methods return true if the caller should process the events * so far received (eg return from parseNext and call HttpChannel.handle). @@ -1900,37 +1864,42 @@ public class HttpParser */ public interface HttpHandler { - public boolean content(ByteBuffer item); + boolean content(ByteBuffer item); - public boolean headerComplete(); + boolean headerComplete(); - public boolean contentComplete(); - - public boolean messageComplete(); + boolean contentComplete(); + + boolean messageComplete(); /** - * This is the method called by parser when a HTTP Header name and value is found + * This is the method called by parser when an HTTP Header name and value is found + * * @param field The field parsed */ - public void parsedHeader(HttpField field); - + void parsedHeader(HttpField field); + /** - * This is the method called by parser when a HTTP Trailer name and value is found + * This is the method called by parser when an HTTP Trailer name and value is found + * * @param field The field parsed */ - public default void parsedTrailer(HttpField field) {} + default void parsedTrailer(HttpField field) + { + } - /* ------------------------------------------------------------ */ - /** Called to signal that an EOF was received unexpectedly - * during the parsing of a HTTP message + /** + * Called to signal that an EOF was received unexpectedly + * during the parsing of an HTTP message */ - public void earlyEOF(); + void earlyEOF(); - /* ------------------------------------------------------------ */ - /** Called to signal that a bad HTTP message has been received. + /** + * Called to signal that a bad HTTP message has been received. + * * @param failure the failure with the bad message information */ - public default void badMessage(BadMessageException failure) + default void badMessage(BadMessageException failure) { badMessage(failure.getCode(), failure.getReason()); } @@ -1939,70 +1908,63 @@ public class HttpParser * @deprecated use {@link #badMessage(BadMessageException)} instead */ @Deprecated - public default void badMessage(int status, String reason) + default void badMessage(int status, String reason) { } - /* ------------------------------------------------------------ */ - /** @return the size in bytes of the per parser header cache + /** + * @return the size in bytes of the per parser header cache */ - public int getHeaderCacheSize(); + int getHeaderCacheSize(); } - /* ------------------------------------------------------------------------------- */ - /* ------------------------------------------------------------------------------- */ - /* ------------------------------------------------------------------------------- */ public interface RequestHandler extends HttpHandler { /** * This is the method called by parser when the HTTP request line is parsed + * * @param method The method * @param uri The raw bytes of the URI. These are copied into a ByteBuffer that will not be changed until this parser is reset and reused. * @param version the http version in use * @return true if handling parsing should return. */ - public boolean startRequest(String method, String uri, HttpVersion version); - + boolean startRequest(String method, String uri, HttpVersion version); } - /* ------------------------------------------------------------------------------- */ - /* ------------------------------------------------------------------------------- */ - /* ------------------------------------------------------------------------------- */ public interface ResponseHandler extends HttpHandler { /** * This is the method called by parser when the HTTP request line is parsed + * * @param version the http version in use * @param status the response status * @param reason the response reason phrase * @return true if handling parsing should return */ - public boolean startResponse(HttpVersion version, int status, String reason); + boolean startResponse(HttpVersion version, int status, String reason); } - /* ------------------------------------------------------------------------------- */ - /* ------------------------------------------------------------------------------- */ - /* ------------------------------------------------------------------------------- */ public interface ComplianceHandler extends HttpHandler { @Deprecated - public default void onComplianceViolation(HttpCompliance compliance, HttpCompliance required, String reason) {} - - public default void onComplianceViolation(HttpCompliance compliance, HttpComplianceSection violation, String details) + default void onComplianceViolation(HttpCompliance compliance, HttpCompliance required, String reason) { - onComplianceViolation(compliance,HttpCompliance.requiredCompliance(violation), details); + } + + default void onComplianceViolation(HttpCompliance compliance, HttpComplianceSection violation, String details) + { + onComplianceViolation(compliance, HttpCompliance.requiredCompliance(violation), details); } } - /* ------------------------------------------------------------------------------- */ @SuppressWarnings("serial") private static class IllegalCharacterException extends BadMessageException { - private IllegalCharacterException(State state,HttpTokens.Token token,ByteBuffer buffer) + private IllegalCharacterException(State state, HttpTokens.Token token, ByteBuffer buffer) { - super(400,String.format("Illegal character %s",token)); + super(400, String.format("Illegal character %s", token)); if (LOG.isDebugEnabled()) - LOG.debug(String.format("Illegal character %s in state=%s for buffer %s",token,state,BufferUtil.toDetailString(buffer))); + LOG.debug(String.format("Illegal character %s in state=%s for buffer %s", token, state, BufferUtil.toDetailString(buffer))); } } } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpScheme.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpScheme.java index 341c0249cc6..9340fb6f974 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpScheme.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpScheme.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -24,8 +24,8 @@ import org.eclipse.jetty.util.ArrayTrie; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Trie; -/* ------------------------------------------------------------------------------- */ /** + * */ public enum HttpScheme { @@ -34,34 +34,33 @@ public enum HttpScheme WS("ws"), WSS("wss"); - /* ------------------------------------------------------------ */ - public final static Trie CACHE= new ArrayTrie(); + public static final Trie CACHE = new ArrayTrie(); + static { for (HttpScheme version : HttpScheme.values()) - CACHE.put(version.asString(),version); + { + CACHE.put(version.asString(), version); + } } private final String _string; private final ByteBuffer _buffer; - /* ------------------------------------------------------------ */ HttpScheme(String s) { - _string=s; - _buffer=BufferUtil.toBuffer(s); + _string = s; + _buffer = BufferUtil.toBuffer(s); } - /* ------------------------------------------------------------ */ public ByteBuffer asByteBuffer() { return _buffer.asReadOnlyBuffer(); } - /* ------------------------------------------------------------ */ public boolean is(String s) { - return s!=null && _string.equalsIgnoreCase(s); + return s != null && _string.equalsIgnoreCase(s); } public String asString() @@ -69,11 +68,9 @@ public enum HttpScheme return _string; } - /* ------------------------------------------------------------ */ @Override public String toString() { return _string; } - } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpStatus.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpStatus.java index 505b5174efa..20e6f8cf431 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpStatus.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpStatus.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -22,83 +22,84 @@ package org.eclipse.jetty.http; *

      * Http Status Codes *

      + * * @see IANA HTTP Status Code Registry */ public class HttpStatus { - public final static int CONTINUE_100 = 100; - public final static int SWITCHING_PROTOCOLS_101 = 101; - public final static int PROCESSING_102 = 102; + public static final int CONTINUE_100 = 100; + public static final int SWITCHING_PROTOCOLS_101 = 101; + public static final int PROCESSING_102 = 102; - public final static int OK_200 = 200; - public final static int CREATED_201 = 201; - public final static int ACCEPTED_202 = 202; - public final static int NON_AUTHORITATIVE_INFORMATION_203 = 203; - public final static int NO_CONTENT_204 = 204; - public final static int RESET_CONTENT_205 = 205; - public final static int PARTIAL_CONTENT_206 = 206; - public final static int MULTI_STATUS_207 = 207; + public static final int OK_200 = 200; + public static final int CREATED_201 = 201; + public static final int ACCEPTED_202 = 202; + public static final int NON_AUTHORITATIVE_INFORMATION_203 = 203; + public static final int NO_CONTENT_204 = 204; + public static final int RESET_CONTENT_205 = 205; + public static final int PARTIAL_CONTENT_206 = 206; + public static final int MULTI_STATUS_207 = 207; - public final static int MULTIPLE_CHOICES_300 = 300; - public final static int MOVED_PERMANENTLY_301 = 301; - public final static int MOVED_TEMPORARILY_302 = 302; - public final static int FOUND_302 = 302; - public final static int SEE_OTHER_303 = 303; - public final static int NOT_MODIFIED_304 = 304; - public final static int USE_PROXY_305 = 305; - public final static int TEMPORARY_REDIRECT_307 = 307; - public final static int PERMANENT_REDIRECT_308 = 308; + public static final int MULTIPLE_CHOICES_300 = 300; + public static final int MOVED_PERMANENTLY_301 = 301; + public static final int MOVED_TEMPORARILY_302 = 302; + public static final int FOUND_302 = 302; + public static final int SEE_OTHER_303 = 303; + public static final int NOT_MODIFIED_304 = 304; + public static final int USE_PROXY_305 = 305; + public static final int TEMPORARY_REDIRECT_307 = 307; + public static final int PERMANENT_REDIRECT_308 = 308; - public final static int BAD_REQUEST_400 = 400; - public final static int UNAUTHORIZED_401 = 401; - public final static int PAYMENT_REQUIRED_402 = 402; - public final static int FORBIDDEN_403 = 403; - public final static int NOT_FOUND_404 = 404; - public final static int METHOD_NOT_ALLOWED_405 = 405; - public final static int NOT_ACCEPTABLE_406 = 406; - public final static int PROXY_AUTHENTICATION_REQUIRED_407 = 407; - public final static int REQUEST_TIMEOUT_408 = 408; - public final static int CONFLICT_409 = 409; - public final static int GONE_410 = 410; - public final static int LENGTH_REQUIRED_411 = 411; - public final static int PRECONDITION_FAILED_412 = 412; + public static final int BAD_REQUEST_400 = 400; + public static final int UNAUTHORIZED_401 = 401; + public static final int PAYMENT_REQUIRED_402 = 402; + public static final int FORBIDDEN_403 = 403; + public static final int NOT_FOUND_404 = 404; + public static final int METHOD_NOT_ALLOWED_405 = 405; + public static final int NOT_ACCEPTABLE_406 = 406; + public static final int PROXY_AUTHENTICATION_REQUIRED_407 = 407; + public static final int REQUEST_TIMEOUT_408 = 408; + public static final int CONFLICT_409 = 409; + public static final int GONE_410 = 410; + public static final int LENGTH_REQUIRED_411 = 411; + public static final int PRECONDITION_FAILED_412 = 412; @Deprecated - public final static int REQUEST_ENTITY_TOO_LARGE_413 = 413; - public final static int PAYLOAD_TOO_LARGE_413 = 413; + public static final int REQUEST_ENTITY_TOO_LARGE_413 = 413; + public static final int PAYLOAD_TOO_LARGE_413 = 413; @Deprecated - public final static int REQUEST_URI_TOO_LONG_414 = 414; - public final static int URI_TOO_LONG_414 = 414; - public final static int UNSUPPORTED_MEDIA_TYPE_415 = 415; + public static final int REQUEST_URI_TOO_LONG_414 = 414; + public static final int URI_TOO_LONG_414 = 414; + public static final int UNSUPPORTED_MEDIA_TYPE_415 = 415; @Deprecated - public final static int REQUESTED_RANGE_NOT_SATISFIABLE_416 = 416; - public final static int RANGE_NOT_SATISFIABLE_416 = 416; - public final static int EXPECTATION_FAILED_417 = 417; - public final static int IM_A_TEAPOT_418 = 418; - public final static int ENHANCE_YOUR_CALM_420 = 420; - public final static int MISDIRECTED_REQUEST_421 = 421; - public final static int UNPROCESSABLE_ENTITY_422 = 422; - public final static int LOCKED_423 = 423; - public final static int FAILED_DEPENDENCY_424 = 424; - public final static int UPGRADE_REQUIRED_426 = 426; - public final static int PRECONDITION_REQUIRED_428 = 428; - public final static int TOO_MANY_REQUESTS_429 = 429; - public final static int REQUEST_HEADER_FIELDS_TOO_LARGE_431 = 431; - public final static int UNAVAILABLE_FOR_LEGAL_REASONS_451 = 451; + public static final int REQUESTED_RANGE_NOT_SATISFIABLE_416 = 416; + public static final int RANGE_NOT_SATISFIABLE_416 = 416; + public static final int EXPECTATION_FAILED_417 = 417; + public static final int IM_A_TEAPOT_418 = 418; + public static final int ENHANCE_YOUR_CALM_420 = 420; + public static final int MISDIRECTED_REQUEST_421 = 421; + public static final int UNPROCESSABLE_ENTITY_422 = 422; + public static final int LOCKED_423 = 423; + public static final int FAILED_DEPENDENCY_424 = 424; + public static final int UPGRADE_REQUIRED_426 = 426; + public static final int PRECONDITION_REQUIRED_428 = 428; + public static final int TOO_MANY_REQUESTS_429 = 429; + public static final int REQUEST_HEADER_FIELDS_TOO_LARGE_431 = 431; + public static final int UNAVAILABLE_FOR_LEGAL_REASONS_451 = 451; + + public static final int INTERNAL_SERVER_ERROR_500 = 500; + public static final int NOT_IMPLEMENTED_501 = 501; + public static final int BAD_GATEWAY_502 = 502; + public static final int SERVICE_UNAVAILABLE_503 = 503; + public static final int GATEWAY_TIMEOUT_504 = 504; + public static final int HTTP_VERSION_NOT_SUPPORTED_505 = 505; + public static final int INSUFFICIENT_STORAGE_507 = 507; + public static final int LOOP_DETECTED_508 = 508; + public static final int NOT_EXTENDED_510 = 510; + public static final int NETWORK_AUTHENTICATION_REQUIRED_511 = 511; - public final static int INTERNAL_SERVER_ERROR_500 = 500; - public final static int NOT_IMPLEMENTED_501 = 501; - public final static int BAD_GATEWAY_502 = 502; - public final static int SERVICE_UNAVAILABLE_503 = 503; - public final static int GATEWAY_TIMEOUT_504 = 504; - public final static int HTTP_VERSION_NOT_SUPPORTED_505 = 505; - public final static int INSUFFICIENT_STORAGE_507 = 507; - public final static int LOOP_DETECTED_508 = 508; - public final static int NOT_EXTENDED_510 = 510; - public final static int NETWORK_AUTHENTICATION_REQUIRED_511 = 511; - public static final int MAX_CODE = 511; - private static final Code[] codeMap = new Code[MAX_CODE+1]; + private static final Code[] codeMap = new Code[MAX_CODE + 1]; static { @@ -108,14 +109,12 @@ public class HttpStatus } } - public enum Code { CONTINUE(CONTINUE_100, "Continue"), SWITCHING_PROTOCOLS(SWITCHING_PROTOCOLS_101, "Switching Protocols"), PROCESSING(PROCESSING_102, "Processing"), - OK(OK_200, "OK"), CREATED(CREATED_201, "Created"), ACCEPTED(ACCEPTED_202, "Accepted"), @@ -177,16 +176,16 @@ public class HttpStatus LOOP_DETECTED(LOOP_DETECTED_508, "Loop Detected"), NOT_EXTENDED(NOT_EXTENDED_510, "Not Extended"), NETWORK_AUTHENTICATION_REQUIRED(NETWORK_AUTHENTICATION_REQUIRED_511, "Network Authentication Required"), - + ; - + private final int _code; private final String _message; - private Code(int code, String message) + Code(int code, String message) { this._code = code; - _message=message; + _message = message; } public int getCode() @@ -199,7 +198,6 @@ public class HttpStatus return _message; } - public boolean equals(int code) { return (this._code == code); @@ -208,7 +206,7 @@ public class HttpStatus @Override public String toString() { - return String.format("[%03d %s]",this._code,this.getMessage()); + return String.format("[%03d %s]", this._code, this.getMessage()); } /** @@ -219,7 +217,7 @@ public class HttpStatus * HTTP/1.1. * * @return true if within range of codes that belongs to - * Informational messages. + * Informational messages. */ public boolean isInformational() { @@ -234,7 +232,7 @@ public class HttpStatus * HTTP/1.1. * * @return true if within range of codes that belongs to - * Success messages. + * Success messages. */ public boolean isSuccess() { @@ -249,7 +247,7 @@ public class HttpStatus * HTTP/1.1. * * @return true if within range of codes that belongs to - * Redirection messages. + * Redirection messages. */ public boolean isRedirection() { @@ -264,7 +262,7 @@ public class HttpStatus * HTTP/1.1. * * @return true if within range of codes that belongs to - * Client Error messages. + * Client Error messages. */ public boolean isClientError() { @@ -279,7 +277,7 @@ public class HttpStatus * HTTP/1.1. * * @return true if within range of codes that belongs to - * Server Error messages. + * Server Error messages. */ public boolean isServerError() { @@ -287,12 +285,10 @@ public class HttpStatus } } - /** * Get the HttpStatusCode for a specific code * - * @param code - * the code to lookup. + * @param code the code to lookup. * @return the {@link HttpStatus} if found, or null if not found. */ public static Code getCode(int code) @@ -307,10 +303,9 @@ public class HttpStatus /** * Get the status message for a specific code. * - * @param code - * the code to look up + * @param code the code to look up * @return the specific message, or the code number itself if code - * does not match known list. + * does not match known list. */ public static String getMessage(int code) { @@ -325,16 +320,29 @@ public class HttpStatus } } + public static boolean hasNoBody(int status) + { + switch (status) + { + case NO_CONTENT_204: + case NOT_MODIFIED_304: + case PARTIAL_CONTENT_206: + return true; + + default: + return status < OK_200; + } + } + /** * Simple test against an code to determine if it falls into the * Informational message category as defined in the RFC 1945 - HTTP/1.0, and RFC 7231 - HTTP/1.1. * - * @param code - * the code to test. + * @param code the code to test. * @return true if within range of codes that belongs to - * Informational messages. + * Informational messages. */ public static boolean isInformational(int code) { @@ -347,10 +355,9 @@ public class HttpStatus * href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0, and RFC 7231 - HTTP/1.1. * - * @param code - * the code to test. + * @param code the code to test. * @return true if within range of codes that belongs to - * Success messages. + * Success messages. */ public static boolean isSuccess(int code) { @@ -363,10 +370,9 @@ public class HttpStatus * href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0, and RFC 7231 - HTTP/1.1. * - * @param code - * the code to test. + * @param code the code to test. * @return true if within range of codes that belongs to - * Redirection messages. + * Redirection messages. */ public static boolean isRedirection(int code) { @@ -379,10 +385,9 @@ public class HttpStatus * href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0, and RFC 7231 - HTTP/1.1. * - * @param code - * the code to test. + * @param code the code to test. * @return true if within range of codes that belongs to - * Client Error messages. + * Client Error messages. */ public static boolean isClientError(int code) { @@ -395,10 +400,9 @@ public class HttpStatus * href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0, and RFC 7231 - HTTP/1.1. * - * @param code - * the code to test. + * @param code the code to test. * @return true if within range of codes that belongs to - * Server Error messages. + * Server Error messages. */ public static boolean isServerError(int code) { diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTokens.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTokens.java index 818eb1f3426..61cdadd6193 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTokens.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTokens.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -25,18 +25,20 @@ import org.eclipse.jetty.util.TypeUtil; */ public class HttpTokens { - static final byte COLON= (byte)':'; - static final byte TAB= 0x09; - static final byte LINE_FEED= 0x0A; - static final byte CARRIAGE_RETURN= 0x0D; - static final byte SPACE= 0x20; - static final byte[] CRLF = {CARRIAGE_RETURN,LINE_FEED}; + static final byte COLON = (byte)':'; + static final byte TAB = 0x09; + static final byte LINE_FEED = 0x0A; + static final byte CARRIAGE_RETURN = 0x0D; + static final byte SPACE = 0x20; + static final byte[] CRLF = {CARRIAGE_RETURN, LINE_FEED}; - public enum EndOfContent { UNKNOWN_CONTENT,NO_CONTENT,EOF_CONTENT,CONTENT_LENGTH,CHUNKED_CONTENT } + public enum EndOfContent + { + UNKNOWN_CONTENT, NO_CONTENT, EOF_CONTENT, CONTENT_LENGTH, CHUNKED_CONTENT + } - - public enum Type - { + public enum Type + { CNTL, // Control characters excluding LF, CR HTAB, // Horizontal tab LF, // Line feed @@ -49,21 +51,21 @@ public class HttpTokens VCHAR, // Visible characters excluding COLON,DIGIT,ALPHA OTEXT // Obsolete text } - + public static class Token { private final Type _type; private final byte _b; private final char _c; private final int _x; - + private Token(byte b, Type type) { _type = type; _b = b; - _c = (char)(0xff&b); - char lc = (_c>='A' & _c<='Z')?((char)(_c-'A'+'a')):_c; - _x = (_type==Type.DIGIT || _type==Type.ALPHA && lc>='a' && lc<='f')?TypeUtil.convertHexDigit(b):-1; + _c = (char)(0xff & b); + char lc = (_c >= 'A' & _c <= 'Z') ? ((char)(_c - 'A' + 'a')) : _c; + _x = (_type == Type.DIGIT || _type == Type.ALPHA && lc >= 'a' && lc <= 'f') ? TypeUtil.convertHexDigit(b) : -1; } public Type getType() @@ -80,21 +82,21 @@ public class HttpTokens { return _c; } - + public boolean isHexDigit() { - return _x>=0; + return _x >= 0; } - + public int getHexDigit() { return _x; } - + @Override public String toString() { - switch(_type) + switch (_type) { case SPACE: case COLON: @@ -102,26 +104,25 @@ public class HttpTokens case DIGIT: case TCHAR: case VCHAR: - return _type+"='"+_c+"'"; - + return _type + "='" + _c + "'"; + case CR: return "CR=\\r"; - + case LF: return "LF=\\n"; - + default: - return String.format("%s=0x%x",_type,_b); + return String.format("%s=0x%x", _type, _b); } } - } - - public final static Token[] TOKENS = new Token[256]; + + public static final Token[] TOKENS = new Token[256]; static { - for (int b=0; b<256; b++) + for (int b = 0; b < 256; b++) { // token = 1*tchar // tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" @@ -134,56 +135,56 @@ public class HttpTokens // comment = "(" *( ctext / quoted-pair / comment ) ")" // ctext = HTAB / SP / %x21-27 / %x2A-5B / %x5D-7E / obs-text // quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text ) - + switch (b) { - case LINE_FEED: - TOKENS[b] = new Token((byte)b,Type.LF); + case LINE_FEED: + TOKENS[b] = new Token((byte)b, Type.LF); break; - case CARRIAGE_RETURN: - TOKENS[b] = new Token((byte)b,Type.CR); + case CARRIAGE_RETURN: + TOKENS[b] = new Token((byte)b, Type.CR); break; - case SPACE: - TOKENS[b] = new Token((byte)b,Type.SPACE); + case SPACE: + TOKENS[b] = new Token((byte)b, Type.SPACE); break; - case TAB: - TOKENS[b] = new Token((byte)b,Type.HTAB); + case TAB: + TOKENS[b] = new Token((byte)b, Type.HTAB); break; - case COLON: - TOKENS[b] = new Token((byte)b,Type.COLON); + case COLON: + TOKENS[b] = new Token((byte)b, Type.COLON); break; - - case '!': - case '#': - case '$': - case '%': - case '&': - case '\'': - case '*': - case '+': - case '-': - case '.': - case '^': - case '_': - case '`': - case '|': - case '~': - TOKENS[b] = new Token((byte)b,Type.TCHAR); + + case '!': + case '#': + case '$': + case '%': + case '&': + case '\'': + case '*': + case '+': + case '-': + case '.': + case '^': + case '_': + case '`': + case '|': + case '~': + TOKENS[b] = new Token((byte)b, Type.TCHAR); break; - + default: - if (b>=0x30 &&b<=0x39) // DIGIT - TOKENS[b] = new Token((byte)b,Type.DIGIT); - else if (b>=0x41 &&b<=0x5A) // ALPHA (uppercase) - TOKENS[b] = new Token((byte)b,Type.ALPHA); - else if (b>=0x61 &&b<=0x7A) // ALPHA (lowercase) - TOKENS[b] = new Token((byte)b,Type.ALPHA); - else if (b>=0x21 &&b<=0x7E) // Visible - TOKENS[b] = new Token((byte)b,Type.VCHAR); - else if (b>=0x80) // OBS - TOKENS[b] = new Token((byte)b,Type.OTEXT); + if (b >= 0x30 && b <= 0x39) // DIGIT + TOKENS[b] = new Token((byte)b, Type.DIGIT); + else if (b >= 0x41 && b <= 0x5A) // ALPHA (uppercase) + TOKENS[b] = new Token((byte)b, Type.ALPHA); + else if (b >= 0x61 && b <= 0x7A) // ALPHA (lowercase) + TOKENS[b] = new Token((byte)b, Type.ALPHA); + else if (b >= 0x21 && b <= 0x7E) // Visible + TOKENS[b] = new Token((byte)b, Type.VCHAR); + else if (b >= 0x80) // OBS + TOKENS[b] = new Token((byte)b, Type.OTEXT); else - TOKENS[b] = new Token((byte)b,Type.CNTL); + TOKENS[b] = new Token((byte)b, Type.CNTL); } } } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java index af3e12e678e..4fb2a36989e 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -29,10 +29,9 @@ import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.UrlEncoded; - -/* ------------------------------------------------------------ */ -/** Http URI. - * Parse a HTTP URI from a string or byte array. Given a URI +/** + * Http URI. + * Parse an HTTP URI from a string or byte array. Given a URI * http://user@host:port/path/info;param?query#fragment * this class will split it into the following undecoded optional elements:
        *
      • {@link #getScheme()} - http:
      • @@ -44,25 +43,27 @@ import org.eclipse.jetty.util.UrlEncoded; *
      • {@link #getQuery()} - query
      • *
      • {@link #getFragment()} - fragment
      • *
      - * + * *

      Any parameters will be returned from {@link #getPath()}, but are excluded from the - * return value of {@link #getDecodedPath()}. If there are multiple parameters, the + * return value of {@link #getDecodedPath()}. If there are multiple parameters, the * {@link #getParam()} method returns only the last one. */ public class HttpURI { - private enum State { - START, - HOST_OR_PATH, - SCHEME_OR_PATH, - HOST, - IPV6, - PORT, - PATH, - PARAM, - QUERY, - FRAGMENT, - ASTERISK}; + private enum State + { + START, + HOST_OR_PATH, + SCHEME_OR_PATH, + HOST, + IPV6, + PORT, + PATH, + PARAM, + QUERY, + FRAGMENT, + ASTERISK + } private String _scheme; private String _user; @@ -72,14 +73,14 @@ public class HttpURI private String _param; private String _query; private String _fragment; - + String _uri; String _decodedPath; - /* ------------------------------------------------------------ */ /** * Construct a normalized URI. * Port is not set if it is the default port. + * * @param scheme the URI scheme * @param host the URI hose * @param port the URI port @@ -91,19 +92,17 @@ public class HttpURI */ public static HttpURI createHttpURI(String scheme, String host, int port, String path, String param, String query, String fragment) { - if (port==80 && HttpScheme.HTTP.is(scheme)) - port=0; - if (port==443 && HttpScheme.HTTPS.is(scheme)) - port=0; - return new HttpURI(scheme,host,port,path,param,query,fragment); + if (port == 80 && HttpScheme.HTTP.is(scheme)) + port = 0; + if (port == 443 && HttpScheme.HTTPS.is(scheme)) + port = 0; + return new HttpURI(scheme, host, port, path, param, query, fragment); } - - /* ------------------------------------------------------------ */ + public HttpURI() { } - /* ------------------------------------------------------------ */ public HttpURI(String scheme, String host, int port, String path, String param, String query, String fragment) { _scheme = scheme; @@ -115,33 +114,30 @@ public class HttpURI _fragment = fragment; } - /* ------------------------------------------------------------ */ public HttpURI(HttpURI uri) { - this(uri._scheme,uri._host,uri._port,uri._path,uri._param,uri._query,uri._fragment); - _uri=uri._uri; - } - - /* ------------------------------------------------------------ */ - public HttpURI(String uri) - { - _port=-1; - parse(State.START,uri,0,uri.length()); + this(uri._scheme, uri._host, uri._port, uri._path, uri._param, uri._query, uri._fragment); + _uri = uri._uri; + } + + public HttpURI(String uri) + { + _port = -1; + parse(State.START, uri, 0, uri.length()); } - /* ------------------------------------------------------------ */ public HttpURI(URI uri) { - _uri=null; - - _scheme=uri.getScheme(); - _host=uri.getHost(); - if (_host==null && uri.getRawSchemeSpecificPart().startsWith("//")) - _host=""; - _port=uri.getPort(); + _uri = null; + + _scheme = uri.getScheme(); + _host = uri.getHost(); + if (_host == null && uri.getRawSchemeSpecificPart().startsWith("//")) + _host = ""; + _port = uri.getPort(); _user = uri.getUserInfo(); - _path=uri.getRawPath(); - + _path = uri.getRawPath(); + _decodedPath = uri.getPath(); if (_decodedPath != null) { @@ -149,117 +145,111 @@ public class HttpURI if (p >= 0) _param = _decodedPath.substring(p + 1); } - _query=uri.getRawQuery(); - _fragment=uri.getFragment(); - - _decodedPath=null; + _query = uri.getRawQuery(); + _fragment = uri.getFragment(); + + _decodedPath = null; } - /* ------------------------------------------------------------ */ public HttpURI(String scheme, String host, int port, String pathQuery) { - _uri=null; - - _scheme=scheme; - _host=host; - _port=port; + _uri = null; - if (pathQuery!=null) - parse(State.PATH,pathQuery,0,pathQuery.length()); - + _scheme = scheme; + _host = host; + _port = port; + + if (pathQuery != null) + parse(State.PATH, pathQuery, 0, pathQuery.length()); } - /* ------------------------------------------------------------ */ public void parse(String uri) { clear(); - _uri=uri; - parse(State.START,uri,0,uri.length()); + _uri = uri; + parse(State.START, uri, 0, uri.length()); } - /* ------------------------------------------------------------ */ /** * Parse according to https://tools.ietf.org/html/rfc7230#section-5.3 + * * @param method the request method * @param uri the request uri */ - public void parseRequestTarget(String method,String uri) + public void parseRequestTarget(String method, String uri) { clear(); - _uri=uri; + _uri = uri; if (HttpMethod.CONNECT.is(method)) - _path=uri; + _path = uri; else - parse(uri.startsWith("/")?State.PATH:State.START,uri,0,uri.length()); + parse(uri.startsWith("/") ? State.PATH : State.START, uri, 0, uri.length()); } - /* ------------------------------------------------------------ */ @Deprecated public void parseConnect(String uri) { clear(); - _uri=uri; - _path=uri; + _uri = uri; + _path = uri; } - /* ------------------------------------------------------------ */ public void parse(String uri, int offset, int length) { clear(); - int end=offset+length; - _uri=uri.substring(offset,end); - parse(State.START,uri,offset,end); + int end = offset + length; + _uri = uri.substring(offset, end); + parse(State.START, uri, offset, end); } - /* ------------------------------------------------------------ */ private void parse(State state, final String uri, final int offset, final int end) { - boolean encoded=false; - int mark=offset; - int path_mark=0; - - for (int i=offset; i mark) - _host=uri.substring(mark,i); - mark=i+1; - state=State.PORT; + _host = uri.substring(mark, i); + mark = i + 1; + state = State.PORT; break; case '@': - if (_user!=null) + if (_user != null) throw new IllegalArgumentException("Bad authority"); - _user=uri.substring(mark,i); - mark=i+1; + _user = uri.substring(mark, i); + mark = i + 1; break; - + case '[': - state=State.IPV6; + state = State.IPV6; break; } continue; @@ -374,16 +364,16 @@ public class HttpURI throw new IllegalArgumentException("No closing ']' for ipv6 in " + uri); case ']': c = uri.charAt(++i); - _host=uri.substring(mark,i); + _host = uri.substring(mark, i); if (c == ':') { - mark=i+1; - state=State.PORT; + mark = i + 1; + state = State.PORT; } else { - path_mark=mark=i; - state=State.PATH; + pathMark = mark = i; + state = State.PATH; } break; } @@ -393,20 +383,20 @@ public class HttpURI case PORT: { - if (c=='@') + if (c == '@') { - if (_user!=null) + if (_user != null) throw new IllegalArgumentException("Bad authority"); // It wasn't a port, but a password! - _user=_host+":"+uri.substring(mark,i); - mark=i+1; - state=State.HOST; + _user = _host + ":" + uri.substring(mark, i); + mark = i + 1; + state = State.HOST; } - else if (c=='/') + else if (c == '/') { - _port=TypeUtil.parseInt(uri,mark,i-mark,10); - path_mark=mark=i; - state=State.PATH; + _port = TypeUtil.parseInt(uri, mark, i - mark, 10); + pathMark = mark = i; + state = State.PATH; } continue; } @@ -416,21 +406,21 @@ public class HttpURI switch (c) { case ';': - mark=i+1; - state=State.PARAM; + mark = i + 1; + state = State.PARAM; break; case '?': - _path=uri.substring(path_mark,i); - mark=i+1; - state=State.QUERY; + _path = uri.substring(pathMark, i); + mark = i + 1; + state = State.QUERY; break; case '#': - _path=uri.substring(path_mark,i); - mark=i+1; - state=State.FRAGMENT; + _path = uri.substring(pathMark, i); + mark = i + 1; + state = State.FRAGMENT; break; case '%': - encoded=true; + encoded = true; break; } continue; @@ -441,25 +431,25 @@ public class HttpURI switch (c) { case '?': - _path=uri.substring(path_mark,i); - _param=uri.substring(mark,i); - mark=i+1; - state=State.QUERY; + _path = uri.substring(pathMark, i); + _param = uri.substring(mark, i); + mark = i + 1; + state = State.QUERY; break; case '#': - _path=uri.substring(path_mark,i); - _param=uri.substring(mark,i); - mark=i+1; - state=State.FRAGMENT; + _path = uri.substring(pathMark, i); + _param = uri.substring(mark, i); + mark = i + 1; + state = State.FRAGMENT; break; case '/': - encoded=true; + encoded = true; // ignore internal params - state=State.PATH; + state = State.PATH; break; case ';': // multiple parameters - mark=i+1; + mark = i + 1; break; } continue; @@ -467,11 +457,11 @@ public class HttpURI case QUERY: { - if (c=='#') + if (c == '#') { - _query=uri.substring(mark,i); - mark=i+1; - state=State.FRAGMENT; + _query = uri.substring(mark, i); + mark = i + 1; + state = State.FRAGMENT; } continue; } @@ -480,95 +470,90 @@ public class HttpURI { throw new IllegalArgumentException("Bad character '*'"); } - + case FRAGMENT: { - _fragment=uri.substring(mark,end); - i=end; + _fragment = uri.substring(mark, end); + i = end; } } } - - switch(state) + switch (state) { case START: break; case SCHEME_OR_PATH: - _path=uri.substring(mark,end); + _path = uri.substring(mark, end); break; case HOST_OR_PATH: - _path=uri.substring(mark,end); + _path = uri.substring(mark, end); break; - + case HOST: - if(end>mark) - _host=uri.substring(mark,end); + if (end > mark) + _host = uri.substring(mark, end); break; - + case IPV6: throw new IllegalArgumentException("No closing ']' for ipv6 in " + uri); case PORT: - _port=TypeUtil.parseInt(uri,mark,end-mark,10); + _port = TypeUtil.parseInt(uri, mark, end - mark, 10); break; - + case ASTERISK: break; - + case FRAGMENT: - _fragment=uri.substring(mark,end); + _fragment = uri.substring(mark, end); break; - + case PARAM: - _path=uri.substring(path_mark,end); - _param=uri.substring(mark,end); + _path = uri.substring(pathMark, end); + _param = uri.substring(mark, end); break; - + case PATH: - _path=uri.substring(path_mark,end); + _path = uri.substring(pathMark, end); break; - + case QUERY: - _query=uri.substring(mark,end); + _query = uri.substring(mark, end); break; } - + if (!encoded) { - if (_param==null) - _decodedPath=_path; + if (_param == null) + _decodedPath = _path; else - _decodedPath=_path.substring(0,_path.length()-_param.length()-1); + _decodedPath = _path.substring(0, _path.length() - _param.length() - 1); } } - /* ------------------------------------------------------------ */ public String getScheme() { return _scheme; } - /* ------------------------------------------------------------ */ public String getHost() { // Return null for empty host to retain compatibility with java.net.URI - if (_host!=null && _host.length()==0) + if (_host != null && _host.isEmpty()) return null; return _host; } - /* ------------------------------------------------------------ */ public int getPort() { return _port; } - /* ------------------------------------------------------------ */ /** * The parsed Path. - * + * * @return the path as parsed on valid URI. null for invalid URI. */ public String getPath() @@ -576,97 +561,86 @@ public class HttpURI return _path; } - /* ------------------------------------------------------------ */ public String getDecodedPath() { - if (_decodedPath==null && _path!=null) - _decodedPath=URIUtil.decodePath(_path); + if (_decodedPath == null && _path != null) + _decodedPath = URIUtil.decodePath(_path); return _decodedPath; } - /* ------------------------------------------------------------ */ public String getParam() { return _param; } - /* ------------------------------------------------------------ */ public String getQuery() { return _query; } - /* ------------------------------------------------------------ */ public boolean hasQuery() { - return _query!=null && _query.length()>0; + return _query != null && !_query.isEmpty(); } - /* ------------------------------------------------------------ */ public String getFragment() { return _fragment; } - /* ------------------------------------------------------------ */ public void decodeQueryTo(MultiMap parameters) { - if (_query==null) + if (_query == null) return; - UrlEncoded.decodeUtf8To(_query,parameters); + UrlEncoded.decodeUtf8To(_query, parameters); } - /* ------------------------------------------------------------ */ public void decodeQueryTo(MultiMap parameters, String encoding) throws UnsupportedEncodingException { - decodeQueryTo(parameters,Charset.forName(encoding)); + decodeQueryTo(parameters, Charset.forName(encoding)); } - /* ------------------------------------------------------------ */ public void decodeQueryTo(MultiMap parameters, Charset encoding) throws UnsupportedEncodingException { - if (_query==null) + if (_query == null) return; - if (encoding==null || StandardCharsets.UTF_8.equals(encoding)) - UrlEncoded.decodeUtf8To(_query,parameters); + if (encoding == null || StandardCharsets.UTF_8.equals(encoding)) + UrlEncoded.decodeUtf8To(_query, parameters); else - UrlEncoded.decodeTo(_query,parameters,encoding); + UrlEncoded.decodeTo(_query, parameters, encoding); } - /* ------------------------------------------------------------ */ public void clear() { - _uri=null; + _uri = null; - _scheme=null; - _host=null; - _port=-1; - _path=null; - _param=null; - _query=null; - _fragment=null; + _scheme = null; + _host = null; + _port = -1; + _path = null; + _param = null; + _query = null; + _fragment = null; - _decodedPath=null; + _decodedPath = null; } - /* ------------------------------------------------------------ */ public boolean isAbsolute() { - return _scheme!=null && _scheme.length()>0; + return _scheme != null && !_scheme.isEmpty(); } - - /* ------------------------------------------------------------ */ + @Override public String toString() { - if (_uri==null) + if (_uri == null) { StringBuilder out = new StringBuilder(); - - if (_scheme!=null) + + if (_scheme != null) out.append(_scheme).append(':'); - + if (_host != null) { out.append("//"); @@ -674,114 +648,102 @@ public class HttpURI out.append(_user).append('@'); out.append(_host); } - - if (_port>0) + + if (_port > 0) out.append(':').append(_port); - - if (_path!=null) + + if (_path != null) out.append(_path); - - if (_query!=null) + + if (_query != null) out.append('?').append(_query); - - if (_fragment!=null) + + if (_fragment != null) out.append('#').append(_fragment); - - if (out.length()>0) - _uri=out.toString(); + + if (out.length() > 0) + _uri = out.toString(); else - _uri=""; + _uri = ""; } return _uri; } - /* ------------------------------------------------------------ */ @Override public boolean equals(Object o) { - if (o==this) + if (o == this) return true; if (!(o instanceof HttpURI)) return false; return toString().equals(o.toString()); } - /* ------------------------------------------------------------ */ public void setScheme(String scheme) { - _scheme=scheme; - _uri=null; + _scheme = scheme; + _uri = null; } - - /* ------------------------------------------------------------ */ + /** * @param host the host * @param port the port */ public void setAuthority(String host, int port) { - _host=host; - _port=port; - _uri=null; + _host = host; + _port = port; + _uri = null; } - /* ------------------------------------------------------------ */ /** * @param path the path */ public void setPath(String path) { - _uri=null; - _path=path; - _decodedPath=null; - } - - /* ------------------------------------------------------------ */ - public void setPathQuery(String path) - { - _uri=null; - _path=null; - _decodedPath=null; - _param=null; - _fragment=null; - if (path!=null) - parse(State.PATH,path,0,path.length()); - } - - /* ------------------------------------------------------------ */ - public void setQuery(String query) - { - _query=query; - _uri=null; - } - - /* ------------------------------------------------------------ */ - public URI toURI() throws URISyntaxException - { - return new URI(_scheme,null,_host,_port,_path,_query==null?null:UrlEncoded.decodeString(_query),_fragment); + _uri = null; + _path = path; + _decodedPath = null; + } + + public void setPathQuery(String path) + { + _uri = null; + _path = null; + _decodedPath = null; + _param = null; + _fragment = null; + if (path != null) + parse(State.PATH, path, 0, path.length()); + } + + public void setQuery(String query) + { + _query = query; + _uri = null; + } + + public URI toURI() throws URISyntaxException + { + return new URI(_scheme, null, _host, _port, _path, _query == null ? null : UrlEncoded.decodeString(_query), _fragment); } - /* ------------------------------------------------------------ */ public String getPathQuery() { - if (_query==null) + if (_query == null) return _path; - return _path+"?"+_query; + return _path + "?" + _query; } - - /* ------------------------------------------------------------ */ + public String getAuthority() { - if (_port>0) - return _host+":"+_port; + if (_port > 0) + return _host + ":" + _port; return _host; } - - /* ------------------------------------------------------------ */ + public String getUser() { return _user; } - - } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpVersion.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpVersion.java index dfc700fde39..12991ad105f 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpVersion.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpVersion.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -24,45 +24,45 @@ import org.eclipse.jetty.util.ArrayTrie; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.Trie; - -/* ------------------------------------------------------------------------------- */ public enum HttpVersion { - HTTP_0_9("HTTP/0.9",9), - HTTP_1_0("HTTP/1.0",10), - HTTP_1_1("HTTP/1.1",11), - HTTP_2("HTTP/2.0",20); + HTTP_0_9("HTTP/0.9", 9), + HTTP_1_0("HTTP/1.0", 10), + HTTP_1_1("HTTP/1.1", 11), + HTTP_2("HTTP/2.0", 20); + + public static final Trie CACHE = new ArrayTrie(); - /* ------------------------------------------------------------ */ - public final static Trie CACHE= new ArrayTrie(); static { for (HttpVersion version : HttpVersion.values()) - CACHE.put(version.toString(),version); + { + CACHE.put(version.toString(), version); + } } - /* ------------------------------------------------------------ */ - /** - * Optimised lookup to find a Http Version and whitespace in a byte array. + /** + * Optimised lookup to find an Http Version and whitespace in a byte array. + * * @param bytes Array containing ISO-8859-1 characters * @param position The first valid index * @param limit The first non valid index - * @return A HttpMethod if a match or null if no easy match. + * @return An HttpMethod if a match or null if no easy match. */ public static HttpVersion lookAheadGet(byte[] bytes, int position, int limit) { - int length=limit-position; - if (length<9) + int length = limit - position; + if (length < 9) return null; - if (bytes[position+4]=='/' && bytes[position+6]=='.' && Character.isWhitespace((char)bytes[position+8]) && - ((bytes[position]=='H' && bytes[position+1]=='T' && bytes[position+2]=='T' && bytes[position+3]=='P') || - (bytes[position]=='h' && bytes[position+1]=='t' && bytes[position+2]=='t' && bytes[position+3]=='p'))) + if (bytes[position + 4] == '/' && bytes[position + 6] == '.' && Character.isWhitespace((char)bytes[position + 8]) && + ((bytes[position] == 'H' && bytes[position + 1] == 'T' && bytes[position + 2] == 'T' && bytes[position + 3] == 'P') || + (bytes[position] == 'h' && bytes[position + 1] == 't' && bytes[position + 2] == 't' && bytes[position + 3] == 'p'))) { - switch(bytes[position+5]) + switch (bytes[position + 5]) { case '1': - switch(bytes[position+7]) + switch (bytes[position + 7]) { case '0': return HTTP_1_0; @@ -71,7 +71,7 @@ public enum HttpVersion } break; case '2': - switch(bytes[position+7]) + switch (bytes[position + 7]) { case '0': return HTTP_2; @@ -79,69 +79,61 @@ public enum HttpVersion break; } } - + return null; } - /* ------------------------------------------------------------ */ - /** - * Optimised lookup to find a HTTP Version and trailing white space in a byte array. + /** + * Optimised lookup to find an HTTP Version and trailing white space in a byte array. + * * @param buffer buffer containing ISO-8859-1 characters - * @return A HttpVersion if a match or null if no easy match. + * @return An HttpVersion if a match or null if no easy match. */ public static HttpVersion lookAheadGet(ByteBuffer buffer) { if (buffer.hasArray()) - return lookAheadGet(buffer.array(),buffer.arrayOffset()+buffer.position(),buffer.arrayOffset()+buffer.limit()); + return lookAheadGet(buffer.array(), buffer.arrayOffset() + buffer.position(), buffer.arrayOffset() + buffer.limit()); return null; } - - + private final String _string; private final byte[] _bytes; private final ByteBuffer _buffer; private final int _version; - /* ------------------------------------------------------------ */ - HttpVersion(String s,int version) + HttpVersion(String s, int version) { - _string=s; - _bytes=StringUtil.getBytes(s); - _buffer=ByteBuffer.wrap(_bytes); - _version=version; + _string = s; + _bytes = StringUtil.getBytes(s); + _buffer = ByteBuffer.wrap(_bytes); + _version = version; } - /* ------------------------------------------------------------ */ public byte[] toBytes() { return _bytes; } - /* ------------------------------------------------------------ */ public ByteBuffer toBuffer() { return _buffer.asReadOnlyBuffer(); } - /* ------------------------------------------------------------ */ public int getVersion() { return _version; } - /* ------------------------------------------------------------ */ public boolean is(String s) { - return _string.equalsIgnoreCase(s); + return _string.equalsIgnoreCase(s); } - - /* ------------------------------------------------------------ */ + public String asString() { return _string; } - - /* ------------------------------------------------------------ */ + @Override public String toString() { @@ -150,6 +142,7 @@ public enum HttpVersion /** * Case insensitive fromString() conversion + * * @param version the String to convert to enum constant * @return the enum constant or null if version unknown */ @@ -158,16 +151,20 @@ public enum HttpVersion return CACHE.get(version); } - /* ------------------------------------------------------------ */ public static HttpVersion fromVersion(int version) { - switch(version) + switch (version) { - case 9: return HttpVersion.HTTP_0_9; - case 10: return HttpVersion.HTTP_1_0; - case 11: return HttpVersion.HTTP_1_1; - case 20: return HttpVersion.HTTP_2; - default: throw new IllegalArgumentException(); + case 9: + return HttpVersion.HTTP_0_9; + case 10: + return HttpVersion.HTTP_1_0; + case 11: + return HttpVersion.HTTP_1_1; + case 20: + return HttpVersion.HTTP_2; + default: + throw new IllegalArgumentException(); } } } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java index decab4d73bd..7c9ef10d507 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -60,8 +60,8 @@ public class MetaData implements Iterable } /** - * @deprecated use {@link #getHttpVersion()} instead * @return the HTTP version of this MetaData object + * @deprecated use {@link #getHttpVersion()} instead */ @Deprecated public HttpVersion getVersion() @@ -127,7 +127,7 @@ public class MetaData implements Iterable public Iterator iterator() { HttpFields fields = getFields(); - return fields == null ? Collections.emptyIterator() : fields.iterator(); + return fields == null ? Collections.emptyIterator() : fields.iterator(); } @Override @@ -135,7 +135,9 @@ public class MetaData implements Iterable { StringBuilder out = new StringBuilder(); for (HttpField field : this) + { out.append(field).append(System.lineSeparator()); + } return out.toString(); } @@ -163,31 +165,31 @@ public class MetaData implements Iterable public Request(String method, HttpScheme scheme, HostPortHttpField hostPort, String uri, HttpVersion version, HttpFields fields) { - this(method, new HttpURI(scheme == null ? null : scheme.asString(), - hostPort==null?null:hostPort.getHost(), - hostPort==null?-1:hostPort.getPort(), + this(method, new HttpURI(scheme == null ? null : scheme.asString(), + hostPort == null ? null : hostPort.getHost(), + hostPort == null ? -1 : hostPort.getPort(), uri), version, fields); } public Request(String method, HttpScheme scheme, HostPortHttpField hostPort, String uri, HttpVersion version, HttpFields fields, long contentLength) { - this(method, new HttpURI(scheme==null?null:scheme.asString(), - hostPort==null?null:hostPort.getHost(), - hostPort==null?-1:hostPort.getPort(), + this(method, new HttpURI(scheme == null ? null : scheme.asString(), + hostPort == null ? null : hostPort.getHost(), + hostPort == null ? -1 : hostPort.getPort(), uri), version, fields, contentLength); } public Request(String method, String scheme, HostPortHttpField hostPort, String uri, HttpVersion version, HttpFields fields, long contentLength) { this(method, new HttpURI(scheme, - hostPort==null?null:hostPort.getHost(), - hostPort==null?-1:hostPort.getPort(), + hostPort == null ? null : hostPort.getHost(), + hostPort == null ? -1 : hostPort.getPort(), uri), version, fields, contentLength); } public Request(Request request) { - this(request.getMethod(),new HttpURI(request.getURI()), request.getHttpVersion(), new HttpFields(request.getFields()), request.getContentLength()); + this(request.getMethod(), new HttpURI(request.getURI()), request.getHttpVersion(), new HttpFields(request.getFields()), request.getContentLength()); } @Override @@ -250,7 +252,7 @@ public class MetaData implements Iterable { HttpFields fields = getFields(); return String.format("%s{u=%s,%s,h=%d,cl=%d}", - getMethod(), getURI(), getHttpVersion(), fields == null ? -1 : fields.size(), getContentLength()); + getMethod(), getURI(), getHttpVersion(), fields == null ? -1 : fields.size(), getContentLength()); } } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java index de50d4bc09d..a12706a1e3b 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -39,20 +39,18 @@ import org.eclipse.jetty.util.Trie; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; - -/* ------------------------------------------------------------ */ -/** MIME Type enum and utilities - * +/** + * MIME Type enum and utilities */ public class MimeTypes { - /* ------------------------------------------------------------ */ + private static final Logger LOG = Log.getLogger(MimeTypes.class); - private static final Trie TYPES= new ArrayTrie(512); - private static final Map __dftMimeMap = new HashMap(); - private static final Map __inferredEncodings = new HashMap(); - private static final Map __assumedEncodings = new HashMap(); - + private static final Trie TYPES = new ArrayTrie(512); + private static final Map __dftMimeMap = new HashMap(); + private static final Map __inferredEncodings = new HashMap(); + private static final Map __assumedEncodings = new HashMap(); + public enum Type { FORM_ENCODED("application/x-www-form-urlencoded"), @@ -63,26 +61,24 @@ public class MimeTypes TEXT_HTML("text/html"), TEXT_PLAIN("text/plain"), TEXT_XML("text/xml"), - TEXT_JSON("text/json",StandardCharsets.UTF_8), - APPLICATION_JSON("application/json",StandardCharsets.UTF_8), + TEXT_JSON("text/json", StandardCharsets.UTF_8), + APPLICATION_JSON("application/json", StandardCharsets.UTF_8), - TEXT_HTML_8859_1("text/html;charset=iso-8859-1",TEXT_HTML), - TEXT_HTML_UTF_8("text/html;charset=utf-8",TEXT_HTML), + TEXT_HTML_8859_1("text/html;charset=iso-8859-1", TEXT_HTML), + TEXT_HTML_UTF_8("text/html;charset=utf-8", TEXT_HTML), - TEXT_PLAIN_8859_1("text/plain;charset=iso-8859-1",TEXT_PLAIN), - TEXT_PLAIN_UTF_8("text/plain;charset=utf-8",TEXT_PLAIN), + TEXT_PLAIN_8859_1("text/plain;charset=iso-8859-1", TEXT_PLAIN), + TEXT_PLAIN_UTF_8("text/plain;charset=utf-8", TEXT_PLAIN), - TEXT_XML_8859_1("text/xml;charset=iso-8859-1",TEXT_XML), - TEXT_XML_UTF_8("text/xml;charset=utf-8",TEXT_XML), + TEXT_XML_8859_1("text/xml;charset=iso-8859-1", TEXT_XML), + TEXT_XML_UTF_8("text/xml;charset=utf-8", TEXT_XML), - TEXT_JSON_8859_1("text/json;charset=iso-8859-1",TEXT_JSON), - TEXT_JSON_UTF_8("text/json;charset=utf-8",TEXT_JSON), + TEXT_JSON_8859_1("text/json;charset=iso-8859-1", TEXT_JSON), + TEXT_JSON_UTF_8("text/json;charset=utf-8", TEXT_JSON), - APPLICATION_JSON_8859_1("application/json;charset=iso-8859-1",APPLICATION_JSON), - APPLICATION_JSON_UTF_8("application/json;charset=utf-8",APPLICATION_JSON); + APPLICATION_JSON_8859_1("application/json;charset=iso-8859-1", APPLICATION_JSON), + APPLICATION_JSON_UTF_8("application/json;charset=utf-8", APPLICATION_JSON); - - /* ------------------------------------------------------------ */ private final String _string; private final Type _base; private final ByteBuffer _buffer; @@ -91,118 +87,106 @@ public class MimeTypes private final boolean _assumedCharset; private final HttpField _field; - /* ------------------------------------------------------------ */ Type(String s) { - _string=s; - _buffer=BufferUtil.toBuffer(s); - _base=this; - _charset=null; - _charsetString=null; - _assumedCharset=false; - _field=new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,_string); + _string = s; + _buffer = BufferUtil.toBuffer(s); + _base = this; + _charset = null; + _charsetString = null; + _assumedCharset = false; + _field = new PreEncodedHttpField(HttpHeader.CONTENT_TYPE, _string); } - /* ------------------------------------------------------------ */ - Type(String s,Type base) + Type(String s, Type base) { - _string=s; - _buffer=BufferUtil.toBuffer(s); - _base=base; - int i=s.indexOf(";charset="); - _charset=Charset.forName(s.substring(i+9)); - _charsetString=_charset.toString().toLowerCase(Locale.ENGLISH); - _assumedCharset=false; - _field=new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,_string); + _string = s; + _buffer = BufferUtil.toBuffer(s); + _base = base; + int i = s.indexOf(";charset="); + _charset = Charset.forName(s.substring(i + 9)); + _charsetString = _charset.toString().toLowerCase(Locale.ENGLISH); + _assumedCharset = false; + _field = new PreEncodedHttpField(HttpHeader.CONTENT_TYPE, _string); } - /* ------------------------------------------------------------ */ - Type(String s,Charset cs) + Type(String s, Charset cs) { - _string=s; - _base=this; - _buffer=BufferUtil.toBuffer(s); - _charset=cs; - _charsetString=_charset==null?null:_charset.toString().toLowerCase(Locale.ENGLISH); - _assumedCharset=true; - _field=new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,_string); + _string = s; + _base = this; + _buffer = BufferUtil.toBuffer(s); + _charset = cs; + _charsetString = _charset == null ? null : _charset.toString().toLowerCase(Locale.ENGLISH); + _assumedCharset = true; + _field = new PreEncodedHttpField(HttpHeader.CONTENT_TYPE, _string); } - /* ------------------------------------------------------------ */ public ByteBuffer asBuffer() { return _buffer.asReadOnlyBuffer(); } - /* ------------------------------------------------------------ */ public Charset getCharset() { return _charset; } - /* ------------------------------------------------------------ */ public String getCharsetString() { return _charsetString; } - /* ------------------------------------------------------------ */ public boolean is(String s) { return _string.equalsIgnoreCase(s); } - /* ------------------------------------------------------------ */ public String asString() { return _string; } - /* ------------------------------------------------------------ */ @Override public String toString() { return _string; } - /* ------------------------------------------------------------ */ public boolean isCharsetAssumed() { return _assumedCharset; } - /* ------------------------------------------------------------ */ public HttpField getContentTypeField() { return _field; } - /* ------------------------------------------------------------ */ public Type getBaseType() { return _base; } } - /* ------------------------------------------------------------ */ - public static final Trie CACHE= new ArrayTrie<>(512); + public static final Trie CACHE = new ArrayTrie<>(512); + static { for (MimeTypes.Type type : MimeTypes.Type.values()) { - CACHE.put(type.toString(),type); - TYPES.put(type.toString(),type.asBuffer()); + CACHE.put(type.toString(), type); + TYPES.put(type.toString(), type.asBuffer()); - int charset=type.toString().indexOf(";charset="); - if (charset>0) + int charset = type.toString().indexOf(";charset="); + if (charset > 0) { - String alt=type.toString().replace(";charset=","; charset="); - CACHE.put(alt,type); - TYPES.put(alt,type.asBuffer()); + String alt = StringUtil.replace(type.toString(), ";charset=", "; charset="); + CACHE.put(alt, type); + TYPES.put(alt, type.asBuffer()); } - + if (type.isCharsetAssumed()) - __assumedEncodings.put(type.asString(),type.getCharsetString()); + __assumedEncodings.put(type.asString(), type.getCharsetString()); } String resourceName = "org/eclipse/jetty/http/mime.properties"; @@ -219,25 +203,24 @@ public class MimeTypes Properties props = new Properties(); props.load(reader); props.stringPropertyNames().stream() - .filter(x->x!=null) - .forEach(x-> - __dftMimeMap.put(StringUtil.asciiToLowerCase(x), normalizeMimeType(props.getProperty(x)))); + .filter(x -> x != null) + .forEach(x -> + __dftMimeMap.put(StringUtil.asciiToLowerCase(x), normalizeMimeType(props.getProperty(x)))); - if (__dftMimeMap.size()==0) + if (__dftMimeMap.isEmpty()) { LOG.warn("Empty mime types at {}", resourceName); } - else if (__dftMimeMap.size()t!=null) - .forEach(t-> - { - String charset = props.getProperty(t); - if (charset.startsWith("-")) - __assumedEncodings.put(t, charset.substring(1)); - else - __inferredEncodings.put(t, props.getProperty(t)); - }); + .filter(t -> t != null) + .forEach(t -> + { + String charset = props.getProperty(t); + if (charset.startsWith("-")) + __assumedEncodings.put(t, charset.substring(1)); + else + __inferredEncodings.put(t, props.getProperty(t)); + }); - if (__inferredEncodings.size()==0) + if (__inferredEncodings.isEmpty()) { LOG.warn("Empty encodings at {}", resourceName); } - else if ((__inferredEncodings.size()+__assumedEncodings.size()) _mimeMap = new HashMap(); - /* ------------------------------------------------------------ */ - private final Map _mimeMap=new HashMap(); - - /* ------------------------------------------------------------ */ - /** Constructor. + /** + * Constructor. */ public MimeTypes() { } - /* ------------------------------------------------------------ */ - public synchronized Map getMimeMap() + public synchronized Map getMimeMap() { return _mimeMap; } - /* ------------------------------------------------------------ */ /** * @param mimeMap A Map of file extension to mime-type. */ - public void setMimeMap(Map mimeMap) + public void setMimeMap(Map mimeMap) { _mimeMap.clear(); - if (mimeMap!=null) + if (mimeMap != null) { for (Entry ext : mimeMap.entrySet()) - _mimeMap.put(StringUtil.asciiToLowerCase(ext.getKey()),normalizeMimeType(ext.getValue())); + { + _mimeMap.put(StringUtil.asciiToLowerCase(ext.getKey()), normalizeMimeType(ext.getValue())); + } } } - /* ------------------------------------------------------------ */ - /** Get the MIME type by filename extension. + /** + * Get the MIME type by filename extension. * Lookup only the static default mime map. + * * @param filename A file name * @return MIME type matching the longest dot extension of the * file name. */ public static String getDefaultMimeByExtension(String filename) { - String type=null; + String type = null; - if (filename!=null) + if (filename != null) { - int i=-1; - while(type==null) + int i = -1; + while (type == null) { - i=filename.indexOf(".",i+1); + i = filename.indexOf(".", i + 1); - if (i<0 || i>=filename.length()) + if (i < 0 || i >= filename.length()) break; - String ext=StringUtil.asciiToLowerCase(filename.substring(i+1)); - if (type==null) - type=__dftMimeMap.get(ext); + String ext = StringUtil.asciiToLowerCase(filename.substring(i + 1)); + if (type == null) + type = __dftMimeMap.get(ext); } } - if (type==null) + if (type == null) { - type=__dftMimeMap.get("*"); + type = __dftMimeMap.get("*"); } return type; } - /* ------------------------------------------------------------ */ - /** Get the MIME type by filename extension. + /** + * Get the MIME type by filename extension. * Lookup the content and static default mime maps. + * * @param filename A file name * @return MIME type matching the longest dot extension of the * file name. */ public String getMimeByExtension(String filename) { - String type=null; + String type = null; - if (filename!=null) + if (filename != null) { - int i=-1; - while(type==null) + int i = -1; + while (type == null) { - i=filename.indexOf(".",i+1); + i = filename.indexOf(".", i + 1); - if (i<0 || i>=filename.length()) + if (i < 0 || i >= filename.length()) break; - String ext=StringUtil.asciiToLowerCase(filename.substring(i+1)); - if (_mimeMap!=null) - type=_mimeMap.get(ext); - if (type==null) - type=__dftMimeMap.get(ext); + String ext = StringUtil.asciiToLowerCase(filename.substring(i + 1)); + if (_mimeMap != null) + type = _mimeMap.get(ext); + if (type == null) + type = __dftMimeMap.get(ext); } } - if (type==null) + if (type == null) { - if (_mimeMap!=null) - type=_mimeMap.get("*"); - if (type==null) - type=__dftMimeMap.get("*"); + if (_mimeMap != null) + type = _mimeMap.get("*"); + if (type == null) + type = __dftMimeMap.get("*"); } return type; } - /* ------------------------------------------------------------ */ - /** Set a mime mapping + /** + * Set a mime mapping + * * @param extension the extension * @param type the mime type */ - public void addMimeMapping(String extension,String type) + public void addMimeMapping(String extension, String type) { - _mimeMap.put(StringUtil.asciiToLowerCase(extension),normalizeMimeType(type)); + _mimeMap.put(StringUtil.asciiToLowerCase(extension), normalizeMimeType(type)); } - /* ------------------------------------------------------------ */ public static Set getKnownMimeTypes() { return new HashSet<>(__dftMimeMap.values()); } - /* ------------------------------------------------------------ */ private static String normalizeMimeType(String type) { - MimeTypes.Type t =CACHE.get(type); - if (t!=null) + MimeTypes.Type t = CACHE.get(type); + if (t != null) return t.asString(); return StringUtil.asciiToLowerCase(type); } - /* ------------------------------------------------------------ */ public static String getCharsetFromContentType(String value) { - if (value==null) + if (value == null) return null; - int end=value.length(); - int state=0; - int start=0; - boolean quote=false; - int i=0; - for (;i getInferredEncodings() + public static Map getInferredEncodings() { return __inferredEncodings; } - + /** * Access a mutable map of mime type to the charset assumed for that content type. - * An assumed encoding is used by when encoding/decoding a stream, but is not + * An assumed encoding is used by when encoding/decoding a stream, but is not * explicitly set in any metadata (eg Content-Type). + * * @return Map of mime type to charset */ - public static Map getAssumedEncodings() + public static Map getAssumedEncodings() { return __assumedEncodings; } @@ -524,7 +547,7 @@ public class MimeTypes { return getCharsetAssumedFromContentType(contentType); } - + public static String getCharsetInferredFromContentType(String contentType) { return __inferredEncodings.get(contentType); @@ -534,97 +557,129 @@ public class MimeTypes { return __assumedEncodings.get(contentType); } - + public static String getContentTypeWithoutCharset(String value) { - int end=value.length(); - int state=0; - int start=0; - boolean quote=false; - int i=0; - StringBuilder builder=null; - for (;i _headers; protected long _size = 0; protected boolean _temporary = true; - + public MultiPart(String name, String filename) { _name = name; _filename = filename; } - + @Override public String toString() { return String.format("Part{n=%s,fn=%s,ct=%s,s=%d,tmp=%b,file=%s}", _name, _filename, _contentType, _size, _temporary, _file); } - + protected void setContentType(String contentType) { _contentType = contentType; } - + protected void open() throws IOException { // We will either be writing to a file, if it has a filename on the content-disposition // and otherwise a byte-array-input-stream, OR if we exceed the getFileSizeThreshold, we // will need to change to write to a file. - if (isWriteFilesWithFilenames() && _filename != null && _filename.trim().length() > 0) + if (isWriteFilesWithFilenames() && _filename != null && !_filename.trim().isEmpty()) { createFile(); } @@ -118,38 +117,38 @@ public class MultiPartFormInputStream _out = _bout = new ByteArrayOutputStream2(); } } - + protected void close() throws IOException { _out.close(); } - + protected void write(int b) throws IOException { if (MultiPartFormInputStream.this._config.getMaxFileSize() > 0 && _size + 1 > MultiPartFormInputStream.this._config.getMaxFileSize()) throw new IllegalStateException("Multipart Mime part " + _name + " exceeds max filesize"); - - if (MultiPartFormInputStream.this._config.getFileSizeThreshold() > 0 && _size + 1 > MultiPartFormInputStream.this._config.getFileSizeThreshold() - && _file == null) + + if (MultiPartFormInputStream.this._config.getFileSizeThreshold() > 0 && + _size + 1 > MultiPartFormInputStream.this._config.getFileSizeThreshold() && _file == null) createFile(); - + _out.write(b); _size++; } - + protected void write(byte[] bytes, int offset, int length) throws IOException { if (MultiPartFormInputStream.this._config.getMaxFileSize() > 0 && _size + length > MultiPartFormInputStream.this._config.getMaxFileSize()) throw new IllegalStateException("Multipart Mime part " + _name + " exceeds max filesize"); - - if (MultiPartFormInputStream.this._config.getFileSizeThreshold() > 0 - && _size + length > MultiPartFormInputStream.this._config.getFileSizeThreshold() && _file == null) + + if (MultiPartFormInputStream.this._config.getFileSizeThreshold() > 0 && + _size + length > MultiPartFormInputStream.this._config.getFileSizeThreshold() && _file == null) createFile(); - + _out.write(bytes, offset, length); _size += length; } - + protected void createFile() throws IOException { /* @@ -157,16 +156,16 @@ public class MultiPartFormInputStream */ final boolean USER = true; final boolean WORLD = false; - + _file = File.createTempFile("MultiPart", "", MultiPartFormInputStream.this._tmpDir); _file.setReadable(false, WORLD); // (reset) disable it for everyone first _file.setReadable(true, USER); // enable for user only - + if (_deleteOnExit) _file.deleteOnExit(); FileOutputStream fos = new FileOutputStream(_file); BufferedOutputStream bos = new BufferedOutputStream(fos); - + if (_size > 0 && _out != null) { // already written some bytes, so need to copy them into the file @@ -177,18 +176,18 @@ public class MultiPartFormInputStream _bout = null; _out = bos; } - + protected void setHeaders(MultiMap headers) { _headers = headers; } - + @Override public String getContentType() { return _contentType; } - + @Override public String getHeader(String name) { @@ -196,19 +195,20 @@ public class MultiPartFormInputStream return null; return _headers.getValue(StringUtil.asciiToLowerCase(name), 0); } - + @Override public Collection getHeaderNames() { return _headers.keySet(); } - + @Override public Collection getHeaders(String name) { - return _headers.getValues(name); + Collection headers = _headers.getValues(name); + return headers == null ? Collections.emptyList() : headers; } - + @Override public InputStream getInputStream() throws IOException { @@ -223,42 +223,42 @@ public class MultiPartFormInputStream return new ByteArrayInputStream(_bout.getBuf(), 0, _bout.size()); } } - + @Override public String getSubmittedFileName() { return getContentDispositionFilename(); } - + public byte[] getBytes() { if (_bout != null) return _bout.toByteArray(); return null; } - + @Override public String getName() { return _name; } - + @Override public long getSize() { return _size; } - + @Override public void write(String fileName) throws IOException { if (_file == null) { _temporary = false; - + // part data is only in the ByteArrayOutputStream and never been written to disk _file = new File(_tmpDir, fileName); - + try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(_file))) { _bout.writeTo(bos); @@ -273,14 +273,14 @@ public class MultiPartFormInputStream { // the part data is already written to a temporary file, just rename it _temporary = false; - + Path src = _file.toPath(); Path target = src.resolveSibling(fileName); Files.move(src, target, StandardCopyOption.REPLACE_EXISTING); _file = target.toFile(); } } - + /** * Remove the file, whether or not Part.write() was called on it (ie no longer temporary) */ @@ -291,7 +291,7 @@ public class MultiPartFormInputStream if (!_file.delete()) throw new IOException("Could Not Delete File"); } - + /** * Only remove tmp files. * @@ -299,11 +299,10 @@ public class MultiPartFormInputStream */ public void cleanUp() throws IOException { - if (_temporary && _file != null && _file.exists()) - if (!_file.delete()) - throw new IOException("Could Not Delete File"); + if (_temporary) + delete(); } - + /** * Get the file * @@ -313,7 +312,7 @@ public class MultiPartFormInputStream { return _file; } - + /** * Get the filename from the content-disposition. * @@ -324,11 +323,11 @@ public class MultiPartFormInputStream return _filename; } } - + /** - * @param in Request input stream - * @param contentType Content-Type header - * @param config MultipartConfigElement + * @param in Request input stream + * @param contentType Content-Type header + * @param config MultipartConfigElement * @param contextTmpDir javax.servlet.context.tempdir */ public MultiPartFormInputStream(InputStream in, String contentType, MultipartConfigElement config, File contextTmpDir) @@ -338,10 +337,10 @@ public class MultiPartFormInputStream _contextTmpDir = contextTmpDir; if (_contextTmpDir == null) _contextTmpDir = new File(System.getProperty("java.io.tmpdir")); - + if (_config == null) _config = new MultipartConfigElement(_contextTmpDir.getAbsolutePath()); - + if (in instanceof ServletInputStream) { if (((ServletInputStream)in).isFinished()) @@ -353,7 +352,7 @@ public class MultiPartFormInputStream } _in = new BufferedInputStream(in); } - + /** * @return whether the list of parsed parts is empty */ @@ -361,17 +360,17 @@ public class MultiPartFormInputStream { if (_parts == null) return true; - + Collection> values = _parts.values(); for (List partList : values) { - if (partList.size() != 0) + if (!partList.isEmpty()) return false; } - + return true; } - + /** * Get the already parsed parts. * @@ -382,7 +381,7 @@ public class MultiPartFormInputStream { if (_parts == null) return Collections.emptyList(); - + Collection> values = _parts.values(); List parts = new ArrayList<>(); for (List o : values) @@ -392,45 +391,35 @@ public class MultiPartFormInputStream } return parts; } - + /** * Delete any tmp storage for parts, and clear out the parts list. */ public void deleteParts() { - if (!_parsed) - return; - - Collection parts; - try - { - parts = getParts(); - } - catch (IOException e) - { - throw new RuntimeException(e); - } - MultiException err = null; - for (Part p : parts) + for (List parts : _parts.values()) { - try + for (Part p : parts) { - ((MultiPart)p).cleanUp(); - } - catch (Exception e) - { - if (err == null) - err = new MultiException(); - err.add(e); + try + { + ((MultiPart)p).cleanUp(); + } + catch (Exception e) + { + if (err == null) + err = new MultiException(); + err.add(e); + } } } _parts.clear(); - + if (err != null) err.ifExceptionThrowRuntime(); } - + /** * Parse, if necessary, the multipart data and return the list of Parts. * @@ -442,7 +431,7 @@ public class MultiPartFormInputStream if (!_parsed) parse(); throwIfError(); - + Collection> values = _parts.values(); List parts = new ArrayList<>(); for (List o : values) @@ -452,7 +441,7 @@ public class MultiPartFormInputStream } return parts; } - + /** * Get the named Part. * @@ -467,7 +456,7 @@ public class MultiPartFormInputStream throwIfError(); return _parts.getValue(name, 0); } - + /** * Throws an exception if one has been latched. * @@ -477,6 +466,9 @@ public class MultiPartFormInputStream { if (_err != null) { + if (LOG.isDebugEnabled()) + LOG.debug("MultiPart parsing failure ", _err); + _err.addSuppressed(new Throwable()); if (_err instanceof IOException) throw (IOException)_err; @@ -485,7 +477,7 @@ public class MultiPartFormInputStream throw new IllegalStateException(_err); } } - + /** * Parse, if necessary, the multipart stream. */ @@ -495,16 +487,18 @@ public class MultiPartFormInputStream if (_parsed) return; _parsed = true; - + + MultiPartParser parser = null; + Handler handler = new Handler(); try { // initialize _parts = new MultiMap<>(); - + // if its not a multipart request, don't parse it if (_contentType == null || !_contentType.startsWith("multipart/form-data")) return; - + // sort out the location to which to write the files if (_config.getLocation() == null) _tmpDir = _contextTmpDir; @@ -518,10 +512,10 @@ public class MultiPartFormInputStream else _tmpDir = new File(_contextTmpDir, _config.getLocation()); } - + if (!_tmpDir.exists()) _tmpDir.mkdirs(); - + String contentTypeBoundary = ""; int bstart = _contentType.indexOf("boundary="); if (bstart >= 0) @@ -530,22 +524,19 @@ public class MultiPartFormInputStream bend = (bend < 0 ? _contentType.length() : bend); contentTypeBoundary = QuotedStringTokenizer.unquote(value(_contentType.substring(bstart, bend)).trim()); } - - Handler handler = new Handler(); - MultiPartParser parser = new MultiPartParser(handler, contentTypeBoundary); - + + parser = new MultiPartParser(handler, contentTypeBoundary); byte[] data = new byte[_bufferSize]; int len; long total = 0; - + while (true) { - + len = _in.read(data); - + if (len > 0) { - // keep running total of size of bytes read from input and throw an exception if exceeds MultipartConfigElement._maxRequestSize total += len; if (_config.getMaxRequestSize() > 0 && total > _config.getMaxRequestSize()) @@ -553,30 +544,28 @@ public class MultiPartFormInputStream _err = new IllegalStateException("Request exceeds maxRequestSize (" + _config.getMaxRequestSize() + ")"); return; } - + ByteBuffer buffer = BufferUtil.toBuffer(data); buffer.limit(len); if (parser.parse(buffer, false)) break; - + if (buffer.hasRemaining()) throw new IllegalStateException("Buffer did not fully consume"); - } else if (len == -1) { parser.parse(BufferUtil.EMPTY_BUFFER, true); break; } - } - + // check for exceptions if (_err != null) { return; } - + // check we read to the end of the message if (parser.getState() != MultiPartParser.State.END) { @@ -585,32 +574,35 @@ public class MultiPartFormInputStream else _err = new IOException("Incomplete Multipart"); } - + if (LOG.isDebugEnabled()) { LOG.debug("Parsing Complete {} err={}", parser, _err); } - } catch (Throwable e) { _err = e; + + // Notify parser if failure occurs + if (parser != null) + parser.parse(BufferUtil.EMPTY_BUFFER, true); } } - + class Handler implements MultiPartParser.Handler { private MultiPart _part = null; private String contentDisposition = null; private String contentType = null; private MultiMap headers = new MultiMap<>(); - + @Override public boolean messageComplete() { return true; } - + @Override public void parsedField(String key, String value) { @@ -620,12 +612,12 @@ public class MultiPartFormInputStream contentDisposition = value; else if (key.equalsIgnoreCase("content-type")) contentType = value; - + // Transfer encoding is not longer considers as it is deprecated as per // https://tools.ietf.org/html/rfc7578#section-4.7 - + } - + @Override public boolean headerComplete() { @@ -633,16 +625,16 @@ public class MultiPartFormInputStream { LOG.debug("headerComplete {}", this); } - + try { // Extract content-disposition - boolean form_data = false; + boolean formData = false; if (contentDisposition == null) { throw new IOException("Missing content-disposition"); } - + QuotedStringTokenizer tok = new QuotedStringTokenizer(contentDisposition, ";", false, true); String name = null; String filename = null; @@ -651,17 +643,17 @@ public class MultiPartFormInputStream String t = tok.nextToken().trim(); String tl = StringUtil.asciiToLowerCase(t); if (tl.startsWith("form-data")) - form_data = true; + formData = true; else if (tl.startsWith("name=")) name = value(t); else if (tl.startsWith("filename=")) filename = filenameValue(t); } - + // Check disposition - if (!form_data) + if (!formData) throw new IOException("Part not form-data"); - + // It is valid for reset and submit buttons to have an empty name. // If no name is supplied, the browser skips sending the info for that field. // However, if you supply the empty string as the name, the browser sends the @@ -669,14 +661,13 @@ public class MultiPartFormInputStream // have not yet seen a name field. if (name == null) throw new IOException("No name in part"); - - + // create the new part _part = new MultiPart(name, filename); _part.setHeaders(headers); _part.setContentType(contentType); _parts.add(name, _part); - + try { _part.open(); @@ -692,16 +683,16 @@ public class MultiPartFormInputStream _err = e; return true; } - + return false; } - + @Override public boolean content(ByteBuffer buffer, boolean last) { if (_part == null) return false; - + if (BufferUtil.hasContent(buffer)) { try @@ -714,7 +705,7 @@ public class MultiPartFormInputStream return true; } } - + if (last) { try @@ -727,23 +718,33 @@ public class MultiPartFormInputStream return true; } } - + return false; } - + @Override public void startPart() { reset(); } - + @Override public void earlyEOF() { if (LOG.isDebugEnabled()) LOG.debug("Early EOF {}", MultiPartFormInputStream.this); + + try + { + if (_part != null) + _part.close(); + } + catch (IOException e) + { + LOG.warn("part could not be closed", e); + } } - + public void reset() { _part = null; @@ -752,41 +753,39 @@ public class MultiPartFormInputStream headers = new MultiMap<>(); } } - + public void setDeleteOnExit(boolean deleteOnExit) { _deleteOnExit = deleteOnExit; } - + public void setWriteFilesWithFilenames(boolean writeFilesWithFilenames) { _writeFilesWithFilenames = writeFilesWithFilenames; } - + public boolean isWriteFilesWithFilenames() { return _writeFilesWithFilenames; } - + public boolean isDeleteOnExit() { return _deleteOnExit; } - - /* ------------------------------------------------------------ */ + private static String value(String nameEqualsValue) { int idx = nameEqualsValue.indexOf('='); String value = nameEqualsValue.substring(idx + 1).trim(); return QuotedStringTokenizer.unquoteOnly(value); } - - /* ------------------------------------------------------------ */ + private static String filenameValue(String nameEqualsValue) { int idx = nameEqualsValue.indexOf('='); String value = nameEqualsValue.substring(idx + 1).trim(); - + if (value.matches(".??[a-z,A-Z]\\:\\\\[^\\\\].*")) { // incorrectly escaped IE filenames that have the whole path @@ -797,7 +796,7 @@ public class MultiPartFormInputStream char last = value.charAt(value.length() - 1); if (last == '"' || last == '\'') value = value.substring(0, value.length() - 1); - + return value; } else @@ -807,7 +806,7 @@ public class MultiPartFormInputStream // backslashes return QuotedStringTokenizer.unquoteOnly(value, true); } - + /** * @return the size of buffer used to read data from the input stream */ @@ -815,7 +814,7 @@ public class MultiPartFormInputStream { return _bufferSize; } - + /** * @param bufferSize the size of buffer used to read data from the input stream */ diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java index 3b1fb97b1ca..6fdf5a1b49c 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -29,8 +29,6 @@ import org.eclipse.jetty.util.Utf8StringBuilder; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -/* ------------------------------------------------------------ */ - /** * A parser for MultiPart content type. * @@ -40,7 +38,7 @@ import org.eclipse.jetty.util.log.Logger; public class MultiPartParser { public static final Logger LOG = Log.getLogger(MultiPartParser.class); - + // States public enum FieldState { @@ -50,7 +48,7 @@ public class MultiPartParser VALUE, IN_VALUE } - + // States public enum State { @@ -64,93 +62,83 @@ public class MultiPartParser EPILOGUE, END } - - private final static EnumSet __delimiterStates = EnumSet.of(State.DELIMITER, State.DELIMITER_CLOSE, State.DELIMITER_PADDING); - private final static int MAX_HEADER_LINE_LENGTH = 998; - - private final boolean DEBUG = LOG.isDebugEnabled(); + + private static final EnumSet __delimiterStates = EnumSet.of(State.DELIMITER, State.DELIMITER_CLOSE, State.DELIMITER_PADDING); + private static final int MAX_HEADER_LINE_LENGTH = 998; + + private final boolean debug = LOG.isDebugEnabled(); private final Handler _handler; private final SearchPattern _delimiterSearch; - + private String _fieldName; private String _fieldValue; - + private State _state = State.PREAMBLE; private FieldState _fieldState = FieldState.FIELD; private int _partialBoundary = 2; // No CRLF if no preamble private boolean _cr; private ByteBuffer _patternBuffer; - + private final Utf8StringBuilder _string = new Utf8StringBuilder(); private int _length; - + private int _totalHeaderLineLength = -1; - - /* ------------------------------------------------------------------------------- */ + public MultiPartParser(Handler handler, String boundary) { _handler = handler; - + String delimiter = "\r\n--" + boundary; _patternBuffer = ByteBuffer.wrap(delimiter.getBytes(StandardCharsets.US_ASCII)); _delimiterSearch = SearchPattern.compile(_patternBuffer.array()); } - + public void reset() { _state = State.PREAMBLE; _fieldState = FieldState.FIELD; _partialBoundary = 2; // No CRLF if no preamble } - - /* ------------------------------------------------------------------------------- */ + public Handler getHandler() { return _handler; } - - /* ------------------------------------------------------------------------------- */ + public State getState() { return _state; } - - /* ------------------------------------------------------------------------------- */ + public boolean isState(State state) { return _state == state; } - - /* ------------------------------------------------------------------------------- */ + private static boolean hasNextByte(ByteBuffer buffer) { return BufferUtil.hasContent(buffer); } - - /* ------------------------------------------------------------------------------- */ + private HttpTokens.Token next(ByteBuffer buffer) { byte ch = buffer.get(); - HttpTokens.Token t = HttpTokens.TOKENS[0xff & ch]; - - if (DEBUG) - LOG.debug("token={}",t); - - switch(t.getType()) + + switch (t.getType()) { case CNTL: - throw new IllegalCharacterException(_state,t,buffer); + throw new IllegalCharacterException(_state, t, buffer); case LF: - _cr=false; + _cr = false; break; case CR: if (_cr) throw new BadMessageException("Bad EOL"); - _cr=true; + _cr = true; return null; case ALPHA: @@ -164,23 +152,21 @@ public class MultiPartParser if (_cr) throw new BadMessageException("Bad EOL"); break; - + default: break; } return t; - } - - /* ------------------------------------------------------------------------------- */ + } + private void setString(String s) { _string.reset(); _string.append(s); _length = s.length(); } - - /* ------------------------------------------------------------------------------- */ + /* * Mime Field strings are treated as UTF-8 as per https://tools.ietf.org/html/rfc7578#section-5.1 */ @@ -194,14 +180,12 @@ public class MultiPartParser _length = -1; return s; } - - /* ------------------------------------------------------------------------------- */ - + /** * Parse until next Event. * * @param buffer the buffer to parse - * @param last whether this buffer contains last bit of content + * @param last whether this buffer contains last bit of content * @return True if an {@link RequestHandler} method was called and it returned true; */ public boolean parse(ByteBuffer buffer, boolean last) @@ -214,63 +198,64 @@ public class MultiPartParser case PREAMBLE: parsePreamble(buffer); continue; - + case DELIMITER: case DELIMITER_PADDING: case DELIMITER_CLOSE: parseDelimiter(buffer); continue; - + case BODY_PART: handle = parseMimePartHeaders(buffer); break; - + case FIRST_OCTETS: case OCTETS: handle = parseOctetContent(buffer); break; - + case EPILOGUE: BufferUtil.clear(buffer); break; - + case END: handle = true; break; - + default: throw new IllegalStateException(); - } } - + if (last && BufferUtil.isEmpty(buffer)) { if (_state == State.EPILOGUE) { _state = State.END; - + if (LOG.isDebugEnabled()) LOG.debug("messageComplete {}", this); - + return _handler.messageComplete(); } else { if (LOG.isDebugEnabled()) LOG.debug("earlyEOF {}", this); - + _handler.earlyEOF(); return true; } } - + return handle; } - - /* ------------------------------------------------------------------------------- */ + private void parsePreamble(ByteBuffer buffer) { + if (LOG.isDebugEnabled()) + LOG.debug("parsePreamble({})", BufferUtil.toDetailString(buffer)); + if (_partialBoundary > 0) { int partial = _delimiterSearch.startsWith(buffer.array(), buffer.arrayOffset() + buffer.position(), buffer.remaining(), _partialBoundary); @@ -283,15 +268,15 @@ public class MultiPartParser setState(State.DELIMITER); return; } - + _partialBoundary = partial; BufferUtil.clear(buffer); return; } - + _partialBoundary = 0; } - + int delimiter = _delimiterSearch.match(buffer.array(), buffer.arrayOffset() + buffer.position(), buffer.remaining()); if (delimiter >= 0) { @@ -299,31 +284,33 @@ public class MultiPartParser setState(State.DELIMITER); return; } - + _partialBoundary = _delimiterSearch.endsWith(buffer.array(), buffer.arrayOffset() + buffer.position(), buffer.remaining()); BufferUtil.clear(buffer); } - - /* ------------------------------------------------------------------------------- */ + private void parseDelimiter(ByteBuffer buffer) { + if (LOG.isDebugEnabled()) + LOG.debug("parseDelimiter({})", BufferUtil.toDetailString(buffer)); + while (__delimiterStates.contains(_state) && hasNextByte(buffer)) { HttpTokens.Token t = next(buffer); if (t == null) return; - - if (t.getType()==HttpTokens.Type.LF) + + if (t.getType() == HttpTokens.Type.LF) { setState(State.BODY_PART); - + if (LOG.isDebugEnabled()) LOG.debug("startPart {}", this); - + _handler.startPart(); return; } - + switch (_state) { case DELIMITER: @@ -332,7 +319,7 @@ public class MultiPartParser else setState(State.DELIMITER_PADDING); continue; - + case DELIMITER_CLOSE: if (t.getChar() == '-') { @@ -341,19 +328,21 @@ public class MultiPartParser } setState(State.DELIMITER_PADDING); continue; - + case DELIMITER_PADDING: default: } } } - - /* ------------------------------------------------------------------------------- */ + /* * Parse the message headers and return true if the handler has signaled for a return */ protected boolean parseMimePartHeaders(ByteBuffer buffer) { + if (LOG.isDebugEnabled()) + LOG.debug("parseMimePartHeaders({})", BufferUtil.toDetailString(buffer)); + // Process headers while (_state == State.BODY_PART && hasNextByte(buffer)) { @@ -361,13 +350,13 @@ public class MultiPartParser HttpTokens.Token t = next(buffer); if (t == null) break; - + if (t.getType() != HttpTokens.Type.LF) _totalHeaderLineLength++; - + if (_totalHeaderLineLength > MAX_HEADER_LINE_LENGTH) throw new IllegalStateException("Header Line Exceeded Max Length"); - + switch (_fieldState) { case FIELD: @@ -377,10 +366,10 @@ public class MultiPartParser case HTAB: { // Folded field value! - + if (_fieldName == null) throw new IllegalStateException("First field folded"); - + if (_fieldValue == null) { _string.reset(); @@ -396,15 +385,15 @@ public class MultiPartParser setState(FieldState.VALUE); break; } - + case LF: handleField(); setState(State.FIRST_OCTETS); _partialBoundary = 2; // CRLF is option for empty parts - + if (LOG.isDebugEnabled()) LOG.debug("headerComplete {}", this); - + if (_handler.headerComplete()) return true; break; @@ -414,39 +403,39 @@ public class MultiPartParser case TCHAR: // process previous header handleField(); - + // New header setState(FieldState.IN_NAME); _string.reset(); _string.append(t.getChar()); _length = 1; - + break; default: - throw new IllegalCharacterException(_state,t,buffer); + throw new IllegalCharacterException(_state, t, buffer); } break; - + case IN_NAME: - switch(t.getType()) + switch (t.getType()) { case COLON: _fieldName = takeString(); _length = -1; setState(FieldState.VALUE); break; - + case SPACE: // Ignore trailing whitespaces setState(FieldState.AFTER_NAME); break; - + case LF: { if (LOG.isDebugEnabled()) LOG.debug("Line Feed in Name {}", this); - + handleField(); setState(FieldState.FIELD); break; @@ -458,47 +447,47 @@ public class MultiPartParser _string.append(t.getChar()); _length = _string.length(); break; - + default: - throw new IllegalCharacterException(_state,t,buffer); + throw new IllegalCharacterException(_state, t, buffer); } break; - + case AFTER_NAME: - switch(t.getType()) + switch (t.getType()) { case COLON: _fieldName = takeString(); _length = -1; setState(FieldState.VALUE); break; - + case LF: _fieldName = takeString(); _string.reset(); _fieldValue = ""; _length = -1; break; - + case SPACE: break; - + default: throw new IllegalCharacterException(_state, t, buffer); } break; - + case VALUE: - switch(t.getType()) + switch (t.getType()) { case LF: _string.reset(); _fieldValue = ""; _length = -1; - + setState(FieldState.FIELD); break; - + case SPACE: case HTAB: break; @@ -515,18 +504,18 @@ public class MultiPartParser break; default: - throw new IllegalCharacterException(_state,t,buffer); + throw new IllegalCharacterException(_state, t, buffer); } break; - + case IN_VALUE: - switch(t.getType()) + switch (t.getType()) { case SPACE: case HTAB: _string.append(' '); break; - + case LF: if (_length > 0) { @@ -536,7 +525,7 @@ public class MultiPartParser } setState(FieldState.FIELD); break; - + case ALPHA: case DIGIT: case TCHAR: @@ -544,38 +533,36 @@ public class MultiPartParser case COLON: case OTEXT: _string.append(t.getByte()); - _length=_string.length(); + _length = _string.length(); break; default: - throw new IllegalCharacterException(_state,t,buffer); + throw new IllegalCharacterException(_state, t, buffer); } break; - + default: throw new IllegalStateException(_state.toString()); - } } return false; } - - /* ------------------------------------------------------------------------------- */ + private void handleField() { if (LOG.isDebugEnabled()) LOG.debug("parsedField: _fieldName={} _fieldValue={} {}", _fieldName, _fieldValue, this); - + if (_fieldName != null && _fieldValue != null) _handler.parsedField(_fieldName, _fieldValue); _fieldName = _fieldValue = null; } - - /* ------------------------------------------------------------------------------- */ - + protected boolean parseOctetContent(ByteBuffer buffer) { - + if (LOG.isDebugEnabled()) + LOG.debug("parseOctetContent({})", BufferUtil.toDetailString(buffer)); + // Starts With if (_partialBoundary > 0) { @@ -587,13 +574,13 @@ public class MultiPartParser buffer.position(buffer.position() + _delimiterSearch.getLength() - _partialBoundary); setState(State.DELIMITER); _partialBoundary = 0; - + if (LOG.isDebugEnabled()) LOG.debug("Content={}, Last={} {}", BufferUtil.toDetailString(BufferUtil.EMPTY_BUFFER), true, this); - + return _handler.content(BufferUtil.EMPTY_BUFFER, true); } - + _partialBoundary = partial; BufferUtil.clear(buffer); return false; @@ -609,81 +596,75 @@ public class MultiPartParser } content.limit(_partialBoundary); _partialBoundary = 0; - + if (LOG.isDebugEnabled()) LOG.debug("Content={}, Last={} {}", BufferUtil.toDetailString(content), false, this); - + if (_handler.content(content, false)) return true; } } - + // Contains int delimiter = _delimiterSearch.match(buffer.array(), buffer.arrayOffset() + buffer.position(), buffer.remaining()); if (delimiter >= 0) { ByteBuffer content = buffer.slice(); content.limit(delimiter - buffer.arrayOffset() - buffer.position()); - + buffer.position(delimiter - buffer.arrayOffset() + _delimiterSearch.getLength()); setState(State.DELIMITER); - + if (LOG.isDebugEnabled()) LOG.debug("Content={}, Last={} {}", BufferUtil.toDetailString(content), true, this); - + return _handler.content(content, true); } - + // Ends With _partialBoundary = _delimiterSearch.endsWith(buffer.array(), buffer.arrayOffset() + buffer.position(), buffer.remaining()); if (_partialBoundary > 0) { ByteBuffer content = buffer.slice(); content.limit(content.limit() - _partialBoundary); - + if (LOG.isDebugEnabled()) LOG.debug("Content={}, Last={} {}", BufferUtil.toDetailString(content), false, this); - + BufferUtil.clear(buffer); return _handler.content(content, false); } - + // There is normal content with no delimiter ByteBuffer content = buffer.slice(); - + if (LOG.isDebugEnabled()) LOG.debug("Content={}, Last={} {}", BufferUtil.toDetailString(content), false, this); - + BufferUtil.clear(buffer); return _handler.content(content, false); } - - /* ------------------------------------------------------------------------------- */ + private void setState(State state) { - if (DEBUG) + if (debug) LOG.debug("{} --> {}", _state, state); _state = state; } - - /* ------------------------------------------------------------------------------- */ + private void setState(FieldState state) { - if (DEBUG) + if (debug) LOG.debug("{}:{} --> {}", _state, _fieldState, state); _fieldState = state; } - - /* ------------------------------------------------------------------------------- */ + @Override public String toString() { return String.format("%s{s=%s}", getClass().getSimpleName(), _state); } - - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ + /* * Event Handler interface These methods return true if the caller should process the events so far received (eg return from parseNext and call * HttpChannel.handle). If multiple callbacks are called in sequence (eg headerComplete then messageComplete) from the same point in the parsing then it is @@ -694,42 +675,41 @@ public class MultiPartParser default void startPart() { } - + @SuppressWarnings("unused") default void parsedField(String name, String value) { } - + default boolean headerComplete() { return false; } - + @SuppressWarnings("unused") default boolean content(ByteBuffer item, boolean last) { return false; } - + default boolean messageComplete() { return false; } - + default void earlyEOF() { } } - /* ------------------------------------------------------------------------------- */ @SuppressWarnings("serial") private static class IllegalCharacterException extends BadMessageException { - private IllegalCharacterException(State state,HttpTokens.Token token,ByteBuffer buffer) + private IllegalCharacterException(State state, HttpTokens.Token token, ByteBuffer buffer) { - super(400,String.format("Illegal character %s",token)); + super(400, String.format("Illegal character %s", token)); if (LOG.isDebugEnabled()) - LOG.debug(String.format("Illegal character %s in state=%s for buffer %s",token,state,BufferUtil.toDetailString(buffer))); + LOG.debug(String.format("Illegal character %s in state=%s for buffer %s", token, state, BufferUtil.toDetailString(buffer))); } } } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/PathMap.java b/jetty-http/src/main/java/org/eclipse/jetty/http/PathMap.java index 86bd0054935..f18b2877da0 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/PathMap.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/PathMap.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -27,13 +27,12 @@ import java.util.List; import java.util.Map; import java.util.StringTokenizer; import java.util.function.Predicate; -import java.util.function.Predicate; import org.eclipse.jetty.util.ArrayTernaryTrie; import org.eclipse.jetty.util.Trie; import org.eclipse.jetty.util.URIUtil; -/** +/** * URI path map to Object. *

      * This mapping implements the path specification recommended @@ -50,15 +49,15 @@ import org.eclipse.jetty.util.URIUtil; * / - the default path specification. * "" - the / path specification * - * - * Matching is performed in the following order + * + * Matching is performed in the following order *

        *
      1. Exact match.
      2. *
      3. Longest prefix match.
      4. *
      5. Longest suffix match.
      6. *
      7. default.
      8. *
      - * + * *

      * Multiple path specifications can be mapped by providing a list of * specifications. By default this class uses characters ":," as path @@ -71,66 +70,62 @@ import org.eclipse.jetty.util.URIUtil; *

      * This class is not synchronized. If concurrent modifications are * possible then it should be synchronized at a higher level. - * + * * @param the Map.Entry value type - * @deprecated replaced with {@link org.eclipse.jetty.http.pathmap.PathMappings} (this class will be removed in Jetty 10) + * @deprecated replaced with {@link org.eclipse.jetty.http.pathmap.PathMappings} (this class will be removed in Jetty 10) */ @Deprecated -public class PathMap extends HashMap +public class PathMap extends HashMap { - /* ------------------------------------------------------------ */ + private static String __pathSpecSeparators = ":,"; - /* ------------------------------------------------------------ */ - /** Set the path spec separator. + /** + * Set the path spec separator. * Multiple path specification may be included in a single string * if they are separated by the characters set in this string. * By default this class uses ":," characters as path separators. + * * @param s separators */ public static void setPathSpecSeparators(String s) { - __pathSpecSeparators=s; + __pathSpecSeparators = s; } - /* --------------------------------------------------------------- */ - Trie> _prefixMap=new ArrayTernaryTrie<>(false); - Trie> _suffixMap=new ArrayTernaryTrie<>(false); - final Map> _exactMap=new HashMap<>(); + Trie> _prefixMap = new ArrayTernaryTrie<>(false); + Trie> _suffixMap = new ArrayTernaryTrie<>(false); + final Map> _exactMap = new HashMap<>(); - List> _defaultSingletonList=null; - MappedEntry _prefixDefault=null; - MappedEntry _default=null; - boolean _nodefault=false; + List> _defaultSingletonList = null; + MappedEntry _prefixDefault = null; + MappedEntry _default = null; + boolean _nodefault = false; - /* --------------------------------------------------------------- */ public PathMap() { this(11); } - /* --------------------------------------------------------------- */ public PathMap(boolean noDefault) { this(11, noDefault); } - /* --------------------------------------------------------------- */ public PathMap(int capacity) { this(capacity, false); } - /* --------------------------------------------------------------- */ private PathMap(int capacity, boolean noDefault) { super(capacity); - _nodefault=noDefault; + _nodefault = noDefault; } - /* --------------------------------------------------------------- */ - /** + /** * Construct from dictionary PathMap. + * * @param dictMap the map representing the dictionary to build this PathMap from */ public PathMap(Map dictMap) @@ -138,8 +133,9 @@ public class PathMap extends HashMap putAll(dictMap); } - /* --------------------------------------------------------------- */ - /** Add a single path match to the PathMap. + /** + * Add a single path match to the PathMap. + * * @param pathSpec The path specification, or comma separated list of * path specifications. * @param object The object the path maps to @@ -149,58 +145,62 @@ public class PathMap extends HashMap { if ("".equals(pathSpec.trim())) { - MappedEntry entry = new MappedEntry<>("",object); + MappedEntry entry = new MappedEntry<>("", object); entry.setMapped(""); _exactMap.put("", entry); return super.put("", object); } - StringTokenizer tok = new StringTokenizer(pathSpec,__pathSpecSeparators); - O old =null; + StringTokenizer tok = new StringTokenizer(pathSpec, __pathSpecSeparators); + O old = null; while (tok.hasMoreTokens()) { - String spec=tok.nextToken(); + String spec = tok.nextToken(); if (!spec.startsWith("/") && !spec.startsWith("*.")) - throw new IllegalArgumentException("PathSpec "+spec+". must start with '/' or '*.'"); + throw new IllegalArgumentException("PathSpec " + spec + ". must start with '/' or '*.'"); - old = super.put(spec,object); + old = super.put(spec, object); // Make entry that was just created. - MappedEntry entry = new MappedEntry<>(spec,object); + MappedEntry entry = new MappedEntry<>(spec, object); if (entry.getKey().equals(spec)) { if (spec.equals("/*")) - _prefixDefault=entry; + _prefixDefault = entry; else if (spec.endsWith("/*")) { - String mapped=spec.substring(0,spec.length()-2); + String mapped = spec.substring(0, spec.length() - 2); entry.setMapped(mapped); - while (!_prefixMap.put(mapped,entry)) - _prefixMap=new ArrayTernaryTrie<>((ArrayTernaryTrie>)_prefixMap,1.5); + while (!_prefixMap.put(mapped, entry)) + { + _prefixMap = new ArrayTernaryTrie<>((ArrayTernaryTrie>)_prefixMap, 1.5); + } } else if (spec.startsWith("*.")) { - String suffix=spec.substring(2); - while(!_suffixMap.put(suffix,entry)) - _suffixMap=new ArrayTernaryTrie<>((ArrayTernaryTrie>)_suffixMap,1.5); + String suffix = spec.substring(2); + while (!_suffixMap.put(suffix, entry)) + { + _suffixMap = new ArrayTernaryTrie<>((ArrayTernaryTrie>)_suffixMap, 1.5); + } } else if (spec.equals(URIUtil.SLASH)) { if (_nodefault) - _exactMap.put(spec,entry); + _exactMap.put(spec, entry); else { - _default=entry; - _defaultSingletonList=Collections.singletonList(_default); + _default = entry; + _defaultSingletonList = Collections.singletonList(_default); } } else { entry.setMapped(spec); - _exactMap.put(spec,entry); + _exactMap.put(spec, entry); } } } @@ -208,36 +208,37 @@ public class PathMap extends HashMap return old; } - /* ------------------------------------------------------------ */ - /** Get object matched by the path. + /** + * Get object matched by the path. + * * @param path the path. * @return Best matched object or null. */ public O match(String path) { MappedEntry entry = getMatch(path); - if (entry!=null) + if (entry != null) return entry.getValue(); return null; } - - /* --------------------------------------------------------------- */ - /** Get the entry mapped by the best specification. + /** + * Get the entry mapped by the best specification. + * * @param path the path. * @return Map.Entry of the best matched or null. */ public MappedEntry getMatch(String path) { - if (path==null) + if (path == null) return null; - int l=path.length(); + int l = path.length(); - MappedEntry entry=null; + MappedEntry entry = null; //special case - if (l == 1 && path.charAt(0)=='/') + if (l == 1 && path.charAt(0) == '/') { entry = _exactMap.get(""); if (entry != null) @@ -245,35 +246,35 @@ public class PathMap extends HashMap } // try exact match - entry=_exactMap.get(path); - if (entry!=null) + entry = _exactMap.get(path); + if (entry != null) return entry; // prefix search - int i=l; - final Trie> prefix_map=_prefixMap; - while(i>=0) + int i = l; + final Trie> prefix_map = _prefixMap; + while (i >= 0) { - entry=prefix_map.getBest(path,0,i); - if (entry==null) + entry = prefix_map.getBest(path, 0, i); + if (entry == null) break; String key = entry.getKey(); - if (key.length()-2>=path.length() || path.charAt(key.length()-2)=='/') + if (key.length() - 2 >= path.length() || path.charAt(key.length() - 2) == '/') return entry; - i=key.length()-3; + i = key.length() - 3; } // Prefix Default - if (_prefixDefault!=null) + if (_prefixDefault != null) return _prefixDefault; // Extension search - i=0; - final Trie> suffix_map=_suffixMap; - while ((i=path.indexOf('.',i+1))>0) + i = 0; + final Trie> suffix_map = _suffixMap; + while ((i = path.indexOf('.', i + 1)) > 0) { - entry=suffix_map.get(path,i+1,l-i-1); - if (entry!=null) + entry = suffix_map.get(path, i + 1, l - i - 1); + if (entry != null) return entry; } @@ -281,102 +282,102 @@ public class PathMap extends HashMap return _default; } - /* --------------------------------------------------------------- */ - /** Get all entries matched by the path. + /** + * Get all entries matched by the path. * Best match first. + * * @param path Path to match * @return List of Map.Entry instances key=pathSpec */ - public List> getMatches(String path) + public List> getMatches(String path) { MappedEntry entry; - List> entries=new ArrayList<>(); + List> entries = new ArrayList<>(); - if (path==null) + if (path == null) return entries; - if (path.length()==0) + if (path.isEmpty()) return _defaultSingletonList; // try exact match - entry=_exactMap.get(path); - if (entry!=null) + entry = _exactMap.get(path); + if (entry != null) entries.add(entry); // prefix search - int l=path.length(); - int i=l; - final Trie> prefix_map=_prefixMap; - while(i>=0) + int l = path.length(); + int i = l; + final Trie> prefix_map = _prefixMap; + while (i >= 0) { - entry=prefix_map.getBest(path,0,i); - if (entry==null) + entry = prefix_map.getBest(path, 0, i); + if (entry == null) break; String key = entry.getKey(); - if (key.length()-2>=path.length() || path.charAt(key.length()-2)=='/') + if (key.length() - 2 >= path.length() || path.charAt(key.length() - 2) == '/') entries.add(entry); - i=key.length()-3; + i = key.length() - 3; } // Prefix Default - if (_prefixDefault!=null) + if (_prefixDefault != null) entries.add(_prefixDefault); // Extension search - i=0; - final Trie> suffix_map=_suffixMap; - while ((i=path.indexOf('.',i+1))>0) + i = 0; + final Trie> suffix_map = _suffixMap; + while ((i = path.indexOf('.', i + 1)) > 0) { - entry=suffix_map.get(path,i+1,l-i-1); - if (entry!=null) + entry = suffix_map.get(path, i + 1, l - i - 1); + if (entry != null) entries.add(entry); } // root match if ("/".equals(path)) { - entry=_exactMap.get(""); - if (entry!=null) + entry = _exactMap.get(""); + if (entry != null) entries.add(entry); } - + // Default - if (_default!=null) + if (_default != null) entries.add(_default); return entries; } - - /* --------------------------------------------------------------- */ - /** Return whether the path matches any entries in the PathMap, + /** + * Return whether the path matches any entries in the PathMap, * excluding the default entry + * * @param path Path to match * @return Whether the PathMap contains any entries that match this */ public boolean containsMatch(String path) { MappedEntry match = getMatch(path); - return match!=null && !match.equals(_default); + return match != null && !match.equals(_default); } - /* --------------------------------------------------------------- */ @Override public O remove(Object pathSpec) { - if (pathSpec!=null) + if (pathSpec != null) { - String spec=(String) pathSpec; + String spec = (String)pathSpec; if (spec.equals("/*")) - _prefixDefault=null; + _prefixDefault = null; else if (spec.endsWith("/*")) - _prefixMap.remove(spec.substring(0,spec.length()-2)); + _prefixMap.remove(spec.substring(0, spec.length() - 2)); else if (spec.startsWith("*.")) _suffixMap.remove(spec.substring(2)); else if (spec.equals(URIUtil.SLASH)) { - _default=null; - _defaultSingletonList=null; + _default = null; + _defaultSingletonList = null; } else _exactMap.remove(spec); @@ -384,20 +385,18 @@ public class PathMap extends HashMap return super.remove(pathSpec); } - /* --------------------------------------------------------------- */ @Override public void clear() { _exactMap.clear(); - _prefixMap=new ArrayTernaryTrie<>(false); - _suffixMap=new ArrayTernaryTrie<>(false); - _default=null; - _defaultSingletonList=null; - _prefixDefault=null; + _prefixMap = new ArrayTernaryTrie<>(false); + _suffixMap = new ArrayTernaryTrie<>(false); + _default = null; + _defaultSingletonList = null; + _prefixDefault = null; super.clear(); } - /* --------------------------------------------------------------- */ /** * @param pathSpec the path spec * @param path the path @@ -408,49 +407,45 @@ public class PathMap extends HashMap return match(pathSpec, path, false); } - /* --------------------------------------------------------------- */ /** * @param pathSpec the path spec * @param path the path - * @param noDefault true to not handle the default path "/" special, false to allow matcher rules to run + * @param noDefault true to not handle the default path "/" special, false to allow matcher rules to run * @return true if match. */ public static boolean match(String pathSpec, String path, boolean noDefault) { - if (pathSpec.length()==0) + if (pathSpec.isEmpty()) return "/".equals(path); - + char c = pathSpec.charAt(0); - if (c=='/') + if (c == '/') { - if (!noDefault && pathSpec.length()==1 || pathSpec.equals(path)) + if (!noDefault && pathSpec.length() == 1 || pathSpec.equals(path)) return true; - if(isPathWildcardMatch(pathSpec, path)) - return true; + return isPathWildcardMatch(pathSpec, path); } - else if (c=='*') - return path.regionMatches(path.length()-pathSpec.length()+1, - pathSpec,1,pathSpec.length()-1); + else if (c == '*') + return path.regionMatches(path.length() - pathSpec.length() + 1, + pathSpec, 1, pathSpec.length() - 1); return false; } - /* --------------------------------------------------------------- */ private static boolean isPathWildcardMatch(String pathSpec, String path) { // For a spec of "/foo/*" match "/foo" , "/foo/..." but not "/foobar" - int cpl=pathSpec.length()-2; - if (pathSpec.endsWith("/*") && path.regionMatches(0,pathSpec,0,cpl)) + int cpl = pathSpec.length() - 2; + if (pathSpec.endsWith("/*") && path.regionMatches(0, pathSpec, 0, cpl)) { - if (path.length()==cpl || '/'==path.charAt(cpl)) - return true; + return path.length() == cpl || '/' == path.charAt(cpl); } return false; } - - /* --------------------------------------------------------------- */ - /** Return the portion of a path that matches a path spec. + /** + * Return the portion of a path that matches a path spec. + * * @param pathSpec the path spec * @param path the path * @return null if no match at all. @@ -459,28 +454,29 @@ public class PathMap extends HashMap { char c = pathSpec.charAt(0); - if (c=='/') + if (c == '/') { - if (pathSpec.length()==1) + if (pathSpec.length() == 1) return path; if (pathSpec.equals(path)) return path; if (isPathWildcardMatch(pathSpec, path)) - return path.substring(0,pathSpec.length()-2); + return path.substring(0, pathSpec.length() - 2); } - else if (c=='*') + else if (c == '*') { - if (path.regionMatches(path.length()-(pathSpec.length()-1), - pathSpec,1,pathSpec.length()-1)) + if (path.regionMatches(path.length() - (pathSpec.length() - 1), + pathSpec, 1, pathSpec.length() - 1)) return path; } return null; } - /* --------------------------------------------------------------- */ - /** Return the portion of a path that is after a path spec. + /** + * Return the portion of a path that is after a path spec. + * * @param pathSpec the path spec * @param path the path * @return The path info string @@ -492,9 +488,9 @@ public class PathMap extends HashMap char c = pathSpec.charAt(0); - if (c=='/') + if (c == '/') { - if (pathSpec.length()==1) + if (pathSpec.length() == 1) return null; boolean wildcard = isPathWildcardMatch(pathSpec, path); @@ -505,49 +501,45 @@ public class PathMap extends HashMap if (wildcard) { - if (path.length()==pathSpec.length()-2) + if (path.length() == pathSpec.length() - 2) return null; - return path.substring(pathSpec.length()-2); + return path.substring(pathSpec.length() - 2); } } return null; } - - /* ------------------------------------------------------------ */ - /** Relative path. + /** + * Relative path. + * * @param base The base the path is relative to. * @param pathSpec The spec of the path segment to ignore. * @param path the additional path * @return base plus path with pathspec removed */ public static String relativePath(String base, - String pathSpec, - String path ) + String pathSpec, + String path) { - String info=pathInfo(pathSpec,path); - if (info==null) - info=path; + String info = pathInfo(pathSpec, path); + if (info == null) + info = path; - if( info.startsWith( "./")) - info = info.substring( 2); - if( base.endsWith( URIUtil.SLASH)) - if( info.startsWith( URIUtil.SLASH)) + if (info.startsWith("./")) + info = info.substring(2); + if (base.endsWith(URIUtil.SLASH)) + if (info.startsWith(URIUtil.SLASH)) path = base + info.substring(1); else path = base + info; + else if (info.startsWith(URIUtil.SLASH)) + path = base + info; else - if( info.startsWith( URIUtil.SLASH)) - path = base + info; - else - path = base + URIUtil.SLASH + info; + path = base + URIUtil.SLASH + info; return path; } - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ - public static class MappedEntry implements Map.Entry + public static class MappedEntry implements Map.Entry { private final String key; private final O value; @@ -555,8 +547,8 @@ public class PathMap extends HashMap MappedEntry(String key, O value) { - this.key=key; - this.value=value; + this.key = key; + this.value = value; } @Override @@ -580,7 +572,7 @@ public class PathMap extends HashMap @Override public String toString() { - return key+"="+value; + return key + "=" + value; } public String getMapped() @@ -593,11 +585,11 @@ public class PathMap extends HashMap this.mapped = mapped; } } - + public static class PathSet extends AbstractSet implements Predicate { private final PathMap _map = new PathMap<>(); - + @Override public Iterator iterator() { @@ -609,34 +601,34 @@ public class PathMap extends HashMap { return _map.size(); } - + @Override public boolean add(String item) { - return _map.put(item,Boolean.TRUE)==null; - } - - @Override - public boolean remove(Object item) - { - return _map.remove(item)!=null; + return _map.put(item, Boolean.TRUE) == null; } @Override - public boolean contains(Object o) - { - return _map.containsKey(o); + public boolean remove(Object item) + { + return _map.remove(item) != null; } - + + @Override + public boolean contains(Object o) + { + return _map.containsKey(o); + } + @Override public boolean test(String s) { return _map.containsMatch(s); } - - public boolean containsMatch(String s) - { - return _map.containsMatch(s); + + public boolean containsMatch(String s) + { + return _map.containsMatch(s); } } } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java index 4bff0efdf92..cf9cf1c0752 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,12 +16,10 @@ // ======================================================================== // - package org.eclipse.jetty.http; import java.nio.ByteBuffer; import java.util.ArrayList; -import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.ServiceLoader; @@ -29,23 +27,22 @@ import java.util.ServiceLoader; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; - -/* ------------------------------------------------------------ */ -/** Pre encoded HttpField. - *

      A HttpField that will be cached and used many times can be created as +/** + * Pre encoded HttpField. + *

      An HttpField that will be cached and used many times can be created as * a {@link PreEncodedHttpField}, which will use the {@link HttpFieldPreEncoder} - * instances discovered by the {@link ServiceLoader} to pre-encode the header - * for each version of HTTP in use. This will save garbage + * instances discovered by the {@link ServiceLoader} to pre-encode the header + * for each version of HTTP in use. This will save garbage * and CPU each time the field is encoded into a response. *

      */ public class PreEncodedHttpField extends HttpField { - private final static Logger LOG = Log.getLogger(PreEncodedHttpField.class); - private final static HttpFieldPreEncoder[] __encoders; - + private static final Logger LOG = Log.getLogger(PreEncodedHttpField.class); + private static final HttpFieldPreEncoder[] __encoders; + static - { + { List encoders = new ArrayList<>(); Iterator iter = ServiceLoader.load(HttpFieldPreEncoder.class).iterator(); while (iter.hasNext()) @@ -53,32 +50,32 @@ public class PreEncodedHttpField extends HttpField try { HttpFieldPreEncoder encoder = iter.next(); - if (index(encoder.getHttpVersion())>=0) + if (index(encoder.getHttpVersion()) >= 0) encoders.add(encoder); } - catch(Error|RuntimeException e) + catch (Error | RuntimeException e) { LOG.debug(e); } } - LOG.debug("HttpField encoders loaded: {}",encoders); - int size=encoders.size(); - - __encoders = new HttpFieldPreEncoder[size==0?1:size]; - for (HttpFieldPreEncoder e:encoders) + LOG.debug("HttpField encoders loaded: {}", encoders); + int size = encoders.size(); + + __encoders = new HttpFieldPreEncoder[size == 0 ? 1 : size]; + for (HttpFieldPreEncoder e : encoders) { int i = index(e.getHttpVersion()); - if (__encoders[i]==null) + if (__encoders[i] == null) __encoders[i] = e; else - LOG.warn("multiple PreEncoders for "+e.getHttpVersion()); + LOG.warn("multiple PreEncoders for " + e.getHttpVersion()); } - + // Always support HTTP1 - if (__encoders[0]==null) - __encoders[0] = new Http1FieldPreEncoder(); + if (__encoders[0] == null) + __encoders[0] = new Http1FieldPreEncoder(); } - + private static int index(HttpVersion version) { switch (version) @@ -94,26 +91,28 @@ public class PreEncodedHttpField extends HttpField return -1; } } - - private final byte[][] _encodedField=new byte[__encoders.length][]; - public PreEncodedHttpField(HttpHeader header,String name,String value) + private final byte[][] _encodedField = new byte[__encoders.length][]; + + public PreEncodedHttpField(HttpHeader header, String name, String value) { - super(header,name, value); - for (int i=0;i<__encoders.length;i++) - _encodedField[i]=__encoders[i].getEncodedField(header,name,value); + super(header, name, value); + for (int i = 0; i < __encoders.length; i++) + { + _encodedField[i] = __encoders[i].getEncodedField(header, name, value); + } } - - public PreEncodedHttpField(HttpHeader header,String value) + + public PreEncodedHttpField(HttpHeader header, String value) { - this(header,header.asString(),value); + this(header, header.asString(), value); } - - public PreEncodedHttpField(String name,String value) + + public PreEncodedHttpField(String name, String value) { - this(null,name,value); + this(null, name, value); } - + public void putTo(ByteBuffer bufferInFillMode, HttpVersion version) { bufferInFillMode.put(_encodedField[index(version)]); diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/PrecompressedHttpContent.java b/jetty-http/src/main/java/org/eclipse/jetty/http/PrecompressedHttpContent.java index 3a52aaab406..e7fceabea63 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/PrecompressedHttpContent.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/PrecompressedHttpContent.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -27,7 +27,6 @@ import java.util.Map; import org.eclipse.jetty.http.MimeTypes.Type; import org.eclipse.jetty.util.resource.Resource; -/* ------------------------------------------------------------ */ public class PrecompressedHttpContent implements HttpContent { private final HttpContent _content; @@ -66,7 +65,7 @@ public class PrecompressedHttpContent implements HttpContent @Override public HttpField getETag() { - return new HttpField(HttpHeader.ETAG,getETagValue()); + return new HttpField(HttpHeader.ETAG, getETagValue()); } @Override @@ -168,10 +167,10 @@ public class PrecompressedHttpContent implements HttpContent @Override public String toString() { - return String.format("PrecompressedHttpContent@%x{e=%s,r=%s|%s,lm=%s|%s,ct=%s}",hashCode(),_format._encoding, - _content.getResource(),_precompressedContent.getResource(), - _content.getResource().lastModified(),_precompressedContent.getResource().lastModified(), - getContentType()); + return String.format("PrecompressedHttpContent@%x{e=%s,r=%s|%s,lm=%s|%s,ct=%s}", hashCode(), _format._encoding, + _content.getResource(), _precompressedContent.getResource(), + _content.getResource().lastModified(), _precompressedContent.getResource().lastModified(), + getContentType()); } @Override @@ -179,4 +178,4 @@ public class PrecompressedHttpContent implements HttpContent { return null; } -} \ No newline at end of file +} diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedCSV.java b/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedCSV.java index 9fbb36ab86d..ae6ee4a2673 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedCSV.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedCSV.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -22,236 +22,36 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import org.eclipse.jetty.util.QuotedStringTokenizer; - -/* ------------------------------------------------------------ */ /** * Implements a quoted comma separated list of values * in accordance with RFC7230. * OWS is removed and quoted characters ignored for parsing. + * * @see "https://tools.ietf.org/html/rfc7230#section-3.2.6" * @see "https://tools.ietf.org/html/rfc7230#section-7" */ -public class QuotedCSV implements Iterable -{ - private enum State { VALUE, PARAM_NAME, PARAM_VALUE}; - +public class QuotedCSV extends QuotedCSVParser implements Iterable +{ protected final List _values = new ArrayList<>(); - protected final boolean _keepQuotes; - - /* ------------------------------------------------------------ */ + public QuotedCSV(String... values) { - this(true,values); + this(true, values); } - - /* ------------------------------------------------------------ */ - public QuotedCSV(boolean keepQuotes,String... values) + + public QuotedCSV(boolean keepQuotes, String... values) { - _keepQuotes=keepQuotes; - for (String v:values) - addValue(v); - } - - /* ------------------------------------------------------------ */ - /** Add and parse a value string(s) - * @param value A value that may contain one or more Quoted CSV items. - */ - public void addValue(String value) - { - if (value == null) - return; - - StringBuffer buffer = new StringBuffer(); - - int l=value.length(); - State state=State.VALUE; - boolean quoted=false; - boolean sloshed=false; - int nws_length=0; - int last_length=0; - int value_length=-1; - int param_name=-1; - int param_value=-1; - - for (int i=0;i<=l;i++) + super(keepQuotes); + for (String v : values) { - char c=i==l?0:value.charAt(i); - - // Handle quoting https://tools.ietf.org/html/rfc7230#section-3.2.6 - if (quoted && c!=0) - { - if (sloshed) - sloshed=false; - else - { - switch(c) - { - case '\\': - sloshed=true; - if (!_keepQuotes) - continue; - break; - case '"': - quoted=false; - if (!_keepQuotes) - continue; - break; - } - } - - buffer.append(c); - nws_length=buffer.length(); - continue; - } - - // Handle common cases - switch(c) - { - case ' ': - case '\t': - if (buffer.length()>last_length) // not leading OWS - buffer.append(c); - continue; - - case '"': - quoted=true; - if (_keepQuotes) - { - if (state==State.PARAM_VALUE && param_value<0) - param_value=nws_length; - buffer.append(c); - } - else if (state==State.PARAM_VALUE && param_value<0) - param_value=nws_length; - nws_length=buffer.length(); - continue; - - case ';': - buffer.setLength(nws_length); // trim following OWS - if (state==State.VALUE) - { - parsedValue(buffer); - value_length=buffer.length(); - } - else - parsedParam(buffer,value_length,param_name,param_value); - nws_length=buffer.length(); - param_name=param_value=-1; - buffer.append(c); - last_length=++nws_length; - state=State.PARAM_NAME; - continue; - - case ',': - case 0: - if (nws_length>0) - { - buffer.setLength(nws_length); // trim following OWS - switch(state) - { - case VALUE: - parsedValue(buffer); - value_length=buffer.length(); - break; - case PARAM_NAME: - case PARAM_VALUE: - parsedParam(buffer,value_length,param_name,param_value); - break; - } - _values.add(buffer.toString()); - } - buffer.setLength(0); - last_length=0; - nws_length=0; - value_length=param_name=param_value=-1; - state=State.VALUE; - continue; - - case '=': - switch (state) - { - case VALUE: - // It wasn't really a value, it was a param name - value_length=param_name=0; - buffer.setLength(nws_length); // trim following OWS - String param = buffer.toString(); - buffer.setLength(0); - parsedValue(buffer); - value_length=buffer.length(); - buffer.append(param); - buffer.append(c); - last_length=++nws_length; - state=State.PARAM_VALUE; - continue; - - case PARAM_NAME: - buffer.setLength(nws_length); // trim following OWS - buffer.append(c); - last_length=++nws_length; - state=State.PARAM_VALUE; - continue; - - case PARAM_VALUE: - if (param_value<0) - param_value=nws_length; - buffer.append(c); - nws_length=buffer.length(); - continue; - } - continue; - - default: - { - switch (state) - { - case VALUE: - { - buffer.append(c); - nws_length=buffer.length(); - continue; - } - - case PARAM_NAME: - { - if (param_name<0) - param_name=nws_length; - buffer.append(c); - nws_length=buffer.length(); - continue; - } - - case PARAM_VALUE: - { - if (param_value<0) - param_value=nws_length; - buffer.append(c); - nws_length=buffer.length(); - continue; - } - } - } - } + addValue(v); } } - /** - * Called when a value has been parsed - * @param buffer Containing the trimmed value, which may be mutated - */ - protected void parsedValue(StringBuffer buffer) - { - } - - /** - * Called when a parameter has been parsed - * @param buffer Containing the trimmed value and all parameters, which may be mutated - * @param valueLength The length of the value - * @param paramName The index of the start of the parameter just parsed - * @param paramValue The index of the start of the parameter value just parsed, or -1 - */ - protected void parsedParam(StringBuffer buffer, int valueLength, int paramName, int paramValue) + @Override + protected void parsedValueAndParams(StringBuffer buffer) { + _values.add(buffer.toString()); } public int size() @@ -268,67 +68,21 @@ public class QuotedCSV implements Iterable { return _values; } - + @Override public Iterator iterator() { return _values.iterator(); } - - public static String unquote(String s) - { - // handle trivial cases - int l=s.length(); - if (s==null || l==0) - return s; - - // Look for any quotes - int i=0; - for (;i list = new ArrayList<>(); for (String s : this) + { list.add(s); + } return list.toString(); } } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedCSVParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedCSVParser.java new file mode 100644 index 00000000000..3cdf5e5af7c --- /dev/null +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedCSVParser.java @@ -0,0 +1,303 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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; + +/** + * Implements a quoted comma separated list parser + * in accordance with RFC7230. + * OWS is removed and quoted characters ignored for parsing. + * + * @see "https://tools.ietf.org/html/rfc7230#section-3.2.6" + * @see "https://tools.ietf.org/html/rfc7230#section-7" + */ +public abstract class QuotedCSVParser +{ + private enum State + { + VALUE, PARAM_NAME, PARAM_VALUE + } + + protected final boolean _keepQuotes; + + public QuotedCSVParser(boolean keepQuotes) + { + _keepQuotes = keepQuotes; + } + + public static String unquote(String s) + { + // handle trivial cases + int l = s.length(); + if (s == null || l == 0) + return s; + + // Look for any quotes + int i = 0; + for (; i < l; i++) + { + char c = s.charAt(i); + if (c == '"') + break; + } + if (i == l) + return s; + + boolean quoted = true; + boolean sloshed = false; + StringBuffer buffer = new StringBuffer(); + buffer.append(s, 0, i); + i++; + for (; i < l; i++) + { + char c = s.charAt(i); + if (quoted) + { + if (sloshed) + { + buffer.append(c); + sloshed = false; + } + else if (c == '"') + quoted = false; + else if (c == '\\') + sloshed = true; + else + buffer.append(c); + } + else if (c == '"') + quoted = true; + else + buffer.append(c); + } + return buffer.toString(); + } + + /** + * Add and parse a value string(s) + * + * @param value A value that may contain one or more Quoted CSV items. + */ + public void addValue(String value) + { + if (value == null) + return; + + StringBuffer buffer = new StringBuffer(); + + int l = value.length(); + State state = State.VALUE; + boolean quoted = false; + boolean sloshed = false; + int nwsLength = 0; + int lastLength = 0; + int valueLength = -1; + int paramName = -1; + int paramValue = -1; + + for (int i = 0; i <= l; i++) + { + char c = i == l ? 0 : value.charAt(i); + + // Handle quoting https://tools.ietf.org/html/rfc7230#section-3.2.6 + if (quoted && c != 0) + { + if (sloshed) + sloshed = false; + else + { + switch (c) + { + case '\\': + sloshed = true; + if (!_keepQuotes) + continue; + break; + case '"': + quoted = false; + if (!_keepQuotes) + continue; + break; + } + } + + buffer.append(c); + nwsLength = buffer.length(); + continue; + } + + // Handle common cases + switch (c) + { + case ' ': + case '\t': + if (buffer.length() > lastLength) // not leading OWS + buffer.append(c); + continue; + + case '"': + quoted = true; + if (_keepQuotes) + { + if (state == State.PARAM_VALUE && paramValue < 0) + paramValue = nwsLength; + buffer.append(c); + } + else if (state == State.PARAM_VALUE && paramValue < 0) + paramValue = nwsLength; + nwsLength = buffer.length(); + continue; + + case ';': + buffer.setLength(nwsLength); // trim following OWS + if (state == State.VALUE) + { + parsedValue(buffer); + valueLength = buffer.length(); + } + else + parsedParam(buffer, valueLength, paramName, paramValue); + nwsLength = buffer.length(); + paramName = paramValue = -1; + buffer.append(c); + lastLength = ++nwsLength; + state = State.PARAM_NAME; + continue; + + case ',': + case 0: + if (nwsLength > 0) + { + buffer.setLength(nwsLength); // trim following OWS + switch (state) + { + case VALUE: + parsedValue(buffer); + valueLength = buffer.length(); + break; + case PARAM_NAME: + case PARAM_VALUE: + parsedParam(buffer, valueLength, paramName, paramValue); + break; + } + parsedValueAndParams(buffer); + } + buffer.setLength(0); + lastLength = 0; + nwsLength = 0; + valueLength = paramName = paramValue = -1; + state = State.VALUE; + continue; + + case '=': + switch (state) + { + case VALUE: + // It wasn't really a value, it was a param name + valueLength = paramName = 0; + buffer.setLength(nwsLength); // trim following OWS + String param = buffer.toString(); + buffer.setLength(0); + parsedValue(buffer); + valueLength = buffer.length(); + buffer.append(param); + buffer.append(c); + lastLength = ++nwsLength; + state = State.PARAM_VALUE; + continue; + + case PARAM_NAME: + buffer.setLength(nwsLength); // trim following OWS + buffer.append(c); + lastLength = ++nwsLength; + state = State.PARAM_VALUE; + continue; + + case PARAM_VALUE: + if (paramValue < 0) + paramValue = nwsLength; + buffer.append(c); + nwsLength = buffer.length(); + continue; + } + continue; + + default: + { + switch (state) + { + case VALUE: + { + buffer.append(c); + nwsLength = buffer.length(); + continue; + } + + case PARAM_NAME: + { + if (paramName < 0) + paramName = nwsLength; + buffer.append(c); + nwsLength = buffer.length(); + continue; + } + + case PARAM_VALUE: + { + if (paramValue < 0) + paramValue = nwsLength; + buffer.append(c); + nwsLength = buffer.length(); + continue; + } + } + } + } + } + } + + /** + * Called when a value and it's parameters has been parsed + * + * @param buffer Containing the trimmed value and parameters + */ + protected void parsedValueAndParams(StringBuffer buffer) + { + } + + /** + * Called when a value has been parsed (prior to any parameters) + * + * @param buffer Containing the trimmed value, which may be mutated + */ + protected void parsedValue(StringBuffer buffer) + { + } + + /** + * Called when a parameter has been parsed + * + * @param buffer Containing the trimmed value and all parameters, which may be mutated + * @param valueLength The length of the value + * @param paramName The index of the start of the parameter just parsed + * @param paramValue The index of the start of the parameter value just parsed, or -1 + */ + protected void parsedParam(StringBuffer buffer, int valueLength, int paramName, int paramValue) + { + } +} diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedQualityCSV.java b/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedQualityCSV.java index 4f9ff72ed6c..2e4a97058df 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedQualityCSV.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedQualityCSV.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,66 +18,69 @@ package org.eclipse.jetty.http; -import static java.lang.Integer.MIN_VALUE; - import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import java.util.function.Function; +import java.util.function.ToIntFunction; + +import org.eclipse.jetty.util.log.Log; + +import static java.lang.Integer.MIN_VALUE; -/* ------------------------------------------------------------ */ /** * Implements a quoted comma separated list of quality values * in accordance with RFC7230 and RFC7231. - * Values are returned sorted in quality order, with OWS and the + * Values are returned sorted in quality order, with OWS and the * quality parameters removed. + * * @see "https://tools.ietf.org/html/rfc7230#section-3.2.6" * @see "https://tools.ietf.org/html/rfc7230#section-7" * @see "https://tools.ietf.org/html/rfc7231#section-5.3.1" */ public class QuotedQualityCSV extends QuotedCSV implements Iterable -{ - private final static Double ZERO=new Double(0.0); - private final static Double ONE=new Double(1.0); - - +{ /** - * Function to apply a most specific MIME encoding secondary ordering + * Lambda to apply a most specific MIME encoding secondary ordering. + * + * @see "https://tools.ietf.org/html/rfc7231#section-5.3.2" */ - public static Function MOST_SPECIFIC = new Function() + public static ToIntFunction MOST_SPECIFIC_MIME_ORDERING = s -> { - @Override - public Integer apply(String s) - { - String[] elements = s.split("/"); - return 1000000*elements.length+1000*elements[0].length()+elements[elements.length-1].length(); - } + if ("*/*".equals(s)) + return 0; + if (s.endsWith("/*")) + return 1; + if (s.indexOf(';') < 0) + return 2; + return 3; }; - + private final List _quality = new ArrayList<>(); private boolean _sorted = false; - private final Function _secondaryOrdering; - - /* ------------------------------------------------------------ */ + private final ToIntFunction _secondaryOrdering; + /** * Sorts values with equal quality according to the length of the value String. */ public QuotedQualityCSV() { - this((s) -> 0); + this((ToIntFunction)null); } - /* ------------------------------------------------------------ */ /** * Sorts values with equal quality according to given order. + * * @param preferredOrder Array indicating the preferred order of known values */ public QuotedQualityCSV(String[] preferredOrder) { - this((s) -> { - for (int i=0;i + { + for (int i = 0; i < preferredOrder.length; ++i) + { if (preferredOrder[i].equals(s)) - return preferredOrder.length-i; + return preferredOrder.length - i; + } if ("*".equals(s)) return preferredOrder.length; @@ -86,52 +89,54 @@ public class QuotedQualityCSV extends QuotedCSV implements Iterable }); } - /* ------------------------------------------------------------ */ /** * Orders values with equal quality with the given function. + * * @param secondaryOrdering Function to apply an ordering other than specified by quality */ - public QuotedQualityCSV(Function secondaryOrdering) + public QuotedQualityCSV(ToIntFunction secondaryOrdering) { - this._secondaryOrdering = secondaryOrdering; + this._secondaryOrdering = secondaryOrdering == null ? s -> 0 : secondaryOrdering; } - - /* ------------------------------------------------------------ */ + @Override protected void parsedValue(StringBuffer buffer) { super.parsedValue(buffer); - _quality.add(ONE); + + // Assume a quality of ONE + _quality.add(1.0D); } - /* ------------------------------------------------------------ */ @Override protected void parsedParam(StringBuffer buffer, int valueLength, int paramName, int paramValue) { - if (paramName<0) + if (paramName < 0) { - if (buffer.charAt(buffer.length()-1)==';') - buffer.setLength(buffer.length()-1); + if (buffer.charAt(buffer.length() - 1) == ';') + buffer.setLength(buffer.length() - 1); } - else if (paramValue>=0 && - buffer.charAt(paramName)=='q' && paramValue>paramName && - buffer.length()>=paramName && buffer.charAt(paramName+1)=='=') + else if (paramValue >= 0 && + buffer.charAt(paramName) == 'q' && paramValue > paramName && + buffer.length() >= paramName && buffer.charAt(paramName + 1) == '=') { Double q; try { - q=(_keepQuotes && buffer.charAt(paramValue)=='"') - ?new Double(buffer.substring(paramValue+1,buffer.length()-1)) - :new Double(buffer.substring(paramValue)); + q = (_keepQuotes && buffer.charAt(paramValue) == '"') + ? Double.valueOf(buffer.substring(paramValue + 1, buffer.length() - 1)) + : Double.valueOf(buffer.substring(paramValue)); } - catch(Exception e) + catch (Exception e) { - q=ZERO; - } - buffer.setLength(Math.max(0,paramName-1)); - - if (!ONE.equals(q)) - _quality.set(_quality.size()-1,q); + Log.getLogger(QuotedQualityCSV.class).ignore(e); + q = 0.0D; + } + buffer.setLength(Math.max(0, paramName - 1)); + + if (q != 1.0D) + // replace assumed quality + _quality.set(_quality.size() - 1, q); } } @@ -142,7 +147,7 @@ public class QuotedQualityCSV extends QuotedCSV implements Iterable sort(); return _values; } - + @Override public Iterator iterator() { @@ -153,38 +158,38 @@ public class QuotedQualityCSV extends QuotedCSV implements Iterable protected void sort() { - _sorted=true; + _sorted = true; - Double last = ZERO; + Double last = 0.0D; int lastSecondaryOrder = Integer.MIN_VALUE; - for (int i = _values.size(); i-- > 0;) + for (int i = _values.size(); i-- > 0; ) { String v = _values.get(i); Double q = _quality.get(i); - int compare=last.compareTo(q); - if (compare>0 || (compare==0 && _secondaryOrdering.apply(v) 0 || (compare == 0 && _secondaryOrdering.applyAsInt(v) < lastSecondaryOrder)) { _values.set(i, _values.get(i + 1)); _values.set(i + 1, v); _quality.set(i, _quality.get(i + 1)); _quality.set(i + 1, q); - last = ZERO; - lastSecondaryOrder=0; + last = 0.0D; + lastSecondaryOrder = 0; i = _values.size(); continue; } - last=q; - lastSecondaryOrder=_secondaryOrdering.apply(v); + last = q; + lastSecondaryOrder = _secondaryOrdering.applyAsInt(v); } - - int last_element=_quality.size(); - while(last_element>0 && _quality.get(--last_element).equals(ZERO)) + + int lastElement = _quality.size(); + while (lastElement > 0 && _quality.get(--lastElement).equals(0.0D)) { - _quality.remove(last_element); - _values.remove(last_element); + _quality.remove(lastElement); + _values.remove(lastElement); } } } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/ResourceHttpContent.java b/jetty-http/src/main/java/org/eclipse/jetty/http/ResourceHttpContent.java index 5ea4365975f..22e404a0df8 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/ResourceHttpContent.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/ResourceHttpContent.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -29,11 +29,10 @@ import org.eclipse.jetty.http.MimeTypes.Type; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.resource.Resource; - -/* ------------------------------------------------------------ */ -/** HttpContent created from a {@link Resource}. +/** + * HttpContent created from a {@link Resource}. *

      The HttpContent is used to server static content that is not - * cached. So fields and values are only generated as need be an not + * cached. So fields and values are only generated as need be an not * kept for reuse

      */ public class ResourceHttpContent implements HttpContent @@ -44,23 +43,20 @@ public class ResourceHttpContent implements HttpContent Map _precompressedContents; String _etag; - /* ------------------------------------------------------------ */ public ResourceHttpContent(final Resource resource, final String contentType) { - this(resource,contentType,-1,null); + this(resource, contentType, -1, null); } - /* ------------------------------------------------------------ */ public ResourceHttpContent(final Resource resource, final String contentType, int maxBuffer) { - this(resource,contentType,maxBuffer,null); + this(resource, contentType, maxBuffer, null); } - - /* ------------------------------------------------------------ */ + public ResourceHttpContent(final Resource resource, final String contentType, int maxBuffer, Map precompressedContents) { - _resource=resource; - _contentType=contentType; + _resource = resource; + _contentType = contentType; _maxBuffer = maxBuffer; if (precompressedContents == null) { @@ -71,170 +67,149 @@ public class ResourceHttpContent implements HttpContent _precompressedContents = new HashMap<>(precompressedContents.size()); for (Map.Entry entry : precompressedContents.entrySet()) { - _precompressedContents.put(entry.getKey(),new PrecompressedHttpContent(this,entry.getValue(),entry.getKey())); + _precompressedContents.put(entry.getKey(), new PrecompressedHttpContent(this, entry.getValue(), entry.getKey())); } } } - /* ------------------------------------------------------------ */ @Override public String getContentTypeValue() { return _contentType; } - - /* ------------------------------------------------------------ */ + @Override public HttpField getContentType() { - return _contentType==null?null:new HttpField(HttpHeader.CONTENT_TYPE,_contentType); + return _contentType == null ? null : new HttpField(HttpHeader.CONTENT_TYPE, _contentType); } - /* ------------------------------------------------------------ */ @Override public HttpField getContentEncoding() { return null; } - /* ------------------------------------------------------------ */ @Override public String getContentEncodingValue() { return null; } - /* ------------------------------------------------------------ */ @Override public String getCharacterEncoding() { - return _contentType==null?null:MimeTypes.getCharsetFromContentType(_contentType); + return _contentType == null ? null : MimeTypes.getCharsetFromContentType(_contentType); } - /* ------------------------------------------------------------ */ @Override public Type getMimeType() { - return _contentType==null?null:MimeTypes.CACHE.get(MimeTypes.getContentTypeWithoutCharset(_contentType)); + return _contentType == null ? null : MimeTypes.CACHE.get(MimeTypes.getContentTypeWithoutCharset(_contentType)); } - - /* ------------------------------------------------------------ */ + @Override public HttpField getLastModified() { long lm = _resource.lastModified(); - return lm>=0?new HttpField(HttpHeader.LAST_MODIFIED,DateGenerator.formatDate(lm)):null; + return lm >= 0 ? new HttpField(HttpHeader.LAST_MODIFIED, DateGenerator.formatDate(lm)) : null; } - /* ------------------------------------------------------------ */ @Override public String getLastModifiedValue() { long lm = _resource.lastModified(); - return lm>=0?DateGenerator.formatDate(lm):null; + return lm >= 0 ? DateGenerator.formatDate(lm) : null; } - /* ------------------------------------------------------------ */ @Override public ByteBuffer getDirectBuffer() { - if (_resource.length()<=0 || _maxBuffer>0 && _maxBuffer<_resource.length()) + if (_resource.length() <= 0 || _maxBuffer > 0 && _resource.length() > _maxBuffer) return null; try { - return BufferUtil.toBuffer(_resource,true); + return BufferUtil.toBuffer(_resource, true); } - catch(IOException e) + catch (IOException e) { throw new RuntimeException(e); } } - - /* ------------------------------------------------------------ */ + @Override public HttpField getETag() { - return new HttpField(HttpHeader.ETAG,getETagValue()); + return new HttpField(HttpHeader.ETAG, getETagValue()); } - - /* ------------------------------------------------------------ */ + @Override public String getETagValue() { return _resource.getWeakETag(); } - /* ------------------------------------------------------------ */ @Override public ByteBuffer getIndirectBuffer() { - if (_resource.length()<=0 || _maxBuffer>0 && _maxBuffer<_resource.length()) + if (_resource.length() <= 0 || _maxBuffer > 0 && _resource.length() > _maxBuffer) return null; try { - return BufferUtil.toBuffer(_resource,false); + return BufferUtil.toBuffer(_resource, false); } - catch(IOException e) + catch (IOException e) { throw new RuntimeException(e); } } - /* ------------------------------------------------------------ */ @Override public HttpField getContentLength() { - long l=_resource.length(); - return l==-1?null:new HttpField.LongValueHttpField(HttpHeader.CONTENT_LENGTH,l); + long l = _resource.length(); + return l == -1 ? null : new HttpField.LongValueHttpField(HttpHeader.CONTENT_LENGTH, l); } - /* ------------------------------------------------------------ */ @Override public long getContentLengthValue() { return _resource.length(); } - /* ------------------------------------------------------------ */ @Override public InputStream getInputStream() throws IOException { return _resource.getInputStream(); } - - /* ------------------------------------------------------------ */ + @Override public ReadableByteChannel getReadableByteChannel() throws IOException { return _resource.getReadableByteChannel(); } - /* ------------------------------------------------------------ */ @Override public Resource getResource() { return _resource; } - /* ------------------------------------------------------------ */ @Override public void release() { _resource.close(); } - - /* ------------------------------------------------------------ */ + @Override public String toString() { - return String.format("%s@%x{r=%s,ct=%s,c=%b}",this.getClass().getSimpleName(),hashCode(),_resource,_contentType,_precompressedContents!=null); + return String.format("%s@%x{r=%s,ct=%s,c=%b}", this.getClass().getSimpleName(), hashCode(), _resource, _contentType, _precompressedContents != null); } - /* ------------------------------------------------------------ */ @Override public Map getPrecompressedContents() { return _precompressedContents; } - -} \ No newline at end of file +} diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/Syntax.java b/jetty-http/src/main/java/org/eclipse/jetty/http/Syntax.java index b934a6bbcc3..cb0b2a7d97d 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/Syntax.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/Syntax.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -28,7 +28,7 @@ import java.util.Objects; */ public final class Syntax { - + /** * Per RFC2616: Section 2.2, a token follows these syntax rules *
      @@ -49,30 +49,30 @@ public final class Syntax
           public static void requireValidRFC2616Token(String value, String msg)
           {
               Objects.requireNonNull(msg, "msg cannot be null");
      -        
      +
               if (value == null)
               {
                   return;
               }
      -        
      +
               int valueLen = value.length();
               if (valueLen == 0)
               {
                   return;
               }
      -        
      +
               for (int i = 0; i < valueLen; i++)
               {
                   char c = value.charAt(i);
      -            
      +
                   // 0x00 - 0x1F are low order control characters
                   // 0x7F is the DEL control character
                   if ((c <= 0x1F) || (c == 0x7F))
                       throw new IllegalArgumentException(msg + ": RFC2616 tokens may not contain control characters");
      -            if (c == '(' || c == ')' || c == '<' || c == '>' || c == '@'
      -                    || c == ',' || c == ';' || c == ':' || c == '\\' || c == '"'
      -                    || c == '/' || c == '[' || c == ']' || c == '?' || c == '='
      -                    || c == '{' || c == '}' || c == ' ')
      +            if (c == '(' || c == ')' || c == '<' || c == '>' || c == '@' ||
      +                c == ',' || c == ';' || c == ':' || c == '\\' || c == '"' ||
      +                c == '/' || c == '[' || c == ']' || c == '?' || c == '=' ||
      +                c == '{' || c == '}' || c == ' ')
                   {
                       throw new IllegalArgumentException(msg + ": RFC2616 tokens may not contain separator character: [" + c + "]");
                   }
      @@ -80,7 +80,7 @@ public final class Syntax
                       throw new IllegalArgumentException(msg + ": RFC2616 tokens characters restricted to US-ASCII: 0x" + Integer.toHexString(c));
               }
           }
      -    
      +
           /**
            * Per RFC6265, Cookie.value follows these syntax rules
            * 
      @@ -100,13 +100,13 @@ public final class Syntax
               {
                   return;
               }
      -        
      +
               int valueLen = value.length();
               if (valueLen == 0)
               {
                   return;
               }
      -        
      +
               int i = 0;
               if (value.charAt(0) == '"')
               {
      @@ -115,7 +115,7 @@ public final class Syntax
                   {
                       throw new IllegalArgumentException("RFC6265 Cookie values must have balanced DQUOTES (if used)");
                   }
      -            
      +
                   // adjust search range to exclude DQUOTES
                   i++;
                   valueLen--;
      @@ -123,15 +123,15 @@ public final class Syntax
               for (; i < valueLen; i++)
               {
                   char c = value.charAt(i);
      -            
      +
                   // 0x00 - 0x1F are low order control characters
                   // 0x7F is the DEL control character
                   if ((c <= 0x1F) || (c == 0x7F))
                       throw new IllegalArgumentException("RFC6265 Cookie values may not contain control characters");
                   if ((c == ' ' /* 0x20 */) ||
      -                    (c == '"' /* 0x2C */) ||
      -                    (c == ';' /* 0x3B */) ||
      -                    (c == '\\' /* 0x5C */))
      +                (c == '"' /* 0x2C */) ||
      +                (c == ';' /* 0x3B */) ||
      +                (c == '\\' /* 0x5C */))
                   {
                       throw new IllegalArgumentException("RFC6265 Cookie values may not contain character: [" + c + "]");
                   }
      diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/package-info.java b/jetty-http/src/main/java/org/eclipse/jetty/http/package-info.java
      index e5c027f0572..0532f07bf83 100644
      --- a/jetty-http/src/main/java/org/eclipse/jetty/http/package-info.java
      +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/package-info.java
      @@ -1,6 +1,6 @@
       //
       //  ========================================================================
      -//  Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
      +//  Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
       //  ------------------------------------------------------------------------
       //  All rights reserved. This program and the accompanying materials
       //  are made available under the terms of the Eclipse Public License v1.0
      diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/MappedResource.java b/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/MappedResource.java
      index b696cbba4c9..f05ea6c7528 100644
      --- a/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/MappedResource.java
      +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/MappedResource.java
      @@ -1,6 +1,6 @@
       //
       //  ========================================================================
      -//  Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
      +//  Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
       //  ------------------------------------------------------------------------
       //  All rights reserved. This program and the accompanying materials
       //  are made available under the terms of the Eclipse Public License v1.0
      @@ -60,16 +60,10 @@ public class MappedResource implements Comparable>
               MappedResource other = (MappedResource)obj;
               if (pathSpec == null)
               {
      -            if (other.pathSpec != null)
      -            {
      -                return false;
      -            }
      +            return other.pathSpec == null;
               }
      -        else if (!pathSpec.equals(other.pathSpec))
      -        {
      -            return false;
      -        }
      -        return true;
      +        else
      +            return pathSpec.equals(other.pathSpec);
           }
       
           @ManagedAttribute(value = "path spec", readonly = true)
      @@ -96,6 +90,6 @@ public class MappedResource implements Comparable>
           @Override
           public String toString()
           {
      -        return String.format("MappedResource[pathSpec=%s,resource=%s]",pathSpec,resource);
      +        return String.format("MappedResource[pathSpec=%s,resource=%s]", pathSpec, resource);
           }
      -}
      \ No newline at end of file
      +}
      diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/PathMappings.java b/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/PathMappings.java
      index 6bd3d6b7217..4194b8db83f 100644
      --- a/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/PathMappings.java
      +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/PathMappings.java
      @@ -1,6 +1,6 @@
       //
       //  ========================================================================
      -//  Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
      +//  Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
       //  ------------------------------------------------------------------------
       //  All rights reserved. This program and the accompanying materials
       //  are made available under the terms of the Eclipse Public License v1.0
      @@ -31,7 +31,6 @@ import org.eclipse.jetty.util.ArrayTernaryTrie;
       import org.eclipse.jetty.util.Trie;
       import org.eclipse.jetty.util.annotation.ManagedAttribute;
       import org.eclipse.jetty.util.annotation.ManagedObject;
      -import org.eclipse.jetty.util.component.ContainerLifeCycle;
       import org.eclipse.jetty.util.component.Dumpable;
       import org.eclipse.jetty.util.log.Log;
       import org.eclipse.jetty.util.log.Logger;
      @@ -40,7 +39,7 @@ import org.eclipse.jetty.util.log.Logger;
        * Path Mappings of PathSpec to Resource.
        * 

      * Sorted into search order upon entry into the Set - * + * * @param the type of mapping endpoint */ @ManagedObject("Path Mappings") @@ -48,24 +47,23 @@ public class PathMappings implements Iterable>, Dumpable { private static final Logger LOG = Log.getLogger(PathMappings.class); private final Set> _mappings = new TreeSet<>(); - - private Trie> _exactMap=new ArrayTernaryTrie<>(false); - private Trie> _prefixMap=new ArrayTernaryTrie<>(false); - private Trie> _suffixMap=new ArrayTernaryTrie<>(false); - + + private Trie> _exactMap = new ArrayTernaryTrie<>(false); + private Trie> _prefixMap = new ArrayTernaryTrie<>(false); + private Trie> _suffixMap = new ArrayTernaryTrie<>(false); + @Override public String dump() { - return ContainerLifeCycle.dump(this); + return Dumpable.dump(this); } @Override public void dump(Appendable out, String indent) throws IOException { - out.append("PathMappings[size=").append(Integer.toString(_mappings.size())).append("]\n"); - ContainerLifeCycle.dump(out, indent, _mappings); + Dumpable.dumpObjects(out, indent, toString(), _mappings); } - + @ManagedAttribute(value = "mappings", readonly = true) public List> getMappings() { @@ -76,31 +74,31 @@ public class PathMappings implements Iterable>, Dumpable { return _mappings.size(); } - + public void reset() { _mappings.clear(); _prefixMap.clear(); _suffixMap.clear(); } - + public void removeIf(Predicate> predicate) { _mappings.removeIf(predicate); } - + /** * Return a list of MappedResource matches for the specified path. - * + * * @param path the path to return matches on * @return the list of mapped resource the path matches on */ public List> getMatches(String path) { boolean isRootPath = "/".equals(path); - + List> ret = new ArrayList<>(); - for (MappedResource mr :_mappings) + for (MappedResource mr : _mappings) { switch (mr.getPathSpec().group) { @@ -123,72 +121,72 @@ public class PathMappings implements Iterable>, Dumpable public MappedResource getMatch(String path) { - PathSpecGroup last_group=null; - + PathSpecGroup lastGroup = null; + // Search all the mappings for (MappedResource mr : _mappings) { - PathSpecGroup group=mr.getPathSpec().getGroup(); - if (group!=last_group) + PathSpecGroup group = mr.getPathSpec().getGroup(); + if (group != lastGroup) { // New group in list, so let's look for an optimization - switch(group) + switch (group) { case EXACT: { - int i= path.length(); - final Trie> exact_map=_exactMap; - while(i>=0) + int i = path.length(); + final Trie> exact_map = _exactMap; + while (i >= 0) { - MappedResource candidate=exact_map.getBest(path,0,i); - if (candidate==null) + MappedResource candidate = exact_map.getBest(path, 0, i); + if (candidate == null) break; if (candidate.getPathSpec().matches(path)) return candidate; - i=candidate.getPathSpec().getPrefix().length()-1; + i = candidate.getPathSpec().getPrefix().length() - 1; } break; } - + case PREFIX_GLOB: { - int i= path.length(); - final Trie> prefix_map=_prefixMap; - while(i>=0) + int i = path.length(); + final Trie> prefix_map = _prefixMap; + while (i >= 0) { - MappedResource candidate=prefix_map.getBest(path,0,i); - if (candidate==null) + MappedResource candidate = prefix_map.getBest(path, 0, i); + if (candidate == null) break; if (candidate.getPathSpec().matches(path)) return candidate; - i=candidate.getPathSpec().getPrefix().length()-1; + i = candidate.getPathSpec().getPrefix().length() - 1; } break; } - + case SUFFIX_GLOB: { - int i=0; - final Trie> suffix_map=_suffixMap; - while ((i=path.indexOf('.',i+1))>0) + int i = 0; + final Trie> suffix_map = _suffixMap; + while ((i = path.indexOf('.', i + 1)) > 0) { - MappedResource candidate=suffix_map.get(path,i+1,path.length()-i-1); - if (candidate!=null && candidate.getPathSpec().matches(path)) + MappedResource candidate = suffix_map.get(path, i + 1, path.length() - i - 1); + if (candidate != null && candidate.getPathSpec().matches(path)) return candidate; } break; } - + default: } } - + if (mr.getPathSpec().matches(path)) return mr; - - last_group=group; + + lastGroup = group; } - + return null; } @@ -204,55 +202,61 @@ public class PathMappings implements Iterable>, Dumpable { throw new RuntimeException("Path Spec String must start with '^', '/', or '*.': got [" + pathSpecString + "]"); } - return pathSpecString.charAt(0) == '^' ? new RegexPathSpec(pathSpecString):new ServletPathSpec(pathSpecString); + return pathSpecString.charAt(0) == '^' ? new RegexPathSpec(pathSpecString) : new ServletPathSpec(pathSpecString); } - + public E get(PathSpec spec) { Optional optionalResource = _mappings.stream() - .filter(mappedResource -> mappedResource.getPathSpec().equals(spec)) - .map(mappedResource -> mappedResource.getResource()) - .findFirst(); - if(!optionalResource.isPresent()) + .filter(mappedResource -> mappedResource.getPathSpec().equals(spec)) + .map(mappedResource -> mappedResource.getResource()) + .findFirst(); + if (!optionalResource.isPresent()) return null; - + return optionalResource.get(); } - + public boolean put(String pathSpecString, E resource) { - return put(asPathSpec(pathSpecString),resource); + return put(asPathSpec(pathSpecString), resource); } - + public boolean put(PathSpec pathSpec, E resource) { - MappedResource entry = new MappedResource<>(pathSpec,resource); + MappedResource entry = new MappedResource<>(pathSpec, resource); switch (pathSpec.group) { case EXACT: String exact = pathSpec.getPrefix(); - while (exact!=null && !_exactMap.put(exact,entry)) - _exactMap=new ArrayTernaryTrie<>((ArrayTernaryTrie>)_exactMap,1.5); + while (exact != null && !_exactMap.put(exact, entry)) + { + _exactMap = new ArrayTernaryTrie<>((ArrayTernaryTrie>)_exactMap, 1.5); + } break; case PREFIX_GLOB: String prefix = pathSpec.getPrefix(); - while (prefix!=null && !_prefixMap.put(prefix,entry)) - _prefixMap=new ArrayTernaryTrie<>((ArrayTernaryTrie>)_prefixMap,1.5); + while (prefix != null && !_prefixMap.put(prefix, entry)) + { + _prefixMap = new ArrayTernaryTrie<>((ArrayTernaryTrie>)_prefixMap, 1.5); + } break; case SUFFIX_GLOB: String suffix = pathSpec.getSuffix(); - while (suffix!=null && !_suffixMap.put(suffix,entry)) - _suffixMap=new ArrayTernaryTrie<>((ArrayTernaryTrie>)_prefixMap,1.5); + while (suffix != null && !_suffixMap.put(suffix, entry)) + { + _suffixMap = new ArrayTernaryTrie<>((ArrayTernaryTrie>)_prefixMap, 1.5); + } break; default: } - - boolean added =_mappings.add(entry); + + boolean added = _mappings.add(entry); if (LOG.isDebugEnabled()) - LOG.debug("{} {} to {}",added?"Added":"Ignored",entry,this); + LOG.debug("{} {} to {}", added ? "Added" : "Ignored", entry, this); return added; } - + @SuppressWarnings("incomplete-switch") public boolean remove(PathSpec pathSpec) { @@ -268,27 +272,26 @@ public class PathMappings implements Iterable>, Dumpable _suffixMap.remove(pathSpec.getSuffix()); break; } - + Iterator> iter = _mappings.iterator(); - boolean removed=false; + boolean removed = false; while (iter.hasNext()) { if (iter.next().getPathSpec().equals(pathSpec)) { - removed=true; + removed = true; iter.remove(); break; } } if (LOG.isDebugEnabled()) - LOG.debug("{} {} to {}",removed?"Removed":"Ignored",pathSpec,this); + LOG.debug("{} {} to {}", removed ? "Removed" : "Ignored", pathSpec, this); return removed; } @Override public String toString() { - return String.format("%s[size=%d]",this.getClass().getSimpleName(),_mappings.size()); + return String.format("%s[size=%d]", this.getClass().getSimpleName(), _mappings.size()); } - } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/PathSpec.java b/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/PathSpec.java index 98f4293fd57..02f72e99cc8 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/PathSpec.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/PathSpec.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -69,16 +69,10 @@ public abstract class PathSpec implements Comparable PathSpec other = (PathSpec)obj; if (pathSpec == null) { - if (other.pathSpec != null) - { - return false; - } + return other.pathSpec == null; } - else if (!pathSpec.equals(other.pathSpec)) - { - return false; - } - return true; + else + return pathSpec.equals(other.pathSpec); } public PathSpecGroup getGroup() @@ -90,7 +84,7 @@ public abstract class PathSpec implements Comparable * Get the number of path elements that this path spec declares. *

      * This is used to determine longest match logic. - * + * * @return the depth of the path segments that this spec declares */ public int getPathDepth() @@ -100,25 +94,23 @@ public abstract class PathSpec implements Comparable /** * Return the portion of the path that is after the path spec. - * - * @param path - * the path to match against + * + * @param path the path to match against * @return the path info portion of the string */ public abstract String getPathInfo(String path); /** * Return the portion of the path that matches a path spec. - * - * @param path - * the path to match against + * + * @param path the path to match against * @return the match, or null if no match at all */ public abstract String getPathMatch(String path); /** * The as-provided path spec. - * + * * @return the as-provided path spec */ public String getDeclaration() @@ -128,6 +120,7 @@ public abstract class PathSpec implements Comparable /** * A simple prefix match for the pathspec or null + * * @return A simple prefix match for the pathspec or null */ public String getPrefix() @@ -137,20 +130,19 @@ public abstract class PathSpec implements Comparable /** * A simple suffix match for the pathspec or null + * * @return A simple suffix match for the pathspec or null */ public String getSuffix() { return suffix; } - + /** * Get the relative path. - * - * @param base - * the base the path is relative to - * @param path - * the additional path + * + * @param base the base the path is relative to + * @param path the additional path * @return the base plus path with pathSpec portion removed */ public abstract String getRelativePath(String base, String path); @@ -160,15 +152,14 @@ public abstract class PathSpec implements Comparable { final int prime = 31; int result = 1; - result = (prime * result) + ((pathSpec == null)?0:pathSpec.hashCode()); + result = (prime * result) + ((pathSpec == null) ? 0 : pathSpec.hashCode()); return result; } /** * Test to see if the provided path matches this path spec - * - * @param path - * the path to test + * + * @param path the path to test * @return true if the path matches this path spec, false otherwise */ public abstract boolean matches(String path); diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/PathSpecGroup.java b/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/PathSpecGroup.java index 3fbfd989b5a..7d364ab2035 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/PathSpecGroup.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/PathSpecGroup.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -23,7 +23,7 @@ package org.eclipse.jetty.http.pathmap; *

      * This is used to facilitate proper pathspec search order. *

      - * Search Order: + * Search Order: *

        *
      1. {@link PathSpecGroup#ordinal()} [increasing]
      2. *
      3. {@link PathSpec#specLength} [decreasing]
      4. @@ -36,12 +36,12 @@ public enum PathSpecGroup /** * The root spec for accessing the Root behavior. - * + * *
              *   ""           - servlet spec       (Root Servlet)
              *   null         - servlet spec       (Root Servlet)
              * 
        - * + * * Note: there is no known uri-template spec variant of this kind of path spec */ ROOT, @@ -51,12 +51,12 @@ public enum PathSpecGroup EXACT, /** * For path specs that have a hardcoded prefix and suffix with wildcard glob in the middle. - * + * *
              *   "^/downloads/[^/]*.zip$"  - regex spec
              *   "/a/{var}/c"              - uri-template spec
              * 
        - * + * * Note: there is no known servlet spec variant of this kind of path spec */ MIDDLE_GLOB, @@ -74,25 +74,25 @@ public enum PathSpecGroup PREFIX_GLOB, /** * For path specs that have a wildcard glob with a hardcoded suffix - * + * *
              *   "*.do"        - servlet spec
              *   "*.css"       - servlet spec
              *   "^.*\.zip$"   - regex spec
              * 
        - * + * * Note: there is no known uri-template spec variant of this kind of path spec */ SUFFIX_GLOB, /** * The default spec for accessing the Default path behavior. - * + * *
              *   "/"           - servlet spec      (Default Servlet)
              *   "/"           - uri-template spec (Root Context)
              *   "^/$"         - regex spec        (Root Context)
              * 
        - * + * * Per Servlet Spec, pathInfo is always null for these specs. * If nothing above matches, then default will match. */ diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/PathSpecSet.java b/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/PathSpecSet.java index 705a1dcfb23..252706d67dc 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/PathSpecSet.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/PathSpecSet.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -34,10 +34,9 @@ public class PathSpecSet extends AbstractSet implements Predicate implements Predicate implements Predicate iterator() { diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/RegexPathSpec.java b/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/RegexPathSpec.java index 87c6d5a9670..5381f4726af 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/RegexPathSpec.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/RegexPathSpec.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -76,15 +76,15 @@ public class RegexPathSpec extends PathSpec // Figure out the grouping based on the signature String sig = signature.toString(); - if (Pattern.matches("^l*$",sig)) + if (Pattern.matches("^l*$", sig)) { this.group = PathSpecGroup.EXACT; } - else if (Pattern.matches("^l*g+",sig)) + else if (Pattern.matches("^l*g+", sig)) { this.group = PathSpecGroup.PREFIX_GLOB; } - else if (Pattern.matches("^g+l+$",sig)) + else if (Pattern.matches("^g+l+$", sig)) { this.group = PathSpecGroup.SUFFIX_GLOB; } @@ -140,7 +140,7 @@ public class RegexPathSpec extends PathSpec { idx--; } - return path.substring(0,idx); + return path.substring(0, idx); } } return path; @@ -167,7 +167,7 @@ public class RegexPathSpec extends PathSpec if (idx >= 0) { // match only non-query part - return getMatcher(path.substring(0,idx)).matches(); + return getMatcher(path.substring(0, idx)).matches(); } else { diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/ServletPathSpec.java b/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/ServletPathSpec.java index 8f374c193dd..612e2df5ea7 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/ServletPathSpec.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/ServletPathSpec.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -26,18 +26,17 @@ public class ServletPathSpec extends PathSpec /** * If a servlet or filter path mapping isn't a suffix mapping, ensure * it starts with '/' - * + * * @param pathSpec the servlet or filter mapping pattern * @return the pathSpec prefixed by '/' if appropriate */ public static String normalize(String pathSpec) { - if (StringUtil.isNotBlank(pathSpec) && !pathSpec.startsWith("/") && !pathSpec.startsWith("*")) + if (StringUtil.isNotBlank(pathSpec) && !pathSpec.startsWith("/") && !pathSpec.startsWith("*")) return "/" + pathSpec; return pathSpec; } - - + public ServletPathSpec(String servletPathSpec) { if (servletPathSpec == null) @@ -47,7 +46,7 @@ public class ServletPathSpec extends PathSpec assertValidServletPathSpec(servletPathSpec); // The Root Path Spec - if (servletPathSpec.length() == 0) + if (servletPathSpec.isEmpty()) { super.pathSpec = ""; super.pathDepth = -1; // force this to be at the end of the sort order @@ -57,7 +56,7 @@ public class ServletPathSpec extends PathSpec } // The Default Path Spec - if("/".equals(servletPathSpec)) + if ("/".equals(servletPathSpec)) { super.pathSpec = "/"; super.pathDepth = -1; // force this to be at the end of the sort order @@ -65,7 +64,7 @@ public class ServletPathSpec extends PathSpec this.group = PathSpecGroup.DEFAULT; return; } - + this.specLength = servletPathSpec.length(); super.pathDepth = 0; char lastChar = servletPathSpec.charAt(specLength - 1); @@ -73,13 +72,13 @@ public class ServletPathSpec extends PathSpec if ((servletPathSpec.charAt(0) == '/') && (specLength > 1) && (lastChar == '*')) { this.group = PathSpecGroup.PREFIX_GLOB; - this.prefix = servletPathSpec.substring(0,specLength-2); + this.prefix = servletPathSpec.substring(0, specLength - 2); } // suffix based else if (servletPathSpec.charAt(0) == '*') { this.group = PathSpecGroup.SUFFIX_GLOB; - this.suffix = servletPathSpec.substring(2,specLength); + this.suffix = servletPathSpec.substring(2, specLength); } else { @@ -129,12 +128,12 @@ public class ServletPathSpec extends PathSpec // only allowed to have '*' at the end of the path spec if (idx != (len - 1)) { - throw new IllegalArgumentException("Servlet Spec 12.2 violation: glob '*' can only exist at end of prefix based matches: bad spec \""+ servletPathSpec +"\""); + throw new IllegalArgumentException("Servlet Spec 12.2 violation: glob '*' can only exist at end of prefix based matches: bad spec \"" + servletPathSpec + "\""); } - - if (idx<1 || servletPathSpec.charAt(idx-1)!='/') + + if (idx < 1 || servletPathSpec.charAt(idx - 1) != '/') { - throw new IllegalArgumentException("Servlet Spec 12.2 violation: suffix glob '*' can only exist after '/': bad spec \""+ servletPathSpec +"\""); + throw new IllegalArgumentException("Servlet Spec 12.2 violation: suffix glob '*' can only exist after '/': bad spec \"" + servletPathSpec + "\""); } } else if (servletPathSpec.startsWith("*.")) @@ -144,19 +143,19 @@ public class ServletPathSpec extends PathSpec // cannot have path separator if (idx >= 0) { - throw new IllegalArgumentException("Servlet Spec 12.2 violation: suffix based path spec cannot have path separators: bad spec \""+ servletPathSpec +"\""); + throw new IllegalArgumentException("Servlet Spec 12.2 violation: suffix based path spec cannot have path separators: bad spec \"" + servletPathSpec + "\""); } - idx = servletPathSpec.indexOf('*',2); + idx = servletPathSpec.indexOf('*', 2); // only allowed to have 1 glob '*', at the start of the path spec if (idx >= 1) { - throw new IllegalArgumentException("Servlet Spec 12.2 violation: suffix based path spec cannot have multiple glob '*': bad spec \""+ servletPathSpec +"\""); + throw new IllegalArgumentException("Servlet Spec 12.2 violation: suffix based path spec cannot have multiple glob '*': bad spec \"" + servletPathSpec + "\""); } } else { - throw new IllegalArgumentException("Servlet Spec 12.2 violation: path spec must start with \"/\" or \"*.\": bad spec \""+ servletPathSpec +"\""); + throw new IllegalArgumentException("Servlet Spec 12.2 violation: path spec must start with \"/\" or \"*.\": bad spec \"" + servletPathSpec + "\""); } } @@ -193,14 +192,14 @@ public class ServletPathSpec extends PathSpec case PREFIX_GLOB: if (isWildcardMatch(path)) { - return path.substring(0,specLength - 2); + return path.substring(0, specLength - 2); } else { return null; } case SUFFIX_GLOB: - if (path.regionMatches(path.length() - (specLength - 1),pathSpec,1,specLength - 1)) + if (path.regionMatches(path.length() - (specLength - 1), pathSpec, 1, specLength - 1)) { return path; } @@ -254,12 +253,9 @@ public class ServletPathSpec extends PathSpec { // For a spec of "/foo/*" match "/foo" , "/foo/..." but not "/foobar" int cpl = specLength - 2; - if ((group == PathSpecGroup.PREFIX_GLOB) && (path.regionMatches(0,pathSpec,0,cpl))) + if ((group == PathSpecGroup.PREFIX_GLOB) && (path.regionMatches(0, pathSpec, 0, cpl))) { - if ((path.length() == cpl) || ('/' == path.charAt(cpl))) - { - return true; - } + return (path.length() == cpl) || ('/' == path.charAt(cpl)); } return false; } @@ -274,7 +270,7 @@ public class ServletPathSpec extends PathSpec case PREFIX_GLOB: return isWildcardMatch(path); case SUFFIX_GLOB: - return path.regionMatches((path.length() - specLength) + 1,pathSpec,1,specLength - 1); + return path.regionMatches((path.length() - specLength) + 1, pathSpec, 1, specLength - 1); case ROOT: // Only "/" matches return ("/".equals(path)); diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/UriTemplatePathSpec.java b/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/UriTemplatePathSpec.java index 62dcf8be295..bd0df5d9b63 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/UriTemplatePathSpec.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/UriTemplatePathSpec.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -35,19 +35,23 @@ import org.eclipse.jetty.util.log.Logger; /** * PathSpec for URI Template based declarations - * + * * @see URI Templates (Level 1) */ public class UriTemplatePathSpec extends RegexPathSpec { private static final Logger LOG = Log.getLogger(UriTemplatePathSpec.class); - + private static final Pattern VARIABLE_PATTERN = Pattern.compile("\\{(.*)\\}"); - /** Reserved Symbols in URI Template variable */ + /** + * Reserved Symbols in URI Template variable + */ private static final String VARIABLE_RESERVED = ":/?#[]@" + // gen-delims - "!$&'()*+,;="; // sub-delims - /** Allowed Symbols in a URI Template variable */ - private static final String VARIABLE_SYMBOLS="-._"; + "!$&'()*+,;="; // sub-delims + /** + * Allowed Symbols in a URI Template variable + */ + private static final String VARIABLE_SYMBOLS = "-._"; private static final Set FORBIDDEN_SEGMENTS; static @@ -58,12 +62,12 @@ public class UriTemplatePathSpec extends RegexPathSpec FORBIDDEN_SEGMENTS.add("//"); } - private String variables[]; + private String[] variables; public UriTemplatePathSpec(String rawSpec) { super(); - Objects.requireNonNull(rawSpec,"Path Param Spec cannot be null"); + Objects.requireNonNull(rawSpec, "Path Param Spec cannot be null"); if ("".equals(rawSpec) || "/".equals(rawSpec)) { @@ -106,8 +110,8 @@ public class UriTemplatePathSpec extends RegexPathSpec List varNames = new ArrayList<>(); // split up into path segments (ignoring the first slash that will always be empty) - String segments[] = rawSpec.substring(1).split("/"); - char segmentSignature[] = new char[segments.length]; + String[] segments = rawSpec.substring(1).split("/"); + char[] segmentSignature = new char[segments.length]; this.pathDepth = segments.length; for (int i = 0; i < segments.length; i++) { @@ -184,9 +188,9 @@ public class UriTemplatePathSpec extends RegexPathSpec } } } - + // Handle trailing slash (which is not picked up during split) - if(rawSpec.charAt(rawSpec.length()-1) == '/') + if (rawSpec.charAt(rawSpec.length() - 1) == '/') { regex.append('/'); } @@ -201,15 +205,15 @@ public class UriTemplatePathSpec extends RegexPathSpec // Convert signature to group String sig = String.valueOf(segmentSignature); - if (Pattern.matches("^e*$",sig)) + if (Pattern.matches("^e*$", sig)) { this.group = PathSpecGroup.EXACT; } - else if (Pattern.matches("^e*v+",sig)) + else if (Pattern.matches("^e*v+", sig)) { this.group = PathSpecGroup.PREFIX_GLOB; } - else if (Pattern.matches("^v+e+",sig)) + else if (Pattern.matches("^v+e+", sig)) { this.group = PathSpecGroup.SUFFIX_GLOB; } @@ -221,17 +225,15 @@ public class UriTemplatePathSpec extends RegexPathSpec /** * Validate variable literal name, per RFC6570, Section 2.1 Literals - * @param variable - * @param pathParamSpec */ private void assertIsValidVariableLiteral(String variable) { int len = variable.length(); - + int i = 0; int codepoint; boolean valid = (len > 0); // must not be zero length - + while (valid && i < len) { codepoint = variable.codePointAt(i); @@ -267,7 +269,7 @@ public class UriTemplatePathSpec extends RegexPathSpec continue; } } - + valid = false; } @@ -282,27 +284,27 @@ public class UriTemplatePathSpec extends RegexPathSpec throw new IllegalArgumentException(err.toString()); } } - + private boolean isValidBasicLiteralCodepoint(int codepoint) { // basic letters or digits - if((codepoint >= 'a' && codepoint <= 'z') || - (codepoint >= 'A' && codepoint <= 'Z') || - (codepoint >= '0' && codepoint <= '9')) + if ((codepoint >= 'a' && codepoint <= 'z') || + (codepoint >= 'A' && codepoint <= 'Z') || + (codepoint >= '0' && codepoint <= '9')) { return true; } - + // basic allowed symbols - if(VARIABLE_SYMBOLS.indexOf(codepoint) >= 0) + if (VARIABLE_SYMBOLS.indexOf(codepoint) >= 0) { return true; // valid simple value } - + // basic reserved symbols - if(VARIABLE_RESERVED.indexOf(codepoint) >= 0) + if (VARIABLE_RESERVED.indexOf(codepoint) >= 0) { - LOG.warn("Detected URI Template reserved symbol [{}] in path spec \"{}\"",(char)codepoint,pathSpec); + LOG.warn("Detected URI Template reserved symbol [{}] in path spec \"{}\"", (char)codepoint, pathSpec); return false; // valid simple value } @@ -322,7 +324,7 @@ public class UriTemplatePathSpec extends RegexPathSpec int groupCount = matcher.groupCount(); for (int i = 1; i <= groupCount; i++) { - ret.put(this.variables[i - 1],matcher.group(i)); + ret.put(this.variables[i - 1], matcher.group(i)); } return ret; } diff --git a/jetty-http/src/main/resources/org/eclipse/jetty/http/mime.properties b/jetty-http/src/main/resources/org/eclipse/jetty/http/mime.properties index b4ad431489b..fe10cfdba3d 100644 --- a/jetty-http/src/main/resources/org/eclipse/jetty/http/mime.properties +++ b/jetty-http/src/main/resources/org/eclipse/jetty/http/mime.properties @@ -167,6 +167,7 @@ ustar=application/x-ustar vcd=application/x-cdlink vrml=model/vrml vxml=application/voicexml+xml +wasm=application/wasm wav=audio/x-wav wbmp=image/vnd.wap.wbmp wml=text/vnd.wap.wml diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/DateParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/DateParserTest.java new file mode 100644 index 00000000000..72a90c31d02 --- /dev/null +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/DateParserTest.java @@ -0,0 +1,44 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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 org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Unit tests for class {@link DateParser}. + * + * @see DateParser + */ +public class DateParserTest +{ + + @Test + public void testParseDateWithNonDateString() + { + assertEquals((-1L), DateParser.parseDate("3%~")); + } + + @Test + public void testParseDateWithNonDateStringEndingWithGMT() + { + assertEquals((-1L), DateParser.parseDate("3%~ GMT")); + } +} diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/GZIPContentDecoderTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/GZIPContentDecoderTest.java index ad6c92fa230..93c7c4c3f37 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/GZIPContentDecoderTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/GZIPContentDecoderTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,10 +18,6 @@ package org.eclipse.jetty.http; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; @@ -35,52 +31,54 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; 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 GZIPContentDecoderTest { - ArrayByteBufferPool pool; - AtomicInteger buffers = new AtomicInteger(0); - + private ArrayByteBufferPool pool; + private AtomicInteger buffers = new AtomicInteger(0); + @BeforeEach - public void beforeClass() throws Exception + public void before() { buffers.set(0); pool = new ArrayByteBufferPool() + { + + @Override + public ByteBuffer acquire(int size, boolean direct) { + buffers.incrementAndGet(); + return super.acquire(size, direct); + } - @Override - public ByteBuffer acquire(int size, boolean direct) - { - buffers.incrementAndGet(); - return super.acquire(size,direct); - } - - @Override - public void release(ByteBuffer buffer) - { - buffers.decrementAndGet(); - super.release(buffer); - } - - }; + @Override + public void release(ByteBuffer buffer) + { + buffers.decrementAndGet(); + super.release(buffer); + } + }; } - + @AfterEach - public void afterClass() throws Exception + public void after() { - assertEquals(0,buffers.get()); + assertEquals(0, buffers.get()); } - + @Test - public void testCompresedContentFormat() throws Exception + public void testCompressedContentFormat() { - assertTrue(CompressedContentFormat.tagEquals("tag","tag")); - assertTrue(CompressedContentFormat.tagEquals("\"tag\"","\"tag\"")); - assertTrue(CompressedContentFormat.tagEquals("\"tag\"","\"tag--gzip\"")); - assertFalse(CompressedContentFormat.tagEquals("Zag","Xag--gzip")); - assertFalse(CompressedContentFormat.tagEquals("xtag","tag")); + assertTrue(CompressedContentFormat.tagEquals("tag", "tag")); + assertTrue(CompressedContentFormat.tagEquals("\"tag\"", "\"tag\"")); + assertTrue(CompressedContentFormat.tagEquals("\"tag\"", "\"tag--gzip\"")); + assertFalse(CompressedContentFormat.tagEquals("Zag", "Xag--gzip")); + assertFalse(CompressedContentFormat.tagEquals("xtag", "tag")); } - + @Test public void testStreamNoBlocks() throws Exception { @@ -99,7 +97,9 @@ public class GZIPContentDecoderTest { String data = "0123456789ABCDEF"; for (int i = 0; i < 10; ++i) + { data += data; + } ByteArrayOutputStream baos = new ByteArrayOutputStream(); GZIPOutputStream output = new GZIPOutputStream(baos); output.write(data.getBytes(StandardCharsets.UTF_8)); @@ -110,7 +110,9 @@ public class GZIPContentDecoderTest GZIPInputStream input = new GZIPInputStream(new ByteArrayInputStream(bytes), 1); int read; while ((read = input.read()) >= 0) + { baos.write(read); + } assertEquals(data, new String(baos.toByteArray(), StandardCharsets.UTF_8)); } @@ -122,7 +124,7 @@ public class GZIPContentDecoderTest output.close(); byte[] bytes = baos.toByteArray(); - GZIPContentDecoder decoder = new GZIPContentDecoder(pool,2048); + GZIPContentDecoder decoder = new GZIPContentDecoder(pool, 2048); ByteBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes)); assertEquals(0, decoded.remaining()); } @@ -138,7 +140,7 @@ public class GZIPContentDecoderTest output.close(); byte[] bytes = baos.toByteArray(); - GZIPContentDecoder decoder = new GZIPContentDecoder(pool,2048); + GZIPContentDecoder decoder = new GZIPContentDecoder(pool, 2048); ByteBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes)); assertEquals(data, StandardCharsets.UTF_8.decode(decoded).toString()); decoder.release(decoded); @@ -161,7 +163,7 @@ public class GZIPContentDecoderTest byte[] bytes2 = new byte[bytes.length - bytes1.length]; System.arraycopy(bytes, bytes1.length, bytes2, 0, bytes2.length); - GZIPContentDecoder decoder = new GZIPContentDecoder(pool,2048); + GZIPContentDecoder decoder = new GZIPContentDecoder(pool, 2048); ByteBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes1)); assertEquals(0, decoded.capacity()); decoded = decoder.decode(ByteBuffer.wrap(bytes2)); @@ -186,7 +188,7 @@ public class GZIPContentDecoderTest byte[] bytes2 = new byte[bytes.length - bytes1.length]; System.arraycopy(bytes, bytes1.length, bytes2, 0, bytes2.length); - GZIPContentDecoder decoder = new GZIPContentDecoder(pool,2048); + GZIPContentDecoder decoder = new GZIPContentDecoder(pool, 2048); ByteBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes1)); assertEquals(data, StandardCharsets.UTF_8.decode(decoded).toString()); assertFalse(decoder.isFinished()); @@ -214,7 +216,7 @@ public class GZIPContentDecoderTest byte[] bytes2 = new byte[bytes.length - bytes1.length]; System.arraycopy(bytes, bytes1.length, bytes2, 0, bytes2.length); - GZIPContentDecoder decoder = new GZIPContentDecoder(pool,2048); + GZIPContentDecoder decoder = new GZIPContentDecoder(pool, 2048); ByteBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes1)); assertEquals(0, decoded.capacity()); decoder.release(decoded); @@ -244,7 +246,7 @@ public class GZIPContentDecoderTest System.arraycopy(bytes1, 0, bytes, 0, bytes1.length); System.arraycopy(bytes2, 0, bytes, bytes1.length, bytes2.length); - GZIPContentDecoder decoder = new GZIPContentDecoder(pool,2048); + GZIPContentDecoder decoder = new GZIPContentDecoder(pool, 2048); ByteBuffer buffer = ByteBuffer.wrap(bytes); ByteBuffer decoded = decoder.decode(buffer); assertEquals(data1, StandardCharsets.UTF_8.decode(decoded).toString()); @@ -263,7 +265,9 @@ public class GZIPContentDecoderTest { String data = "0123456789ABCDEF"; for (int i = 0; i < 10; ++i) + { data += data; + } ByteArrayOutputStream baos = new ByteArrayOutputStream(); GZIPOutputStream output = new GZIPOutputStream(baos); output.write(data.getBytes(StandardCharsets.UTF_8)); @@ -271,7 +275,7 @@ public class GZIPContentDecoderTest byte[] bytes = baos.toByteArray(); String result = ""; - GZIPContentDecoder decoder = new GZIPContentDecoder(pool,2048); + GZIPContentDecoder decoder = new GZIPContentDecoder(pool, 2048); ByteBuffer buffer = ByteBuffer.wrap(bytes); while (buffer.hasRemaining()) { @@ -287,7 +291,9 @@ public class GZIPContentDecoderTest { String data = "0123456789ABCDEF"; for (int i = 0; i < 10; ++i) + { data += data; + } ByteArrayOutputStream baos = new ByteArrayOutputStream(); GZIPOutputStream output = new GZIPOutputStream(baos); output.write(data.getBytes(StandardCharsets.UTF_8)); @@ -313,7 +319,9 @@ public class GZIPContentDecoderTest { String data1 = "0123456789ABCDEF"; for (int i = 0; i < 10; ++i) + { data1 += data1; + } ByteArrayOutputStream baos = new ByteArrayOutputStream(); GZIPOutputStream output = new GZIPOutputStream(baos); output.write(data1.getBytes(StandardCharsets.UTF_8)); diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpCookieTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpCookieTest.java new file mode 100644 index 00000000000..6fc0ef8c964 --- /dev/null +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpCookieTest.java @@ -0,0 +1,221 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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 org.hamcrest.Matchers; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.containsString; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +public class HttpCookieTest +{ + + @Test + public void testConstructFromSetCookie() + { + HttpCookie cookie = new HttpCookie("everything=value; Path=path; Domain=domain; Expires=Thu, 01-Jan-1970 00:00:00 GMT; Max-Age=0; Secure; HttpOnly"); + } + + @Test + public void testSetRFC2965Cookie() throws Exception + { + HttpCookie httpCookie; + + httpCookie = new HttpCookie("null", null, null, null, -1, false, false, null, -1); + assertEquals("null=", httpCookie.getRFC2965SetCookie()); + + httpCookie = new HttpCookie("minimal", "value", null, null, -1, false, false, null, -1); + assertEquals("minimal=value", httpCookie.getRFC2965SetCookie()); + + httpCookie = new HttpCookie("everything", "something", "domain", "path", 0, true, true, "noncomment", 0); + assertEquals("everything=something;Version=1;Path=path;Domain=domain;Expires=Thu, 01-Jan-1970 00:00:00 GMT;Max-Age=0;Secure;HttpOnly;Comment=noncomment", httpCookie.getRFC2965SetCookie()); + + httpCookie = new HttpCookie("everything", "value", "domain", "path", 0, true, true, "comment", 0); + assertEquals("everything=value;Version=1;Path=path;Domain=domain;Expires=Thu, 01-Jan-1970 00:00:00 GMT;Max-Age=0;Secure;HttpOnly;Comment=comment", httpCookie.getRFC2965SetCookie()); + + httpCookie = new HttpCookie("ev erything", "va lue", "do main", "pa th", 1, true, true, "co mment", 1); + String setCookie = httpCookie.getRFC2965SetCookie(); + assertThat(setCookie, Matchers.startsWith("\"ev erything\"=\"va lue\";Version=1;Path=\"pa th\";Domain=\"do main\";Expires=")); + assertThat(setCookie, Matchers.endsWith(" GMT;Max-Age=1;Secure;HttpOnly;Comment=\"co mment\"")); + + httpCookie = new HttpCookie("name", "value", null, null, -1, false, false, null, 0); + setCookie = httpCookie.getRFC2965SetCookie(); + assertEquals(-1, setCookie.indexOf("Version=")); + httpCookie = new HttpCookie("name", "v a l u e", null, null, -1, false, false, null, 0); + setCookie = httpCookie.getRFC2965SetCookie(); + + httpCookie = new HttpCookie("json", "{\"services\":[\"cwa\", \"aa\"]}", null, null, -1, false, false, null, -1); + assertEquals("json=\"{\\\"services\\\":[\\\"cwa\\\", \\\"aa\\\"]}\"", httpCookie.getRFC2965SetCookie()); + + httpCookie = new HttpCookie("name", "value%=", null, null, -1, false, false, null, 0); + setCookie = httpCookie.getRFC2965SetCookie(); + assertEquals("name=value%=", setCookie); + } + + @Test + public void testSetRFC6265Cookie() throws Exception + { + HttpCookie httpCookie; + + httpCookie = new HttpCookie("null", null, null, null, -1, false, false, null, -1); + assertEquals("null=", httpCookie.getRFC6265SetCookie()); + + httpCookie = new HttpCookie("minimal", "value", null, null, -1, false, false, null, -1); + assertEquals("minimal=value", httpCookie.getRFC6265SetCookie()); + + //test cookies with same name, domain and path + httpCookie = new HttpCookie("everything", "something", "domain", "path", 0, true, true, null, -1); + assertEquals("everything=something; Path=path; Domain=domain; Expires=Thu, 01-Jan-1970 00:00:00 GMT; Max-Age=0; Secure; HttpOnly", httpCookie.getRFC6265SetCookie()); + + httpCookie = new HttpCookie("everything", "value", "domain", "path", 0, true, true, null, -1); + assertEquals("everything=value; Path=path; Domain=domain; Expires=Thu, 01-Jan-1970 00:00:00 GMT; Max-Age=0; Secure; HttpOnly", httpCookie.getRFC6265SetCookie()); + + + httpCookie = new HttpCookie("everything", "value", "domain", "path", 0, true, true, null, -1, HttpCookie.SameSite.NONE); + assertEquals("everything=value; Path=path; Domain=domain; Expires=Thu, 01-Jan-1970 00:00:00 GMT; Max-Age=0; Secure; HttpOnly; SameSite=None", httpCookie.getRFC6265SetCookie()); + + httpCookie = new HttpCookie("everything", "value", "domain", "path", 0, true, true, null, -1, HttpCookie.SameSite.LAX); + assertEquals("everything=value; Path=path; Domain=domain; Expires=Thu, 01-Jan-1970 00:00:00 GMT; Max-Age=0; Secure; HttpOnly; SameSite=Lax", httpCookie.getRFC6265SetCookie()); + + httpCookie = new HttpCookie("everything", "value", "domain", "path", 0, true, true, null, -1, HttpCookie.SameSite.STRICT); + assertEquals("everything=value; Path=path; Domain=domain; Expires=Thu, 01-Jan-1970 00:00:00 GMT; Max-Age=0; Secure; HttpOnly; SameSite=Strict", httpCookie.getRFC6265SetCookie()); + + String[] badNameExamples = { + "\"name\"", + "name\t", + "na me", + "name\u0082", + "na\tme", + "na;me", + "{name}", + "[name]", + "\"" + }; + + for (String badNameExample : badNameExamples) + { + try + { + httpCookie = new HttpCookie(badNameExample, "value", null, "/", 1, true, true, null, -1); + httpCookie.getRFC6265SetCookie(); + fail(badNameExample); + } + catch (IllegalArgumentException ex) + { + // System.err.printf("%s: %s%n", ex.getClass().getSimpleName(), ex.getMessage()); + assertThat("Testing bad name: [" + badNameExample + "]", ex.getMessage(), + allOf(containsString("RFC6265"), containsString("RFC2616"))); + } + } + + String[] badValueExamples = { + "va\tlue", + "\t", + "value\u0000", + "val\u0082ue", + "va lue", + "va;lue", + "\"value", + "value\"", + "val\\ue", + "val\"ue", + "\"" + }; + + for (String badValueExample : badValueExamples) + { + try + { + httpCookie = new HttpCookie("name", badValueExample, null, "/", 1, true, true, null, -1); + httpCookie.getRFC6265SetCookie(); + fail(); + } + catch (IllegalArgumentException ex) + { + // System.err.printf("%s: %s%n", ex.getClass().getSimpleName(), ex.getMessage()); + assertThat("Testing bad value [" + badValueExample + "]", ex.getMessage(), Matchers.containsString("RFC6265")); + } + } + + String[] goodNameExamples = { + "name", + "n.a.m.e", + "na-me", + "+name", + "na*me", + "na$me", + "#name" + }; + + for (String goodNameExample : goodNameExamples) + { + httpCookie = new HttpCookie(goodNameExample, "value", null, "/", 1, true, true, null, -1); + // should not throw an exception + } + + String[] goodValueExamples = { + "value", + "", + null, + "val=ue", + "val-ue", + "val/ue", + "v.a.l.u.e" + }; + + for (String goodValueExample : goodValueExamples) + { + httpCookie = new HttpCookie("name", goodValueExample, null, "/", 1, true, true, null, -1); + // should not throw an exception + } + } + + @Test + public void testGetHttpOnlyFromComment() + { + assertTrue(HttpCookie.isHttpOnlyInComment("__HTTP_ONLY__")); + assertTrue(HttpCookie.isHttpOnlyInComment("__HTTP_ONLY__comment")); + assertFalse(HttpCookie.isHttpOnlyInComment("comment")); + } + + @Test + public void testGetSameSiteFromComment() + { + assertEquals(HttpCookie.getSameSiteFromComment("__SAME_SITE_NONE__"), HttpCookie.SameSite.NONE); + assertEquals(HttpCookie.getSameSiteFromComment("__SAME_SITE_LAX__"), HttpCookie.SameSite.LAX); + assertEquals(HttpCookie.getSameSiteFromComment("__SAME_SITE_STRICT__"), HttpCookie.SameSite.STRICT); + assertEquals(HttpCookie.getSameSiteFromComment("__SAME_SITE_NONE____SAME_SITE_STRICT__"), HttpCookie.SameSite.NONE); + assertNull(HttpCookie.getSameSiteFromComment("comment")); + } + + @Test + public void getCommentWithoutAttributes() + { + assertEquals(HttpCookie.getCommentWithoutAttributes("comment__SAME_SITE_NONE__"), "comment"); + assertEquals(HttpCookie.getCommentWithoutAttributes("comment__HTTP_ONLY____SAME_SITE_NONE__"), "comment"); + assertNull(HttpCookie.getCommentWithoutAttributes("__SAME_SITE_LAX__")); + } +} diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldTest.java index 64f2f76335b..101b3f1fa61 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,25 +18,25 @@ package org.eclipse.jetty.http; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.assertNull; - import java.nio.ByteBuffer; import org.eclipse.jetty.util.BufferUtil; import org.junit.jupiter.api.Test; +import static org.hamcrest.MatcherAssert.assertThat; +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.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class HttpFieldTest { @Test public void testContainsSimple() throws Exception { - HttpField field = new HttpField("name","SomeValue"); + HttpField field = new HttpField("name", "SomeValue"); assertTrue(field.contains("somevalue")); assertTrue(field.contains("sOmEvAlUe")); assertTrue(field.contains("SomeValue")); @@ -48,29 +48,29 @@ public class HttpFieldTest assertFalse(field.contains("")); assertFalse(field.contains(null)); } - + @Test public void testCaseInsensitiveHashcode_KnownField() throws Exception { - HttpField fieldFoo1 = new HttpField("Cookie","foo"); - HttpField fieldFoo2 = new HttpField("cookie","foo"); - + HttpField fieldFoo1 = new HttpField("Cookie", "foo"); + HttpField fieldFoo2 = new HttpField("cookie", "foo"); + assertThat("Field hashcodes are case insensitive", fieldFoo1.hashCode(), is(fieldFoo2.hashCode())); } - + @Test public void testCaseInsensitiveHashcode_UnknownField() throws Exception { - HttpField fieldFoo1 = new HttpField("X-Foo","bar"); - HttpField fieldFoo2 = new HttpField("x-foo","bar"); - + HttpField fieldFoo1 = new HttpField("X-Foo", "bar"); + HttpField fieldFoo2 = new HttpField("x-foo", "bar"); + assertThat("Field hashcodes are case insensitive", fieldFoo1.hashCode(), is(fieldFoo2.hashCode())); } @Test public void testContainsList() throws Exception { - HttpField field = new HttpField("name",",aaa,Bbb,CCC, ddd , e e, \"\\\"f,f\\\"\", "); + HttpField field = new HttpField("name", ",aaa,Bbb,CCC, ddd , e e, \"\\\"f,f\\\"\", "); assertTrue(field.contains("aaa")); assertTrue(field.contains("bbb")); assertTrue(field.contains("ccc")); @@ -89,98 +89,94 @@ public class HttpFieldTest assertFalse(field.contains("cc")); assertFalse(field.contains(null)); } - @Test public void testQualityContainsList() throws Exception { HttpField field; - - field = new HttpField("name","yes"); + + field = new HttpField("name", "yes"); assertTrue(field.contains("yes")); assertFalse(field.contains("no")); - field = new HttpField("name",",yes,"); + field = new HttpField("name", ",yes,"); assertTrue(field.contains("yes")); assertFalse(field.contains("no")); - - field = new HttpField("name","other,yes,other"); + + field = new HttpField("name", "other,yes,other"); assertTrue(field.contains("yes")); assertFalse(field.contains("no")); - - field = new HttpField("name","other, yes ,other"); + + field = new HttpField("name", "other, yes ,other"); assertTrue(field.contains("yes")); assertFalse(field.contains("no")); - - field = new HttpField("name","other, y s ,other"); + + field = new HttpField("name", "other, y s ,other"); assertTrue(field.contains("y s")); assertFalse(field.contains("no")); - field = new HttpField("name","other, \"yes\" ,other"); - assertTrue(field.contains("yes")); - assertFalse(field.contains("no")); - - field = new HttpField("name","other, \"\\\"yes\\\"\" ,other"); - assertTrue(field.contains("\"yes\"")); - assertFalse(field.contains("no")); - - field = new HttpField("name",";no,yes,;no"); + field = new HttpField("name", "other, \"yes\" ,other"); assertTrue(field.contains("yes")); assertFalse(field.contains("no")); - field = new HttpField("name","no;q=0,yes;q=1,no; q = 0"); + field = new HttpField("name", "other, \"\\\"yes\\\"\" ,other"); + assertTrue(field.contains("\"yes\"")); + assertFalse(field.contains("no")); + + field = new HttpField("name", ";no,yes,;no"); assertTrue(field.contains("yes")); assertFalse(field.contains("no")); - - field = new HttpField("name","no;q=0.0000,yes;q=0.0001,no; q = 0.00000"); + + field = new HttpField("name", "no;q=0,yes;q=1,no; q = 0"); assertTrue(field.contains("yes")); assertFalse(field.contains("no")); - - field = new HttpField("name","no;q=0.0000,Yes;Q=0.0001,no; Q = 0.00000"); + + field = new HttpField("name", "no;q=0.0000,yes;q=0.0001,no; q = 0.00000"); + assertTrue(field.contains("yes")); + assertFalse(field.contains("no")); + + field = new HttpField("name", "no;q=0.0000,Yes;Q=0.0001,no; Q = 0.00000"); assertTrue(field.contains("yes")); assertFalse(field.contains("no")); - } - + @Test public void testValues() { - String[] values = new HttpField("name","value").getValues(); - assertEquals(1,values.length); - assertEquals("value",values[0]); - + String[] values = new HttpField("name", "value").getValues(); + assertEquals(1, values.length); + assertEquals("value", values[0]); - values = new HttpField("name","a,b,c").getValues(); - assertEquals(3,values.length); - assertEquals("a",values[0]); - assertEquals("b",values[1]); - assertEquals("c",values[2]); + values = new HttpField("name", "a,b,c").getValues(); + assertEquals(3, values.length); + assertEquals("a", values[0]); + assertEquals("b", values[1]); + assertEquals("c", values[2]); - values = new HttpField("name","a,\"x,y,z\",c").getValues(); - assertEquals(3,values.length); - assertEquals("a",values[0]); - assertEquals("x,y,z",values[1]); - assertEquals("c",values[2]); - - values = new HttpField("name","a,\"x,\\\"p,q\\\",z\",c").getValues(); - assertEquals(3,values.length); - assertEquals("a",values[0]); - assertEquals("x,\"p,q\",z",values[1]); - assertEquals("c",values[2]); - + values = new HttpField("name", "a,\"x,y,z\",c").getValues(); + assertEquals(3, values.length); + assertEquals("a", values[0]); + assertEquals("x,y,z", values[1]); + assertEquals("c", values[2]); + + values = new HttpField("name", "a,\"x,\\\"p,q\\\",z\",c").getValues(); + assertEquals(3, values.length); + assertEquals("a", values[0]); + assertEquals("x,\"p,q\",z", values[1]); + assertEquals("c", values[2]); } - + @Test public void testCachedField() { - PreEncodedHttpField field = new PreEncodedHttpField(HttpHeader.ACCEPT,"something"); + PreEncodedHttpField field = new PreEncodedHttpField(HttpHeader.ACCEPT, "something"); ByteBuffer buf = BufferUtil.allocate(256); BufferUtil.clearToFill(buf); - field.putTo(buf,HttpVersion.HTTP_1_0); - BufferUtil.flipToFlush(buf,0); - String s=BufferUtil.toString(buf); - - assertEquals("Accept: something\r\n",s); + field.putTo(buf, HttpVersion.HTTP_1_0); + BufferUtil.flipToFlush(buf, 0); + String s = BufferUtil.toString(buf); + + assertEquals("Accept: something\r\n", s); } @Test diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsMatchers.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsMatchers.java index 4cb8e6cf917..c9ebe113287 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsMatchers.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsMatchers.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,30 +18,29 @@ package org.eclipse.jetty.http; -import org.eclipse.jetty.http.matchers.HttpFieldsContainsHeaderValue; import org.eclipse.jetty.http.matchers.HttpFieldsContainsHeaderKey; -import org.hamcrest.Factory; +import org.eclipse.jetty.http.matchers.HttpFieldsContainsHeaderValue; import org.hamcrest.Matcher; public class HttpFieldsMatchers { - @Factory - public static Matcher containsHeader(String keyName) { + public static Matcher containsHeader(String keyName) + { return new HttpFieldsContainsHeaderKey(keyName); } - @Factory - public static Matcher containsHeader(HttpHeader header) { + public static Matcher containsHeader(HttpHeader header) + { return new HttpFieldsContainsHeaderKey(header); } - @Factory - public static Matcher containsHeaderValue(String keyName, String value) { + public static Matcher containsHeaderValue(String keyName, String value) + { return new HttpFieldsContainsHeaderValue(keyName, value); } - @Factory - public static Matcher containsHeaderValue(HttpHeader header, String value) { + public static Matcher containsHeaderValue(HttpHeader header, String value) + { return new HttpFieldsContainsHeaderValue(header, value); } } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java index 7227c7d4776..2a5394e6ed0 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,15 +18,6 @@ package org.eclipse.jetty.http; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -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.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.nio.ByteBuffer; import java.util.Collections; import java.util.Enumeration; @@ -39,6 +30,17 @@ import java.util.NoSuchElementException; import org.eclipse.jetty.util.BufferUtil; import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +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.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; public class HttpFieldsTest { @@ -50,16 +52,16 @@ public class HttpFieldsTest header.put("name0", "value:0"); header.put("name1", "value1"); - assertEquals(2,header.size()); - assertEquals("value:0",header.get("name0")); - assertEquals("value1",header.get("name1")); + assertEquals(2, header.size()); + assertEquals("value:0", header.get("name0")); + assertEquals("value1", header.get("name1")); assertNull(header.get("name2")); - int matches=0; + int matches = 0; Enumeration e = header.getFieldNames(); while (e.hasMoreElements()) { - Object o=e.nextElement(); + Object o = e.nextElement(); if ("name0".equals(o)) matches++; if ("name1".equals(o)) @@ -83,15 +85,15 @@ public class HttpFieldsTest header.add("name1", "value:B"); header.add("name2", ""); - ByteBuffer buffer=BufferUtil.allocate(1024); + ByteBuffer buffer = BufferUtil.allocate(1024); BufferUtil.flipToFill(buffer); - HttpGenerator.putTo(header,buffer); - BufferUtil.flipToFlush(buffer,0); - String result=BufferUtil.toString(buffer); + HttpGenerator.putTo(header, buffer); + BufferUtil.flipToFlush(buffer, 0); + String result = BufferUtil.toString(buffer); - assertThat(result,Matchers.containsString("name0: value0")); - assertThat(result,Matchers.containsString("name1: value:A")); - assertThat(result,Matchers.containsString("name1: value:B")); + assertThat(result, Matchers.containsString("name0: value0")); + assertThat(result, Matchers.containsString("name1: value:A")); + assertThat(result, Matchers.containsString("name1: value:B")); } @Test @@ -102,21 +104,22 @@ public class HttpFieldsTest header.put("name0", "value0"); header.put("name1", "value1"); - assertEquals("value0",header.get("name0")); - assertEquals("value0",header.get("Name0")); - assertEquals("value1",header.get("name1")); - assertEquals("value1",header.get("Name1")); - assertEquals(null,header.get("Name2")); + assertEquals("value0", header.get("name0")); + assertEquals("value0", header.get("Name0")); + assertEquals("value1", header.get("name1")); + assertEquals("value1", header.get("Name1")); + assertEquals(null, header.get("Name2")); - assertEquals("value0",header.getField("name0").getValue()); - assertEquals("value0",header.getField("Name0").getValue()); - assertEquals("value1",header.getField("name1").getValue()); - assertEquals("value1",header.getField("Name1").getValue()); - assertEquals(null,header.getField("Name2")); + assertEquals("value0", header.getField("name0").getValue()); + assertEquals("value0", header.getField("Name0").getValue()); + assertEquals("value1", header.getField("name1").getValue()); + assertEquals("value1", header.getField("Name1").getValue()); + assertEquals(null, header.getField("Name2")); - assertEquals("value0",header.getField(0).getValue()); - assertEquals("value1",header.getField(1).getValue()); - assertThrows(NoSuchElementException.class, ()->{ + assertEquals("value0", header.getField(0).getValue()); + assertEquals("value1", header.getField(1).getValue()); + assertThrows(NoSuchElementException.class, () -> + { header.getField(2); }); } @@ -129,14 +132,14 @@ public class HttpFieldsTest header.put("Connection", "value0"); header.put(HttpHeader.ACCEPT, "value1"); - assertEquals("value0",header.get(HttpHeader.CONNECTION)); - assertEquals("value1",header.get(HttpHeader.ACCEPT)); + assertEquals("value0", header.get(HttpHeader.CONNECTION)); + assertEquals("value1", header.get(HttpHeader.ACCEPT)); - assertEquals("value0",header.getField(HttpHeader.CONNECTION).getValue()); - assertEquals("value1",header.getField(HttpHeader.ACCEPT).getValue()); + assertEquals("value0", header.getField(HttpHeader.CONNECTION).getValue()); + assertEquals("value1", header.getField(HttpHeader.ACCEPT).getValue()); - assertEquals(null,header.getField(HttpHeader.AGE)); - assertEquals(null,header.get(HttpHeader.AGE)); + assertEquals(null, header.getField(HttpHeader.AGE)); + assertEquals(null, header.get(HttpHeader.AGE)); } @Test @@ -150,12 +153,12 @@ public class HttpFieldsTest ByteBuffer buffer = BufferUtil.allocate(1024); BufferUtil.flipToFill(buffer); - HttpGenerator.putTo(header,buffer); - BufferUtil.flipToFlush(buffer,0); + HttpGenerator.putTo(header, buffer); + BufferUtil.flipToFlush(buffer, 0); String out = BufferUtil.toString(buffer); - assertThat(out,containsString("name0: value 0")); - assertThat(out,containsString("name??1: value1")); - assertThat(out,containsString("name?2: value: 2")); + assertThat(out, containsString("name0: value 0")); + assertThat(out, containsString("name??1: value1")); + assertThat(out, containsString("name?2: value: 2")); } @Test @@ -169,13 +172,13 @@ public class HttpFieldsTest ByteBuffer buffer = BufferUtil.allocate(1024); BufferUtil.flipToFill(buffer); - HttpGenerator.putTo(header,buffer); - BufferUtil.flipToFlush(buffer,0); + HttpGenerator.putTo(header, buffer); + BufferUtil.flipToFlush(buffer, 0); String out = BufferUtil.toString(buffer).toLowerCase(Locale.ENGLISH); - assertThat(out,Matchers.containsString((HttpHeader.CONNECTION+": "+HttpHeaderValue.KEEP_ALIVE).toLowerCase(Locale.ENGLISH))); - assertThat(out,Matchers.containsString((HttpHeader.TRANSFER_ENCODING+": "+HttpHeaderValue.CHUNKED).toLowerCase(Locale.ENGLISH))); - assertThat(out,Matchers.containsString((HttpHeader.CONTENT_ENCODING+": "+HttpHeaderValue.GZIP).toLowerCase(Locale.ENGLISH))); + assertThat(out, Matchers.containsString((HttpHeader.CONNECTION + ": " + HttpHeaderValue.KEEP_ALIVE).toLowerCase(Locale.ENGLISH))); + assertThat(out, Matchers.containsString((HttpHeader.TRANSFER_ENCODING + ": " + HttpHeaderValue.CHUNKED).toLowerCase(Locale.ENGLISH))); + assertThat(out, Matchers.containsString((HttpHeader.CONTENT_ENCODING + ": " + HttpHeaderValue.GZIP).toLowerCase(Locale.ENGLISH))); } @Test @@ -187,22 +190,22 @@ public class HttpFieldsTest header.put("name1", "xxxxxx"); header.put("name2", "value2"); - assertEquals("value0",header.get("name0")); - assertEquals("xxxxxx",header.get("name1")); - assertEquals("value2",header.get("name2")); + assertEquals("value0", header.get("name0")); + assertEquals("xxxxxx", header.get("name1")); + assertEquals("value2", header.get("name2")); header.put("name1", "value1"); - assertEquals("value0",header.get("name0")); - assertEquals("value1",header.get("name1")); - assertEquals("value2",header.get("name2")); + assertEquals("value0", header.get("name0")); + assertEquals("value1", header.get("name1")); + assertEquals("value2", header.get("name2")); assertNull(header.get("name3")); - int matches=0; + int matches = 0; Enumeration e = header.getFieldNames(); while (e.hasMoreElements()) { - String o=e.nextElement(); + String o = e.nextElement(); if ("name0".equals(o)) matches++; if ("name1".equals(o)) @@ -212,7 +215,6 @@ public class HttpFieldsTest } assertEquals(3, matches); - e = header.getValues("name1"); assertEquals(true, e.hasMoreElements()); assertEquals(e.nextElement(), "value1"); @@ -228,22 +230,22 @@ public class HttpFieldsTest header.put("name1", "value1"); header.put("name2", "value2"); - assertEquals("value0",header.get("name0")); - assertEquals("value1",header.get("name1")); - assertEquals("value2",header.get("name2")); + assertEquals("value0", header.get("name0")); + assertEquals("value1", header.get("name1")); + assertEquals("value2", header.get("name2")); header.remove("name1"); - assertEquals("value0",header.get("name0")); + assertEquals("value0", header.get("name0")); assertNull(header.get("name1")); - assertEquals("value2",header.get("name2")); + assertEquals("value2", header.get("name2")); assertNull(header.get("name3")); - int matches=0; + int matches = 0; Enumeration e = header.getFieldNames(); while (e.hasMoreElements()) { - Object o=e.nextElement(); + Object o = e.nextElement(); if ("name0".equals(o)) matches++; if ("name1".equals(o)) @@ -266,22 +268,22 @@ public class HttpFieldsTest fields.add("name1", "valueA"); fields.add("name2", "value2"); - assertEquals("value0",fields.get("name0")); - assertEquals("valueA",fields.get("name1")); - assertEquals("value2",fields.get("name2")); + assertEquals("value0", fields.get("name0")); + assertEquals("valueA", fields.get("name1")); + assertEquals("value2", fields.get("name2")); fields.add("name1", "valueB"); - assertEquals("value0",fields.get("name0")); - assertEquals("valueA",fields.get("name1")); - assertEquals("value2",fields.get("name2")); + assertEquals("value0", fields.get("name0")); + assertEquals("valueA", fields.get("name1")); + assertEquals("value2", fields.get("name2")); assertNull(fields.get("name3")); - int matches=0; + int matches = 0; Enumeration e = fields.getFieldNames(); while (e.hasMoreElements()) { - Object o=e.nextElement(); + Object o = e.nextElement(); if ("name0".equals(o)) matches++; if ("name1".equals(o)) @@ -299,6 +301,46 @@ public class HttpFieldsTest assertEquals(false, e.hasMoreElements()); } + @Test + public void testPreEncodedField() + { + ByteBuffer buffer = BufferUtil.allocate(1024); + + PreEncodedHttpField known = new PreEncodedHttpField(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString()); + BufferUtil.clearToFill(buffer); + known.putTo(buffer, HttpVersion.HTTP_1_1); + BufferUtil.flipToFlush(buffer, 0); + assertThat(BufferUtil.toString(buffer), is("Connection: close\r\n")); + + PreEncodedHttpField unknown = new PreEncodedHttpField(null, "Header", "Value"); + BufferUtil.clearToFill(buffer); + unknown.putTo(buffer, HttpVersion.HTTP_1_1); + BufferUtil.flipToFlush(buffer, 0); + assertThat(BufferUtil.toString(buffer), is("Header: Value\r\n")); + } + + @Test + public void testAddPreEncodedField() + { + final PreEncodedHttpField X_XSS_PROTECTION_FIELD = new PreEncodedHttpField("X-XSS-Protection", "1; mode=block"); + + HttpFields fields = new HttpFields(); + fields.add(X_XSS_PROTECTION_FIELD); + + assertThat("Fields output", fields.toString(), containsString("X-XSS-Protection: 1; mode=block")); + } + + @Test + public void testAddFinalHttpField() + { + final HttpField X_XSS_PROTECTION_FIELD = new HttpField("X-XSS-Protection", "1; mode=block"); + + HttpFields fields = new HttpFields(); + fields.add(X_XSS_PROTECTION_FIELD); + + assertThat("Fields output", fields.toString(), containsString("X-XSS-Protection: 1; mode=block")); + } + @Test public void testGetValues() throws Exception { @@ -316,7 +358,7 @@ public class HttpFieldsTest assertEquals(e.nextElement(), "value0C,value0D"); assertEquals(false, e.hasMoreElements()); - e = fields.getValues("name0",","); + e = fields.getValues("name0", ","); assertEquals(true, e.hasMoreElements()); assertEquals(e.nextElement(), "value0A"); assertEquals(true, e.hasMoreElements()); @@ -327,7 +369,7 @@ public class HttpFieldsTest assertEquals(e.nextElement(), "value0D"); assertEquals(false, e.hasMoreElements()); - e = fields.getValues("name1",","); + e = fields.getValues("name1", ","); assertEquals(true, e.hasMoreElements()); assertEquals(e.nextElement(), "value1A"); assertEquals(true, e.hasMoreElements()); @@ -356,7 +398,7 @@ public class HttpFieldsTest assertEquals(e.nextElement(), "value0C,value0D"); assertEquals(false, e.hasMoreElements()); - e = Collections.enumeration(fields.getCSV("name0",false)); + e = Collections.enumeration(fields.getCSV("name0", false)); assertEquals(true, e.hasMoreElements()); assertEquals(e.nextElement(), "value0A"); assertEquals(true, e.hasMoreElements()); @@ -367,7 +409,7 @@ public class HttpFieldsTest assertEquals(e.nextElement(), "value0D"); assertEquals(false, e.hasMoreElements()); - e = Collections.enumeration(fields.getCSV("name1",false)); + e = Collections.enumeration(fields.getCSV("name1", false)); assertEquals(true, e.hasMoreElements()); assertEquals(e.nextElement(), "value1A"); assertEquals(true, e.hasMoreElements()); @@ -391,16 +433,16 @@ public class HttpFieldsTest fields.add("name", "three"); fields.add("name", "four, I V"); - List list = fields.getCSV("name",false); + List list = fields.getCSV("name", false); assertEquals(HttpFields.valueParameters(list.get(0), null), "zero"); assertEquals(HttpFields.valueParameters(list.get(1), null), "one"); assertEquals(HttpFields.valueParameters(list.get(2), null), "1 + 1"); assertEquals(HttpFields.valueParameters(list.get(3), null), "three"); assertEquals(HttpFields.valueParameters(list.get(4), null), "four"); assertEquals(HttpFields.valueParameters(list.get(5), null), "I V"); - - fields.addCSV("name","six"); - list = fields.getCSV("name",false); + + fields.addCSV("name", "six"); + list = fields.getCSV("name", false); assertEquals(HttpFields.valueParameters(list.get(0), null), "zero"); assertEquals(HttpFields.valueParameters(list.get(1), null), "one"); assertEquals(HttpFields.valueParameters(list.get(2), null), "1 + 1"); @@ -408,9 +450,9 @@ public class HttpFieldsTest assertEquals(HttpFields.valueParameters(list.get(4), null), "four"); assertEquals(HttpFields.valueParameters(list.get(5), null), "I V"); assertEquals(HttpFields.valueParameters(list.get(6), null), "six"); - - fields.addCSV("name","1 + 1","7","zero"); - list = fields.getCSV("name",false); + + fields.addCSV("name", "1 + 1", "7", "zero"); + list = fields.getCSV("name", false); assertEquals(HttpFields.valueParameters(list.get(0), null), "zero"); assertEquals(HttpFields.valueParameters(list.get(1), null), "one"); assertEquals(HttpFields.valueParameters(list.get(2), null), "1 + 1"); @@ -420,7 +462,7 @@ public class HttpFieldsTest assertEquals(HttpFields.valueParameters(list.get(6), null), "six"); assertEquals(HttpFields.valueParameters(list.get(7), null), "7"); } - + @Test public void testGetQualityCSV() throws Exception { @@ -434,7 +476,6 @@ public class HttpFieldsTest fields.add("name", "three;x=y;q=0.2;a=b,two;q=0.3"); fields.add("name", "first;"); - List list = fields.getQualityCSV("name"); assertEquals(HttpFields.valueParameters(list.get(0), null), "first"); assertEquals(HttpFields.valueParameters(list.get(1), null), "zero"); @@ -443,7 +484,7 @@ public class HttpFieldsTest assertEquals(HttpFields.valueParameters(list.get(4), null), "three"); assertEquals(HttpFields.valueParameters(list.get(5), null), "four"); } - + @Test public void testGetQualityCSVHeader() throws Exception { @@ -457,7 +498,6 @@ public class HttpFieldsTest fields.add("Accept", "three;x=y;q=0.2;a=b,two;q=0.3"); fields.add("Accept", "first;"); - List list = fields.getQualityCSV(HttpHeader.ACCEPT); assertEquals(HttpFields.valueParameters(list.get(0), null), "first"); assertEquals(HttpFields.valueParameters(list.get(1), null), "zero"); @@ -467,7 +507,6 @@ public class HttpFieldsTest assertEquals(HttpFields.valueParameters(list.get(5), null), "four"); } - @Test public void testDateFields() throws Exception { @@ -486,28 +525,28 @@ public class HttpFieldsTest long d3 = fields.getDateField("D3"); long d4 = fields.getDateField("D4"); long d5 = fields.getDateField("D5"); - assertTrue(d0!=-1); - assertTrue(d1>0); - assertTrue(d2>0); - assertEquals(d1,d2); - assertEquals(d2,d3); - assertEquals(d3+2000,d4); - assertEquals(951825600000L,d5); + assertTrue(d0 != -1); + assertTrue(d1 > 0); + assertTrue(d2 > 0); + assertEquals(d1, d2); + assertEquals(d2, d3); + assertEquals(d3 + 2000, d4); + assertEquals(951825600000L, d5); d1 = fields.getDateField("D1"); d2 = fields.getDateField("D2"); d3 = fields.getDateField("D3"); d4 = fields.getDateField("D4"); d5 = fields.getDateField("D5"); - assertTrue(d1>0); - assertTrue(d2>0); - assertEquals(d1,d2); - assertEquals(d2,d3); - assertEquals(d3+2000,d4); - assertEquals(951825600000L,d5); + assertTrue(d1 > 0); + assertTrue(d2 > 0); + assertEquals(d1, d2); + assertEquals(d2, d3); + assertEquals(d3 + 2000, d4); + assertEquals(951825600000L, d5); - fields.putDateField("D2",d1); - assertEquals("Fri, 31 Dec 1999 23:59:59 GMT",fields.get("D2")); + fields.putDateField("D2", d1); + assertEquals("Fri, 31 Dec 1999 23:59:59 GMT", fields.get("D2")); } @Test @@ -515,17 +554,17 @@ public class HttpFieldsTest { HttpFields fields = new HttpFields(); - fields.putDateField("Dzero",0); - assertEquals("Thu, 01 Jan 1970 00:00:00 GMT",fields.get("Dzero")); + fields.putDateField("Dzero", 0); + assertEquals("Thu, 01 Jan 1970 00:00:00 GMT", fields.get("Dzero")); - fields.putDateField("Dminus",-1); - assertEquals("Wed, 31 Dec 1969 23:59:59 GMT",fields.get("Dminus")); + fields.putDateField("Dminus", -1); + assertEquals("Wed, 31 Dec 1969 23:59:59 GMT", fields.get("Dminus")); - fields.putDateField("Dminus",-1000); - assertEquals("Wed, 31 Dec 1969 23:59:59 GMT",fields.get("Dminus")); + fields.putDateField("Dminus", -1000); + assertEquals("Wed, 31 Dec 1969 23:59:59 GMT", fields.get("Dminus")); - fields.putDateField("Dancient",Long.MIN_VALUE); - assertEquals("Sun, 02 Dec 55 16:47:04 GMT",fields.get("Dancient")); + fields.putDateField("Dancient", Long.MIN_VALUE); + assertEquals("Sun, 02 Dec 55 16:47:04 GMT", fields.get("Dancient")); } @Test @@ -540,54 +579,56 @@ public class HttpFieldsTest header.put("N1", " - "); header.put("N2", "xx"); - long i1=header.getLongField("I1"); + long i1 = header.getLongField("I1"); try { header.getLongField("I2"); assertTrue(false); } - catch(NumberFormatException e) + catch (NumberFormatException e) { assertTrue(true); } - long i3=header.getLongField("I3"); + long i3 = header.getLongField("I3"); try { header.getLongField("I4"); assertTrue(false); } - catch(NumberFormatException e) + catch (NumberFormatException e) { assertTrue(true); } - try{ + try + { header.getLongField("N1"); assertTrue(false); } - catch(NumberFormatException e) + catch (NumberFormatException e) { assertTrue(true); } - try{ + try + { header.getLongField("N2"); assertTrue(false); } - catch(NumberFormatException e) + catch (NumberFormatException e) { assertTrue(true); } - assertEquals(42,i1); - assertEquals(-44,i3); + assertEquals(42, i1); + assertEquals(-44, i3); header.putLongField("I5", 46); - header.putLongField("I6",-47); - assertEquals("46",header.get("I5")); - assertEquals("-47",header.get("I6")); + header.putLongField("I6", -47); + assertEquals("46", header.get("I5")); + assertEquals("-47", header.get("I6")); } @Test @@ -608,87 +649,119 @@ public class HttpFieldsTest header.add("n8", "abc , def;q=0 , hig"); header.add(HttpHeader.ACCEPT, "abc , def;q=0 , hig"); - for (int i=0;i<8;i++) + for (int i = 0; i < 8; i++) { - assertTrue(header.containsKey("n"+i)); - assertTrue(header.containsKey("N"+i)); - assertFalse(header.contains("n"+i,"xyz"),""+i); - assertEquals(i>=4,header.contains("n"+i, "def"), ""+i); + assertTrue(header.containsKey("n" + i)); + assertTrue(header.containsKey("N" + i)); + assertFalse(header.contains("n" + i, "xyz"), "" + i); + assertEquals(i >= 4, header.contains("n" + i, "def"), "" + i); } - - assertTrue(header.contains(new HttpField("N5","def"))); - assertTrue(header.contains(new HttpField("accept","abc"))); - assertTrue(header.contains(HttpHeader.ACCEPT,"abc")); - assertFalse(header.contains(new HttpField("N5","xyz"))); - assertFalse(header.contains(new HttpField("N8","def"))); - assertFalse(header.contains(HttpHeader.ACCEPT,"def")); - assertFalse(header.contains(HttpHeader.AGE,"abc")); + assertTrue(header.contains(new HttpField("N5", "def"))); + assertTrue(header.contains(new HttpField("accept", "abc"))); + assertTrue(header.contains(HttpHeader.ACCEPT, "abc")); + assertFalse(header.contains(new HttpField("N5", "xyz"))); + assertFalse(header.contains(new HttpField("N8", "def"))); + assertFalse(header.contains(HttpHeader.ACCEPT, "def")); + assertFalse(header.contains(HttpHeader.AGE, "abc")); assertFalse(header.containsKey("n11")); } - + + @ParameterizedTest + @ValueSource(strings = {"Host", "host", "HOST", "HoSt", "Connection", "CONNECTION", "connection", "CoNnEcTiOn"}) + public void testContainsKeyTrue(String keyName) + { + HttpFields fields = new HttpFields(); + fields.put("Host", "localhost"); + HttpField namelessField = new HttpField(HttpHeader.CONNECTION, null, "bogus"); + fields.put(namelessField); + + assertTrue(fields.containsKey(keyName), "containsKey('" + keyName + "')"); + } + + @ParameterizedTest + @ValueSource(strings = {"Content-Type", "Content-Length", "X-Bogus", ""}) + public void testContainsKeyFalse(String keyName) + { + HttpFields fields = new HttpFields(); + fields.add("Host", "localhost"); + HttpField namelessField = new HttpField(HttpHeader.CONNECTION, null, "bogus"); + fields.put(namelessField); + + assertFalse(fields.containsKey(keyName), "containsKey('" + keyName + "')"); + } + + @Test + public void testPreventNullField() + { + HttpFields fields = new HttpFields(); + assertThrows(NullPointerException.class, () -> + { + HttpField nullNullField = new HttpField(null, null, "bogus"); + fields.put(nullNullField); + }); + } @Test public void testIteration() throws Exception { HttpFields header = new HttpFields(); Iterator i = header.iterator(); - assertThat(i.hasNext(),is(false)); + assertThat(i.hasNext(), is(false)); header.put("name1", "valueA"); header.put("name2", "valueB"); header.add("name3", "valueC"); i = header.iterator(); - assertThat(i.hasNext(),is(true)); - assertThat(i.next().getName(),is("name1")); - assertThat(i.next().getName(),is("name2")); + assertThat(i.hasNext(), is(true)); + assertThat(i.next().getName(), is("name1")); + assertThat(i.next().getName(), is("name2")); i.remove(); - assertThat(i.next().getName(),is("name3")); - assertThat(i.hasNext(),is(false)); - + assertThat(i.next().getName(), is("name3")); + assertThat(i.hasNext(), is(false)); + i = header.iterator(); - assertThat(i.hasNext(),is(true)); - assertThat(i.next().getName(),is("name1")); - assertThat(i.next().getName(),is("name3")); - assertThat(i.hasNext(),is(false)); - - + assertThat(i.hasNext(), is(true)); + assertThat(i.next().getName(), is("name1")); + assertThat(i.next().getName(), is("name3")); + assertThat(i.hasNext(), is(false)); + ListIterator l = header.listIterator(); - assertThat(l.hasNext(),is(true)); - l.add(new HttpField("name0","value")); - assertThat(l.hasNext(),is(true)); - assertThat(l.next().getName(),is("name1")); - l.set(new HttpField("NAME1","value")); - assertThat(l.hasNext(),is(true)); - assertThat(l.hasPrevious(),is(true)); - assertThat(l.previous().getName(),is("NAME1")); - assertThat(l.hasNext(),is(true)); - assertThat(l.hasPrevious(),is(true)); - assertThat(l.previous().getName(),is("name0")); - assertThat(l.hasNext(),is(true)); - assertThat(l.hasPrevious(),is(false)); - assertThat(l.next().getName(),is("name0")); - assertThat(l.hasNext(),is(true)); - assertThat(l.hasPrevious(),is(true)); - assertThat(l.next().getName(),is("NAME1")); - l.add(new HttpField("name2","value")); - assertThat(l.next().getName(),is("name3")); - assertThat(l.hasNext(),is(false)); - assertThat(l.hasPrevious(),is(true)); - l.add(new HttpField("name4","value")); - assertThat(l.hasNext(),is(false)); - assertThat(l.hasPrevious(),is(true)); - assertThat(l.previous().getName(),is("name4")); - + assertThat(l.hasNext(), is(true)); + l.add(new HttpField("name0", "value")); + assertThat(l.hasNext(), is(true)); + assertThat(l.next().getName(), is("name1")); + l.set(new HttpField("NAME1", "value")); + assertThat(l.hasNext(), is(true)); + assertThat(l.hasPrevious(), is(true)); + assertThat(l.previous().getName(), is("NAME1")); + assertThat(l.hasNext(), is(true)); + assertThat(l.hasPrevious(), is(true)); + assertThat(l.previous().getName(), is("name0")); + assertThat(l.hasNext(), is(true)); + assertThat(l.hasPrevious(), is(false)); + assertThat(l.next().getName(), is("name0")); + assertThat(l.hasNext(), is(true)); + assertThat(l.hasPrevious(), is(true)); + assertThat(l.next().getName(), is("NAME1")); + l.add(new HttpField("name2", "value")); + assertThat(l.next().getName(), is("name3")); + assertThat(l.hasNext(), is(false)); + assertThat(l.hasPrevious(), is(true)); + l.add(new HttpField("name4", "value")); + assertThat(l.hasNext(), is(false)); + assertThat(l.hasPrevious(), is(true)); + assertThat(l.previous().getName(), is("name4")); + i = header.iterator(); - assertThat(i.hasNext(),is(true)); - assertThat(i.next().getName(),is("name0")); - assertThat(i.next().getName(),is("NAME1")); - assertThat(i.next().getName(),is("name2")); - assertThat(i.next().getName(),is("name3")); - assertThat(i.next().getName(),is("name4")); - assertThat(i.hasNext(),is(false)); + assertThat(i.hasNext(), is(true)); + assertThat(i.next().getName(), is("name0")); + assertThat(i.next().getName(), is("NAME1")); + assertThat(i.next().getName(), is("name2")); + assertThat(i.next().getName(), is("name3")); + assertThat(i.next().getName(), is("name4")); + assertThat(i.hasNext(), is(false)); } } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorClientTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorClientTest.java index 941900584ea..01d965be55d 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorClientTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorClientTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,62 +18,61 @@ package org.eclipse.jetty.http; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.nio.ByteBuffer; import org.eclipse.jetty.util.BufferUtil; import org.hamcrest.Matchers; - import org.junit.jupiter.api.Test; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class HttpGeneratorClientTest { - public final static String[] connect={null,"keep-alive","close"}; + public static final String[] connect = {null, "keep-alive", "close"}; class Info extends MetaData.Request { - Info(String method,String uri) + Info(String method, String uri) { - super(method,new HttpURI(uri),HttpVersion.HTTP_1_1,new HttpFields(),-1); + super(method, new HttpURI(uri), HttpVersion.HTTP_1_1, new HttpFields(), -1); } - public Info(String method,String uri, int contentLength) + public Info(String method, String uri, int contentLength) { - super(method,new HttpURI(uri),HttpVersion.HTTP_1_1,new HttpFields(),contentLength); + super(method, new HttpURI(uri), HttpVersion.HTTP_1_1, new HttpFields(), contentLength); } } @Test public void testGETRequestNoContent() throws Exception { - ByteBuffer header=BufferUtil.allocate(2048); + ByteBuffer header = BufferUtil.allocate(2048); HttpGenerator gen = new HttpGenerator(); HttpGenerator.Result - result=gen.generateRequest(null,null,null,null, true); + result = gen.generateRequest(null, null, null, null, true); assertEquals(HttpGenerator.Result.NEED_INFO, result); assertEquals(HttpGenerator.State.START, gen.getState()); - Info info = new Info("GET","/index.html"); - info.getFields().add("Host","something"); - info.getFields().add("User-Agent","test"); + Info info = new Info("GET", "/index.html"); + info.getFields().add("Host", "something"); + info.getFields().add("User-Agent", "test"); assertTrue(!gen.isChunking()); - result=gen.generateRequest(info,null,null,null, true); + result = gen.generateRequest(info, null, null, null, true); assertEquals(HttpGenerator.Result.NEED_HEADER, result); assertEquals(HttpGenerator.State.START, gen.getState()); - result=gen.generateRequest(info,header,null,null, true); + result = gen.generateRequest(info, header, null, null, true); assertEquals(HttpGenerator.Result.FLUSH, result); assertEquals(HttpGenerator.State.COMPLETING, gen.getState()); assertTrue(!gen.isChunking()); String out = BufferUtil.toString(header); BufferUtil.clear(header); - result=gen.generateResponse(null,false,null,null, null, false); + result = gen.generateResponse(null, false, null, null, null, false); assertEquals(HttpGenerator.Result.DONE, result); assertEquals(HttpGenerator.State.END, gen.getState()); assertTrue(!gen.isChunking()); @@ -86,32 +85,32 @@ public class HttpGeneratorClientTest @Test public void testEmptyHeaders() throws Exception { - ByteBuffer header=BufferUtil.allocate(2048); + ByteBuffer header = BufferUtil.allocate(2048); HttpGenerator gen = new HttpGenerator(); HttpGenerator.Result - result=gen.generateRequest(null,null,null,null, true); + result = gen.generateRequest(null, null, null, null, true); assertEquals(HttpGenerator.Result.NEED_INFO, result); assertEquals(HttpGenerator.State.START, gen.getState()); - Info info = new Info("GET","/index.html"); - info.getFields().add("Host","something"); - info.getFields().add("Null",null); - info.getFields().add("Empty",""); + Info info = new Info("GET", "/index.html"); + info.getFields().add("Host", "something"); + info.getFields().add("Null", null); + info.getFields().add("Empty", ""); assertTrue(!gen.isChunking()); - result=gen.generateRequest(info,null,null,null, true); + result = gen.generateRequest(info, null, null, null, true); assertEquals(HttpGenerator.Result.NEED_HEADER, result); assertEquals(HttpGenerator.State.START, gen.getState()); - result=gen.generateRequest(info,header,null,null, true); + result = gen.generateRequest(info, header, null, null, true); assertEquals(HttpGenerator.Result.FLUSH, result); assertEquals(HttpGenerator.State.COMPLETING, gen.getState()); assertTrue(!gen.isChunking()); String out = BufferUtil.toString(header); BufferUtil.clear(header); - result=gen.generateResponse(null,false,null,null, null, false); + result = gen.generateResponse(null, false, null, null, null, false); assertEquals(HttpGenerator.Result.DONE, result); assertEquals(HttpGenerator.State.END, gen.getState()); assertTrue(!gen.isChunking()); @@ -122,36 +121,35 @@ public class HttpGeneratorClientTest assertThat(out, Matchers.containsString("Empty:")); assertThat(out, Matchers.not(Matchers.containsString("Null:"))); } - - + @Test public void testPOSTRequestNoContent() throws Exception { - ByteBuffer header=BufferUtil.allocate(2048); + ByteBuffer header = BufferUtil.allocate(2048); HttpGenerator gen = new HttpGenerator(); HttpGenerator.Result - result=gen.generateRequest(null,null,null,null, true); + result = gen.generateRequest(null, null, null, null, true); assertEquals(HttpGenerator.Result.NEED_INFO, result); assertEquals(HttpGenerator.State.START, gen.getState()); - Info info = new Info("POST","/index.html"); - info.getFields().add("Host","something"); - info.getFields().add("User-Agent","test"); + Info info = new Info("POST", "/index.html"); + info.getFields().add("Host", "something"); + info.getFields().add("User-Agent", "test"); assertTrue(!gen.isChunking()); - result=gen.generateRequest(info,null,null,null, true); + result = gen.generateRequest(info, null, null, null, true); assertEquals(HttpGenerator.Result.NEED_HEADER, result); assertEquals(HttpGenerator.State.START, gen.getState()); - result=gen.generateRequest(info,header,null,null, true); + result = gen.generateRequest(info, header, null, null, true); assertEquals(HttpGenerator.Result.FLUSH, result); assertEquals(HttpGenerator.State.COMPLETING, gen.getState()); assertTrue(!gen.isChunking()); String out = BufferUtil.toString(header); BufferUtil.clear(header); - result=gen.generateResponse(null,false,null,null, null, false); + result = gen.generateResponse(null, false, null, null, null, false); assertEquals(HttpGenerator.Result.DONE, result); assertEquals(HttpGenerator.State.END, gen.getState()); assertTrue(!gen.isChunking()); @@ -165,38 +163,37 @@ public class HttpGeneratorClientTest public void testRequestWithContent() throws Exception { String out; - ByteBuffer header=BufferUtil.allocate(4096); - ByteBuffer content0=BufferUtil.toBuffer("Hello World. The quick brown fox jumped over the lazy dog."); + ByteBuffer header = BufferUtil.allocate(4096); + ByteBuffer content0 = BufferUtil.toBuffer("Hello World. The quick brown fox jumped over the lazy dog."); HttpGenerator gen = new HttpGenerator(); HttpGenerator.Result - result=gen.generateRequest(null,null,null,content0, true); + result = gen.generateRequest(null, null, null, content0, true); assertEquals(HttpGenerator.Result.NEED_INFO, result); assertEquals(HttpGenerator.State.START, gen.getState()); - Info info = new Info("POST","/index.html"); - info.getFields().add("Host","something"); - info.getFields().add("User-Agent","test"); + Info info = new Info("POST", "/index.html"); + info.getFields().add("Host", "something"); + info.getFields().add("User-Agent", "test"); - result=gen.generateRequest(info,null,null,content0, true); + result = gen.generateRequest(info, null, null, content0, true); assertEquals(HttpGenerator.Result.NEED_HEADER, result); assertEquals(HttpGenerator.State.START, gen.getState()); - result=gen.generateRequest(info,header,null,content0, true); + result = gen.generateRequest(info, header, null, content0, true); assertEquals(HttpGenerator.Result.FLUSH, result); assertEquals(HttpGenerator.State.COMPLETING, gen.getState()); assertTrue(!gen.isChunking()); out = BufferUtil.toString(header); BufferUtil.clear(header); - out+=BufferUtil.toString(content0); + out += BufferUtil.toString(content0); BufferUtil.clear(content0); - result=gen.generateResponse(null,false,null,null, null, false); + result = gen.generateResponse(null, false, null, null, null, false); assertEquals(HttpGenerator.Result.DONE, result); assertEquals(HttpGenerator.State.END, gen.getState()); assertTrue(!gen.isChunking()); - assertThat(out, Matchers.containsString("POST /index.html HTTP/1.1")); assertThat(out, Matchers.containsString("Host: something")); assertThat(out, Matchers.containsString("Content-Length: 58")); @@ -209,60 +206,60 @@ public class HttpGeneratorClientTest public void testRequestWithChunkedContent() throws Exception { String out; - ByteBuffer header=BufferUtil.allocate(4096); - ByteBuffer chunk=BufferUtil.allocate(HttpGenerator.CHUNK_SIZE); - ByteBuffer content0=BufferUtil.toBuffer("Hello World. "); - ByteBuffer content1=BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog."); + ByteBuffer header = BufferUtil.allocate(4096); + ByteBuffer chunk = BufferUtil.allocate(HttpGenerator.CHUNK_SIZE); + ByteBuffer content0 = BufferUtil.toBuffer("Hello World. "); + ByteBuffer content1 = BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog."); HttpGenerator gen = new HttpGenerator(); HttpGenerator.Result - result=gen.generateRequest(null,null,null,content0, false); + result = gen.generateRequest(null, null, null, content0, false); assertEquals(HttpGenerator.Result.NEED_INFO, result); assertEquals(HttpGenerator.State.START, gen.getState()); - Info info = new Info("POST","/index.html"); - info.getFields().add("Host","something"); - info.getFields().add("User-Agent","test"); + Info info = new Info("POST", "/index.html"); + info.getFields().add("Host", "something"); + info.getFields().add("User-Agent", "test"); - result=gen.generateRequest(info,null,null,content0, false); + result = gen.generateRequest(info, null, null, content0, false); assertEquals(HttpGenerator.Result.NEED_HEADER, result); assertEquals(HttpGenerator.State.START, gen.getState()); - result=gen.generateRequest(info,header,null,content0, false); + result = gen.generateRequest(info, header, null, content0, false); assertEquals(HttpGenerator.Result.FLUSH, result); assertEquals(HttpGenerator.State.COMMITTED, gen.getState()); assertTrue(gen.isChunking()); out = BufferUtil.toString(header); BufferUtil.clear(header); - out+=BufferUtil.toString(content0); + out += BufferUtil.toString(content0); BufferUtil.clear(content0); - result=gen.generateRequest(null,header,null,content1, false); + result = gen.generateRequest(null, header, null, content1, false); assertEquals(HttpGenerator.Result.NEED_CHUNK, result); assertEquals(HttpGenerator.State.COMMITTED, gen.getState()); - result=gen.generateRequest(null,null,chunk,content1, false); + result = gen.generateRequest(null, null, chunk, content1, false); assertEquals(HttpGenerator.Result.FLUSH, result); assertEquals(HttpGenerator.State.COMMITTED, gen.getState()); assertTrue(gen.isChunking()); - out+=BufferUtil.toString(chunk); + out += BufferUtil.toString(chunk); BufferUtil.clear(chunk); - out+=BufferUtil.toString(content1); + out += BufferUtil.toString(content1); BufferUtil.clear(content1); - result=gen.generateResponse(null,false,null,chunk, null, true); + result = gen.generateResponse(null, false, null, chunk, null, true); assertEquals(HttpGenerator.Result.CONTINUE, result); assertEquals(HttpGenerator.State.COMPLETING, gen.getState()); assertTrue(gen.isChunking()); - result=gen.generateResponse(null,false,null,chunk, null, true); + result = gen.generateResponse(null, false, null, chunk, null, true); assertEquals(HttpGenerator.Result.FLUSH, result); assertEquals(HttpGenerator.State.COMPLETING, gen.getState()); - out+=BufferUtil.toString(chunk); + out += BufferUtil.toString(chunk); BufferUtil.clear(chunk); assertTrue(!gen.isChunking()); - result=gen.generateResponse(null,false,null,chunk, null, true); + result = gen.generateResponse(null, false, null, chunk, null, true); assertEquals(HttpGenerator.Result.DONE, result); assertEquals(HttpGenerator.State.END, gen.getState()); @@ -274,57 +271,56 @@ public class HttpGeneratorClientTest assertThat(out, Matchers.containsString("\r\n0\r\n\r\n")); assertEquals(58, gen.getContentPrepared()); - } @Test public void testRequestWithKnownContent() throws Exception { String out; - ByteBuffer header=BufferUtil.allocate(4096); - ByteBuffer chunk=BufferUtil.allocate(HttpGenerator.CHUNK_SIZE); - ByteBuffer content0=BufferUtil.toBuffer("Hello World. "); - ByteBuffer content1=BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog."); + ByteBuffer header = BufferUtil.allocate(4096); + ByteBuffer chunk = BufferUtil.allocate(HttpGenerator.CHUNK_SIZE); + ByteBuffer content0 = BufferUtil.toBuffer("Hello World. "); + ByteBuffer content1 = BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog."); HttpGenerator gen = new HttpGenerator(); HttpGenerator.Result - result=gen.generateRequest(null,null,null,content0, false); + result = gen.generateRequest(null, null, null, content0, false); assertEquals(HttpGenerator.Result.NEED_INFO, result); assertEquals(HttpGenerator.State.START, gen.getState()); - Info info = new Info("POST","/index.html",58); - info.getFields().add("Host","something"); - info.getFields().add("User-Agent","test"); + Info info = new Info("POST", "/index.html", 58); + info.getFields().add("Host", "something"); + info.getFields().add("User-Agent", "test"); - result=gen.generateRequest(info,null,null,content0, false); + result = gen.generateRequest(info, null, null, content0, false); assertEquals(HttpGenerator.Result.NEED_HEADER, result); assertEquals(HttpGenerator.State.START, gen.getState()); - result=gen.generateRequest(info,header,null,content0, false); + result = gen.generateRequest(info, header, null, content0, false); assertEquals(HttpGenerator.Result.FLUSH, result); assertEquals(HttpGenerator.State.COMMITTED, gen.getState()); assertTrue(!gen.isChunking()); out = BufferUtil.toString(header); BufferUtil.clear(header); - out+=BufferUtil.toString(content0); + out += BufferUtil.toString(content0); BufferUtil.clear(content0); - result=gen.generateRequest(null,null,null,content1, false); + result = gen.generateRequest(null, null, null, content1, false); assertEquals(HttpGenerator.Result.FLUSH, result); assertEquals(HttpGenerator.State.COMMITTED, gen.getState()); assertTrue(!gen.isChunking()); - out+=BufferUtil.toString(content1); + out += BufferUtil.toString(content1); BufferUtil.clear(content1); - result=gen.generateResponse(null,false,null,null, null, true); + result = gen.generateResponse(null, false, null, null, null, true); assertEquals(HttpGenerator.Result.CONTINUE, result); assertEquals(HttpGenerator.State.COMPLETING, gen.getState()); assertTrue(!gen.isChunking()); - result=gen.generateResponse(null,false,null,null, null, true); + result = gen.generateResponse(null, false, null, null, null, true); assertEquals(HttpGenerator.Result.DONE, result); assertEquals(HttpGenerator.State.END, gen.getState()); - out+=BufferUtil.toString(chunk); + out += BufferUtil.toString(chunk); BufferUtil.clear(chunk); assertThat(out, Matchers.containsString("POST /index.html HTTP/1.1")); @@ -333,7 +329,5 @@ public class HttpGeneratorClientTest assertThat(out, Matchers.containsString("\r\n\r\nHello World. The quick brown fox jumped over the lazy dog.")); assertEquals(58, gen.getContentPrepared()); - } - } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerHTTPTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerHTTPTest.java index 59168afee43..431bc0eef56 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerHTTPTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerHTTPTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,12 +18,6 @@ package org.eclipse.jetty.http; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.either; -import static org.hamcrest.Matchers.equalTo; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.EnumSet; @@ -34,6 +28,12 @@ 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.either; +import static org.hamcrest.Matchers.equalTo; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class HttpGeneratorServerHTTPTest { private String _content; @@ -163,7 +163,6 @@ public class HttpGeneratorServerHTTPTest chunk = BufferUtil.allocate(2048); continue; - case FLUSH: if (BufferUtil.hasContent(header)) { @@ -268,7 +267,7 @@ public class HttpGeneratorServerHTTPTest } } - public final static String CONTENT = "The quick brown fox jumped over the lazy dog.\nNow is the time for all good men to come to the aid of the party\nThe moon is blue to a fish in love.\n"; + public static final String CONTENT = "The quick brown fox jumped over the lazy dog.\nNow is the time for all good men to come to the aid of the party\nThe moon is blue to a fish in love.\n"; private static class Run { @@ -321,18 +320,17 @@ public class HttpGeneratorServerHTTPTest } } - public static Stream data() { Result[] results = { - new Result(200, null, -1, null, false), - new Result(200, null, -1, CONTENT, false), - new Result(200, null, CONTENT.length(), null, true), - new Result(200, null, CONTENT.length(), CONTENT, false), - new Result(200, "text/html", -1, null, true), - new Result(200, "text/html", -1, CONTENT, false), - new Result(200, "text/html", CONTENT.length(), null, true), - new Result(200, "text/html", CONTENT.length(), CONTENT, false) + new Result(200, null, -1, null, false), + new Result(200, null, -1, CONTENT, false), + new Result(200, null, CONTENT.length(), null, true), + new Result(200, null, CONTENT.length(), CONTENT, false), + new Result(200, "text/html", -1, null, true), + new Result(200, "text/html", -1, CONTENT, false), + new Result(200, "text/html", CONTENT.length(), null, true), + new Result(200, "text/html", CONTENT.length(), CONTENT, false) }; ArrayList data = new ArrayList<>(); diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerTest.java index a1d5aaebe4b..6a6713444bf 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,6 +18,12 @@ package org.eclipse.jetty.http; +import java.nio.ByteBuffer; +import java.util.function.Supplier; + +import org.eclipse.jetty.util.BufferUtil; +import org.junit.jupiter.api.Test; + import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.endsWith; @@ -27,14 +33,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; -import java.nio.ByteBuffer; -import java.util.function.Supplier; - -import org.eclipse.jetty.util.BufferUtil; -import org.junit.jupiter.api.Test; - public class HttpGeneratorServerTest -{ +{ @Test public void test_0_9() throws Exception { @@ -57,20 +57,20 @@ public class HttpGeneratorServerTest String response = BufferUtil.toString(header); BufferUtil.clear(header); response += BufferUtil.toString(content); - BufferUtil.clear(content); + BufferUtil.clear(content); result = gen.generateResponse(null, false, null, null, content, false); assertEquals(HttpGenerator.Result.SHUTDOWN_OUT, result); assertEquals(HttpGenerator.State.END, gen.getState()); - + assertEquals(10, gen.getContentPrepared()); - + assertThat(response, not(containsString("200 OK"))); assertThat(response, not(containsString("Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT"))); assertThat(response, not(containsString("Content-Length: 10"))); assertThat(response, containsString("0123456789")); } - + @Test public void testSimple() throws Exception { @@ -96,20 +96,20 @@ public class HttpGeneratorServerTest String response = BufferUtil.toString(header); BufferUtil.clear(header); response += BufferUtil.toString(content); - BufferUtil.clear(content); + BufferUtil.clear(content); result = gen.generateResponse(null, false, null, null, content, false); assertEquals(HttpGenerator.Result.DONE, result); assertEquals(HttpGenerator.State.END, gen.getState()); - + assertEquals(10, gen.getContentPrepared()); - + assertThat(response, containsString("HTTP/1.1 200 OK")); assertThat(response, containsString("Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT")); assertThat(response, containsString("Content-Length: 10")); assertThat(response, containsString("\r\n0123456789")); } - + @Test public void test204() throws Exception { @@ -117,23 +117,23 @@ public class HttpGeneratorServerTest ByteBuffer content = BufferUtil.toBuffer("0123456789"); HttpGenerator gen = new HttpGenerator(); - + MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 204, "Foo", new HttpFields(), 10); info.getFields().add("Content-Type", "test/data"); info.getFields().add("Last-Modified", DateGenerator.__01Jan1970); HttpGenerator.Result result = gen.generateResponse(info, false, header, null, content, true); - - assertEquals(gen.isNoContent(), true); + + assertEquals(gen.isNoContent(), true); assertEquals(HttpGenerator.Result.FLUSH, result); assertEquals(HttpGenerator.State.COMPLETING, gen.getState()); String responseheaders = BufferUtil.toString(header); - BufferUtil.clear(header); + BufferUtil.clear(header); result = gen.generateResponse(null, false, null, null, content, false); assertEquals(HttpGenerator.Result.DONE, result); assertEquals(HttpGenerator.State.END, gen.getState()); - + assertThat(responseheaders, containsString("HTTP/1.1 204 Foo")); assertThat(responseheaders, containsString("Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT")); assertThat(responseheaders, not(containsString("Content-Length: 10"))); @@ -141,8 +141,7 @@ public class HttpGeneratorServerTest //Note: the HttpConnection.process() method is responsible for actually //excluding the content from the response based on generator.isNoContent()==true } - - + @Test public void testComplexChars() throws Exception { @@ -168,14 +167,14 @@ public class HttpGeneratorServerTest String response = BufferUtil.toString(header); BufferUtil.clear(header); response += BufferUtil.toString(content); - BufferUtil.clear(content); + BufferUtil.clear(content); result = gen.generateResponse(null, false, null, null, content, false); assertEquals(HttpGenerator.Result.DONE, result); assertEquals(HttpGenerator.State.END, gen.getState()); - + assertEquals(10, gen.getContentPrepared()); - + assertThat(response, containsString("HTTP/1.1 200 ØÆ")); assertThat(response, containsString("Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT")); assertThat(response, containsString("Content-Type: test/data; extra=value")); @@ -249,7 +248,8 @@ public class HttpGeneratorServerTest result = gen.generateResponse(info, false, null, null, null, true); assertEquals(HttpGenerator.Result.NEED_HEADER, result); - BadMessageException e = assertThrows(BadMessageException.class, ()->{ + BadMessageException e = assertThrows(BadMessageException.class, () -> + { gen.generateResponse(info, false, header, null, null, true); }); assertEquals(500, e._code); @@ -409,16 +409,16 @@ public class HttpGeneratorServerTest assertThat(out, containsString("Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT")); assertThat(out, not(containsString("Content-Length"))); assertThat(out, containsString("Transfer-Encoding: chunked")); - + assertThat(out, endsWith( - "\r\n\r\nD\r\n"+ - "Hello World! \r\n"+ - "2E\r\n"+ - "The quick brown fox jumped over the lazy dog. \r\n"+ - "0\r\n"+ - "\r\n")); + "\r\n\r\nD\r\n" + + "Hello World! \r\n" + + "2E\r\n" + + "The quick brown fox jumped over the lazy dog. \r\n" + + "0\r\n" + + "\r\n")); } - + @Test public void testResponseWithHintedChunkedContent() throws Exception { @@ -451,7 +451,7 @@ public class HttpGeneratorServerTest result = gen.generateResponse(null, false, null, null, content1, false); assertEquals(HttpGenerator.Result.NEED_CHUNK, result); - + result = gen.generateResponse(null, false, null, chunk, content1, false); assertEquals(HttpGenerator.Result.FLUSH, result); assertEquals(HttpGenerator.State.COMMITTED, gen.getState()); @@ -478,14 +478,14 @@ public class HttpGeneratorServerTest assertThat(out, containsString("Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT")); assertThat(out, not(containsString("Content-Length"))); assertThat(out, containsString("Transfer-Encoding: chunked")); - + assertThat(out, endsWith( - "\r\n\r\nD\r\n"+ - "Hello World! \r\n"+ - "2E\r\n"+ - "The quick brown fox jumped over the lazy dog. \r\n"+ - "0\r\n"+ - "\r\n")); + "\r\n\r\nD\r\n" + + "Hello World! \r\n" + + "2E\r\n" + + "The quick brown fox jumped over the lazy dog. \r\n" + + "0\r\n" + + "\r\n")); } @Test @@ -512,13 +512,13 @@ public class HttpGeneratorServerTest public HttpFields get() { HttpFields trailer = new HttpFields(); - trailer.add("T-Name0","T-ValueA"); - trailer.add("T-Name0","T-ValueB"); - trailer.add("T-Name1","T-ValueC"); + trailer.add("T-Name0", "T-ValueA"); + trailer.add("T-Name0", "T-ValueB"); + trailer.add("T-Name1", "T-ValueC"); return trailer; } }); - + result = gen.generateResponse(info, false, null, null, content0, false); assertEquals(HttpGenerator.Result.NEED_HEADER, result); assertEquals(HttpGenerator.State.START, gen.getState()); @@ -534,7 +534,7 @@ public class HttpGeneratorServerTest result = gen.generateResponse(null, false, null, null, content1, false); assertEquals(HttpGenerator.Result.NEED_CHUNK, result); - + result = gen.generateResponse(null, false, null, chunk, content1, false); assertEquals(HttpGenerator.Result.FLUSH, result); assertEquals(HttpGenerator.State.COMMITTED, gen.getState()); @@ -551,9 +551,9 @@ public class HttpGeneratorServerTest assertEquals(HttpGenerator.Result.NEED_CHUNK_TRAILER, result); assertEquals(HttpGenerator.State.COMPLETING, gen.getState()); - + result = gen.generateResponse(null, false, null, trailer, null, true); - + assertEquals(HttpGenerator.Result.FLUSH, result); assertEquals(HttpGenerator.State.COMPLETING, gen.getState()); out += BufferUtil.toString(trailer); @@ -567,17 +567,17 @@ public class HttpGeneratorServerTest assertThat(out, containsString("Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT")); assertThat(out, not(containsString("Content-Length"))); assertThat(out, containsString("Transfer-Encoding: chunked")); - + assertThat(out, endsWith( - "\r\n\r\nD\r\n"+ - "Hello World! \r\n"+ - "2E\r\n"+ - "The quick brown fox jumped over the lazy dog. \r\n"+ - "0\r\n"+ - "T-Name0: T-ValueA\r\n"+ - "T-Name0: T-ValueB\r\n"+ - "T-Name1: T-ValueC\r\n"+ - "\r\n")); + "\r\n\r\nD\r\n" + + "Hello World! \r\n" + + "2E\r\n" + + "The quick brown fox jumped over the lazy dog. \r\n" + + "0\r\n" + + "T-Name0: T-ValueA\r\n" + + "T-Name0: T-ValueB\r\n" + + "T-Name1: T-ValueC\r\n" + + "\r\n")); } @Test @@ -602,13 +602,13 @@ public class HttpGeneratorServerTest public HttpFields get() { HttpFields trailer = new HttpFields(); - trailer.add("T-Name0","T-ValueA"); - trailer.add("T-Name0","T-ValueB"); - trailer.add("T-Name1","T-ValueC"); + trailer.add("T-Name0", "T-ValueA"); + trailer.add("T-Name0", "T-ValueB"); + trailer.add("T-Name1", "T-ValueC"); return trailer; } }); - + result = gen.generateResponse(info, false, null, null, null, true); assertEquals(HttpGenerator.Result.NEED_HEADER, result); assertEquals(HttpGenerator.State.START, gen.getState()); @@ -627,9 +627,9 @@ public class HttpGeneratorServerTest result = gen.generateResponse(null, false, null, chunk, null, true); assertEquals(HttpGenerator.Result.NEED_CHUNK_TRAILER, result); assertEquals(HttpGenerator.State.COMPLETING, gen.getState()); - + result = gen.generateResponse(null, false, null, trailer, null, true); - + assertEquals(HttpGenerator.Result.FLUSH, result); assertEquals(HttpGenerator.State.COMPLETING, gen.getState()); out += BufferUtil.toString(trailer); @@ -643,14 +643,14 @@ public class HttpGeneratorServerTest assertThat(out, containsString("Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT")); assertThat(out, not(containsString("Content-Length"))); assertThat(out, containsString("Transfer-Encoding: chunked")); - + assertThat(out, endsWith( - "\r\n\r\n"+ - "0\r\n"+ - "T-Name0: T-ValueA\r\n"+ - "T-Name0: T-ValueB\r\n"+ - "T-Name1: T-ValueC\r\n"+ - "\r\n")); + "\r\n\r\n" + + "0\r\n" + + "T-Name0: T-ValueA\r\n" + + "T-Name0: T-ValueB\r\n" + + "T-Name1: T-ValueC\r\n" + + "\r\n")); } @Test @@ -715,7 +715,7 @@ public class HttpGeneratorServerTest MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), -1); info.getFields().add("Last-Modified", DateGenerator.__01Jan1970); - info.getFields().add("Content-Length",""+(content0.remaining()+content1.remaining())); + info.getFields().add("Content-Length", "" + (content0.remaining() + content1.remaining())); result = gen.generateResponse(info, false, null, null, content0, false); assertEquals(HttpGenerator.Result.NEED_HEADER, result); assertEquals(HttpGenerator.State.START, gen.getState()); @@ -749,9 +749,6 @@ public class HttpGeneratorServerTest assertThat(out, containsString("Content-Length: 59")); assertThat(out, containsString("\r\n\r\nHello World! The quick brown fox jumped over the lazy dog. ")); } - - - @Test public void test100ThenResponseWithContent() throws Exception @@ -780,7 +777,7 @@ public class HttpGeneratorServerTest assertEquals(HttpGenerator.Result.NEED_INFO, result); assertEquals(HttpGenerator.State.START, gen.getState()); - MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), BufferUtil.length(content0)+BufferUtil.length(content1)); + MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), BufferUtil.length(content0) + BufferUtil.length(content1)); info.getFields().add("Last-Modified", DateGenerator.__01Jan1970); result = gen.generateResponse(info, false, null, null, content0, false); assertEquals(HttpGenerator.Result.NEED_HEADER, result); diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java index cb96bef18a7..f7bf640de51 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,6 +18,21 @@ package org.eclipse.jetty.http; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.eclipse.jetty.http.HttpParser.State; +import org.eclipse.jetty.toolchain.test.Net; +import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.log.StacklessLogging; +import org.hamcrest.Matchers; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + import static org.eclipse.jetty.http.HttpComplianceSection.NO_FIELD_FOLDING; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.contains; @@ -29,26 +44,13 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.eclipse.jetty.http.HttpParser.State; -import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.log.StacklessLogging; -import org.hamcrest.Matchers; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - public class HttpParserTest { static { HttpCompliance.CUSTOM0.sections().remove(HttpComplianceSection.NO_WS_AFTER_FIELD_NAME); } - + /** * Parse until {@link State#END} state. * If the parser is already in the END state, then it is {@link HttpParser#reset()} and re-parsed. @@ -95,7 +97,7 @@ public class HttpParserTest } @Test - public void testLineParse_Mock_IP() throws Exception + public void testLineParseMockIP() throws Exception { ByteBuffer buffer = BufferUtil.toBuffer("POST /mock/127.0.0.1 HTTP/1.1\r\n" + "\r\n"); @@ -123,7 +125,7 @@ public class HttpParserTest } @Test - public void testLineParse1_RFC2616() throws Exception + public void testLineParse1RFC2616() throws Exception { ByteBuffer buffer = BufferUtil.toBuffer("GET /999\r\n"); @@ -148,11 +150,11 @@ public class HttpParserTest HttpParser parser = new HttpParser(handler); parseAll(parser, buffer); assertEquals("HTTP/0.9 not supported", _bad); - assertThat(_complianceViolation,Matchers.empty()); + assertThat(_complianceViolation, Matchers.empty()); } @Test - public void testLineParse2_RFC2616() throws Exception + public void testLineParse2RFC2616() throws Exception { ByteBuffer buffer = BufferUtil.toBuffer("POST /222 \r\n"); @@ -178,7 +180,7 @@ public class HttpParserTest HttpParser parser = new HttpParser(handler); parseAll(parser, buffer); assertEquals("HTTP/0.9 not supported", _bad); - assertThat(_complianceViolation,Matchers.empty()); + assertThat(_complianceViolation, Matchers.empty()); } @Test @@ -226,11 +228,11 @@ public class HttpParserTest @Test public void testAllowedLinePreamble() throws Exception { - ByteBuffer buffer= BufferUtil.toBuffer("\r\n\r\nGET / HTTP/1.0\r\n"); + ByteBuffer buffer = BufferUtil.toBuffer("\r\n\r\nGET / HTTP/1.0\r\n"); - HttpParser.RequestHandler handler = new Handler(); - HttpParser parser= new HttpParser(handler); - parseAll(parser,buffer); + HttpParser.RequestHandler handler = new Handler(); + HttpParser parser = new HttpParser(handler); + parseAll(parser, buffer); assertEquals("GET", _methodOrVersion); assertEquals("/", _uriOrStatus); assertEquals("HTTP/1.0", _versionOrReason); @@ -240,11 +242,11 @@ public class HttpParserTest @Test public void testDisallowedLinePreamble() throws Exception { - ByteBuffer buffer= BufferUtil.toBuffer("\r\n \r\nGET / HTTP/1.0\r\n"); + ByteBuffer buffer = BufferUtil.toBuffer("\r\n \r\nGET / HTTP/1.0\r\n"); - HttpParser.RequestHandler handler = new Handler(); - HttpParser parser= new HttpParser(handler); - parseAll(parser,buffer); + HttpParser.RequestHandler handler = new Handler(); + HttpParser parser = new HttpParser(handler); + parseAll(parser, buffer); assertEquals("Illegal character SPACE=' '", _bad); } @@ -265,10 +267,10 @@ public class HttpParserTest public void testSimple() throws Exception { ByteBuffer buffer = BufferUtil.toBuffer( - "GET / HTTP/1.0\r\n" + - "Host: localhost\r\n" + - "Connection: close\r\n" + - "\r\n"); + "GET / HTTP/1.0\r\n" + + "Host: localhost\r\n" + + "Connection: close\r\n" + + "\r\n"); HttpParser.RequestHandler handler = new Handler(); HttpParser parser = new HttpParser(handler); @@ -290,13 +292,13 @@ public class HttpParserTest public void testFoldedField2616() throws Exception { ByteBuffer buffer = BufferUtil.toBuffer( - "GET / HTTP/1.0\r\n" + - "Host: localhost\r\n" + - "Name: value\r\n" + - " extra\r\n" + - "Name2: \r\n" + - "\tvalue2\r\n" + - "\r\n"); + "GET / HTTP/1.0\r\n" + + "Host: localhost\r\n" + + "Name: value\r\n" + + " extra\r\n" + + "Name2: \r\n" + + "\tvalue2\r\n" + + "\r\n"); HttpParser.RequestHandler handler = new Handler(); HttpParser parser = new HttpParser(handler, HttpCompliance.RFC2616_LEGACY); @@ -310,18 +312,18 @@ public class HttpParserTest assertEquals("value extra", _val[1]); assertEquals("Name2", _hdr[2]); assertEquals("value2", _val[2]); - assertThat(_complianceViolation, contains(NO_FIELD_FOLDING,NO_FIELD_FOLDING)); + assertThat(_complianceViolation, contains(NO_FIELD_FOLDING, NO_FIELD_FOLDING)); } @Test public void testFoldedField7230() throws Exception { ByteBuffer buffer = BufferUtil.toBuffer( - "GET / HTTP/1.0\r\n" + - "Host: localhost\r\n" + - "Name: value\r\n" + - " extra\r\n" + - "\r\n"); + "GET / HTTP/1.0\r\n" + + "Host: localhost\r\n" + + "Name: value\r\n" + + " extra\r\n" + + "\r\n"); HttpParser.RequestHandler handler = new Handler(); HttpParser parser = new HttpParser(handler, 4096, HttpCompliance.RFC7230_LEGACY); @@ -329,17 +331,17 @@ public class HttpParserTest assertThat(_bad, Matchers.notNullValue()); assertThat(_bad, containsString("Header Folding")); - assertThat(_complianceViolation,Matchers.empty()); + assertThat(_complianceViolation, Matchers.empty()); } - + @Test public void testWhiteSpaceInName() throws Exception { ByteBuffer buffer = BufferUtil.toBuffer( - "GET / HTTP/1.0\r\n" + - "Host: localhost\r\n" + - "N ame: value\r\n" + - "\r\n"); + "GET / HTTP/1.0\r\n" + + "Host: localhost\r\n" + + "N ame: value\r\n" + + "\r\n"); HttpParser.RequestHandler handler = new Handler(); HttpParser parser = new HttpParser(handler, 4096, HttpCompliance.RFC7230_LEGACY); @@ -348,15 +350,15 @@ public class HttpParserTest assertThat(_bad, Matchers.notNullValue()); assertThat(_bad, containsString("Illegal character")); } - + @Test public void testWhiteSpaceAfterName() throws Exception { ByteBuffer buffer = BufferUtil.toBuffer( - "GET / HTTP/1.0\r\n" + - "Host: localhost\r\n" + - "Name : value\r\n" + - "\r\n"); + "GET / HTTP/1.0\r\n" + + "Host: localhost\r\n" + + "Name : value\r\n" + + "\r\n"); HttpParser.RequestHandler handler = new Handler(); HttpParser parser = new HttpParser(handler, 4096, HttpCompliance.RFC7230_LEGACY); @@ -370,27 +372,26 @@ public class HttpParserTest public void testWhiteSpaceBeforeRequest() { HttpCompliance[] compliances = new HttpCompliance[] - { - HttpCompliance.RFC7230, HttpCompliance.RFC2616 - }; - - String whitespaces[][] = new String[][] - { - { " ", "Illegal character SPACE" }, - { "\t", "Illegal character HTAB" }, - { "\n", null }, - { "\r", "Bad EOL" }, - { "\r\n", null }, - { "\r\n\r\n", null }, - { "\r\n \r\n", "Illegal character SPACE" }, - { "\r\n\t\r\n", "Illegal character HTAB" }, - { "\r\t\n", "Bad EOL" }, - { "\r\r\n", "Bad EOL" }, - { "\t\r\t\r\n", "Illegal character HTAB" }, - { " \t \r \t \n\n", "Illegal character SPACE" }, - { " \r \t \r\n\r\n\r\n", "Illegal character SPACE" } - }; + { + HttpCompliance.RFC7230, HttpCompliance.RFC2616 + }; + String[][] whitespaces = new String[][] + { + {" ", "Illegal character SPACE"}, + {"\t", "Illegal character HTAB"}, + {"\n", null}, + {"\r", "Bad EOL"}, + {"\r\n", null}, + {"\r\n\r\n", null}, + {"\r\n \r\n", "Illegal character SPACE"}, + {"\r\n\t\r\n", "Illegal character HTAB"}, + {"\r\t\n", "Bad EOL"}, + {"\r\r\n", "Bad EOL"}, + {"\t\r\t\r\n", "Illegal character HTAB"}, + {" \t \r \t \n\n", "Illegal character SPACE"}, + {" \r \t \r\n\r\n\r\n", "Illegal character SPACE"} + }; for (int i = 0; i < compliances.length; i++) { @@ -399,12 +400,12 @@ public class HttpParserTest for (int j = 0; j < whitespaces.length; j++) { String request = - whitespaces[j][0] + - "GET / HTTP/1.1\r\n" + - "Host: localhost\r\n" + - "Name: value" + j + "\r\n" + - "Connection: close\r\n" + - "\r\n"; + whitespaces[j][0] + + "GET / HTTP/1.1\r\n" + + "Host: localhost\r\n" + + "Name: value" + j + "\r\n" + + "Connection: close\r\n" + + "\r\n"; ByteBuffer buffer = BufferUtil.toBuffer(request); HttpParser.RequestHandler handler = new Handler(); @@ -414,7 +415,7 @@ public class HttpParserTest String test = "whitespace.[" + compliance + "].[" + j + "]"; String expected = whitespaces[j][1]; - if (expected==null) + if (expected == null) assertThat(test, _bad, is(nullValue())); else assertThat(test, _bad, containsString(expected)); @@ -426,11 +427,11 @@ public class HttpParserTest public void testNoValue() throws Exception { ByteBuffer buffer = BufferUtil.toBuffer( - "GET / HTTP/1.0\r\n" + - "Host: localhost\r\n" + - "Name0: \r\n" + - "Name1:\r\n" + - "\r\n"); + "GET / HTTP/1.0\r\n" + + "Host: localhost\r\n" + + "Name0: \r\n" + + "Name1:\r\n" + + "\r\n"); HttpParser.RequestHandler handler = new Handler(); HttpParser parser = new HttpParser(handler); @@ -454,43 +455,43 @@ public class HttpParserTest public void testSpaceinNameCustom0() throws Exception { ByteBuffer buffer = BufferUtil.toBuffer( - "GET / HTTP/1.0\r\n" + - "Host: localhost\r\n" + - "Name with space: value\r\n" + - "Other: value\r\n" + - "\r\n"); + "GET / HTTP/1.0\r\n" + + "Host: localhost\r\n" + + "Name with space: value\r\n" + + "Other: value\r\n" + + "\r\n"); HttpParser.RequestHandler handler = new Handler(); - HttpParser parser = new HttpParser(handler,HttpCompliance.CUSTOM0); + HttpParser parser = new HttpParser(handler, HttpCompliance.CUSTOM0); parseAll(parser, buffer); - + assertThat(_bad, containsString("Illegal character")); - assertThat(_complianceViolation,contains(HttpComplianceSection.NO_WS_AFTER_FIELD_NAME)); + assertThat(_complianceViolation, contains(HttpComplianceSection.NO_WS_AFTER_FIELD_NAME)); } @Test public void testNoColonCustom0() throws Exception { ByteBuffer buffer = BufferUtil.toBuffer( - "GET / HTTP/1.0\r\n" + - "Host: localhost\r\n" + - "Name \r\n" + - "Other: value\r\n" + - "\r\n"); + "GET / HTTP/1.0\r\n" + + "Host: localhost\r\n" + + "Name \r\n" + + "Other: value\r\n" + + "\r\n"); HttpParser.RequestHandler handler = new Handler(); - HttpParser parser = new HttpParser(handler,HttpCompliance.CUSTOM0); + HttpParser parser = new HttpParser(handler, HttpCompliance.CUSTOM0); parseAll(parser, buffer); - + assertThat(_bad, containsString("Illegal character")); - assertThat(_complianceViolation,contains(HttpComplianceSection.NO_WS_AFTER_FIELD_NAME)); + assertThat(_complianceViolation, contains(HttpComplianceSection.NO_WS_AFTER_FIELD_NAME)); } @Test public void testTrailingSpacesInHeaderNameInCustom0Mode() throws Exception { ByteBuffer buffer = BufferUtil.toBuffer( - "HTTP/1.1 204 No Content\r\n" + + "HTTP/1.1 204 No Content\r\n" + "Access-Control-Allow-Headers : Origin\r\n" + "Other\t : value\r\n" + "\r\n"); @@ -515,17 +516,17 @@ public class HttpParserTest assertEquals("Other", _hdr[1]); assertEquals("value", _val[1]); - assertThat(_complianceViolation, contains(HttpComplianceSection.NO_WS_AFTER_FIELD_NAME,HttpComplianceSection.NO_WS_AFTER_FIELD_NAME)); + assertThat(_complianceViolation, contains(HttpComplianceSection.NO_WS_AFTER_FIELD_NAME, HttpComplianceSection.NO_WS_AFTER_FIELD_NAME)); } @Test public void testTrailingSpacesInHeaderNameNoCustom0() throws Exception { ByteBuffer buffer = BufferUtil.toBuffer( - "HTTP/1.1 204 No Content\r\n" + - "Access-Control-Allow-Headers : Origin\r\n" + - "Other: value\r\n" + - "\r\n"); + "HTTP/1.1 204 No Content\r\n" + + "Access-Control-Allow-Headers : Origin\r\n" + + "Other: value\r\n" + + "\r\n"); HttpParser.ResponseHandler handler = new Handler(); HttpParser parser = new HttpParser(handler); @@ -541,35 +542,34 @@ public class HttpParserTest public void testNoColon7230() throws Exception { ByteBuffer buffer = BufferUtil.toBuffer( - "GET / HTTP/1.0\r\n" + - "Host: localhost\r\n" + - "Name\r\n" + - "\r\n"); + "GET / HTTP/1.0\r\n" + + "Host: localhost\r\n" + + "Name\r\n" + + "\r\n"); HttpParser.RequestHandler handler = new Handler(); - HttpParser parser = new HttpParser(handler,HttpCompliance.RFC7230_LEGACY); + HttpParser parser = new HttpParser(handler, HttpCompliance.RFC7230_LEGACY); parseAll(parser, buffer); assertThat(_bad, containsString("Illegal character")); - assertThat(_complianceViolation,Matchers.empty()); + assertThat(_complianceViolation, Matchers.empty()); } - @Test public void testHeaderParseDirect() throws Exception { ByteBuffer b0 = BufferUtil.toBuffer( - "GET / HTTP/1.0\r\n" + - "Host: localhost\r\n" + - "Header1: value1\r\n" + - "Header2: value 2a \r\n" + - "Header3: 3\r\n" + - "Header4:value4\r\n" + - "Server5: notServer\r\n" + - "HostHeader: notHost\r\n" + - "Connection: close\r\n" + - "Accept-Encoding: gzip, deflated\r\n" + - "Accept: unknown\r\n" + - "\r\n"); + "GET / HTTP/1.0\r\n" + + "Host: localhost\r\n" + + "Header1: value1\r\n" + + "Header2: value 2a \r\n" + + "Header3: 3\r\n" + + "Header4:value4\r\n" + + "Server5: notServer\r\n" + + "HostHeader: notHost\r\n" + + "Connection: close\r\n" + + "Accept-Encoding: gzip, deflated\r\n" + + "Accept: unknown\r\n" + + "\r\n"); ByteBuffer buffer = BufferUtil.allocateDirect(b0.capacity()); int pos = BufferUtil.flipToFill(buffer); BufferUtil.put(b0, buffer); @@ -609,18 +609,18 @@ public class HttpParserTest public void testHeaderParseCRLF() throws Exception { ByteBuffer buffer = BufferUtil.toBuffer( - "GET / HTTP/1.0\r\n" + - "Host: localhost\r\n" + - "Header1: value1\r\n" + - "Header2: value 2a \r\n" + - "Header3: 3\r\n" + - "Header4:value4\r\n" + - "Server5: notServer\r\n" + - "HostHeader: notHost\r\n" + - "Connection: close\r\n" + - "Accept-Encoding: gzip, deflated\r\n" + - "Accept: unknown\r\n" + - "\r\n"); + "GET / HTTP/1.0\r\n" + + "Host: localhost\r\n" + + "Header1: value1\r\n" + + "Header2: value 2a \r\n" + + "Header3: 3\r\n" + + "Header4:value4\r\n" + + "Server5: notServer\r\n" + + "HostHeader: notHost\r\n" + + "Connection: close\r\n" + + "Accept-Encoding: gzip, deflated\r\n" + + "Accept: unknown\r\n" + + "\r\n"); HttpParser.RequestHandler handler = new Handler(); HttpParser parser = new HttpParser(handler); parseAll(parser, buffer); @@ -655,18 +655,18 @@ public class HttpParserTest public void testHeaderParseLF() throws Exception { ByteBuffer buffer = BufferUtil.toBuffer( - "GET / HTTP/1.0\n" + - "Host: localhost\n" + - "Header1: value1\n" + - "Header2: value 2a value 2b \n" + - "Header3: 3\n" + - "Header4:value4\n" + - "Server5: notServer\n" + - "HostHeader: notHost\n" + - "Connection: close\n" + - "Accept-Encoding: gzip, deflated\n" + - "Accept: unknown\n" + - "\n"); + "GET / HTTP/1.0\n" + + "Host: localhost\n" + + "Header1: value1\n" + + "Header2: value 2a value 2b \n" + + "Header3: 3\n" + + "Header4:value4\n" + + "Server5: notServer\n" + + "HostHeader: notHost\n" + + "Connection: close\n" + + "Accept-Encoding: gzip, deflated\n" + + "Accept: unknown\n" + + "\n"); HttpParser.RequestHandler handler = new Handler(); HttpParser parser = new HttpParser(handler); parseAll(parser, buffer); @@ -701,11 +701,11 @@ public class HttpParserTest public void testQuoted() throws Exception { ByteBuffer buffer = BufferUtil.toBuffer( - "GET / HTTP/1.0\n" + - "Name0: \"value0\"\t\n" + - "Name1: \"value\t1\"\n" + - "Name2: \"value\t2A\",\"value,2B\"\t\n" + - "\n"); + "GET / HTTP/1.0\n" + + "Name0: \"value0\"\t\n" + + "Name1: \"value\t1\"\n" + + "Name2: \"value\t2A\",\"value,2B\"\t\n" + + "\n"); HttpParser.RequestHandler handler = new Handler(); HttpParser parser = new HttpParser(handler); parseAll(parser, buffer); @@ -747,30 +747,30 @@ public class HttpParserTest assertEquals("Header1", _hdr[0]); assertEquals("\u00e6 \u00e6", _val[0]); assertEquals("Header2", _hdr[1]); - assertEquals(""+(char)255, _val[1]); + assertEquals("" + (char)255, _val[1]); assertEquals(1, _headers); assertEquals(null, _bad); } - + @Test public void testResponseBufferUpgradeFrom() throws Exception { ByteBuffer buffer = BufferUtil.toBuffer( - "HTTP/1.1 101 Upgrade\r\n" + + "HTTP/1.1 101 Upgrade\r\n" + "Connection: upgrade\r\n" + "Content-Length: 0\r\n" + "Sec-WebSocket-Accept: 4GnyoUP4Sc1JD+2pCbNYAhFYVVA\r\n" + "\r\n" + "FOOGRADE"); - + HttpParser.ResponseHandler handler = new Handler(); HttpParser parser = new HttpParser(handler); - + while (!parser.isState(State.END)) { parser.parseNext(buffer); } - + assertThat(BufferUtil.toUTF8String(buffer), Matchers.is("FOOGRADE")); } @@ -778,7 +778,7 @@ public class HttpParserTest public void testBadMethodEncoding() throws Exception { ByteBuffer buffer = BufferUtil.toBuffer( - "G\u00e6T / HTTP/1.0\r\nHeader0: value0\r\n\n\n"); + "G\u00e6T / HTTP/1.0\r\nHeader0: value0\r\n\n\n"); HttpParser.RequestHandler handler = new Handler(); HttpParser parser = new HttpParser(handler); @@ -790,7 +790,7 @@ public class HttpParserTest public void testBadVersionEncoding() throws Exception { ByteBuffer buffer = BufferUtil.toBuffer( - "GET / H\u00e6P/1.0\r\nHeader0: value0\r\n\n\n"); + "GET / H\u00e6P/1.0\r\nHeader0: value0\r\n\n\n"); HttpParser.RequestHandler handler = new Handler(); HttpParser parser = new HttpParser(handler); @@ -802,9 +802,9 @@ public class HttpParserTest public void testBadHeaderEncoding() throws Exception { ByteBuffer buffer = BufferUtil.toBuffer( - "GET / HTTP/1.0\r\n" - + "H\u00e6der0: value0\r\n" - + "\n\n"); + "GET / HTTP/1.0\r\n" + + "H\u00e6der0: value0\r\n" + + "\n\n"); HttpParser.RequestHandler handler = new Handler(); HttpParser parser = new HttpParser(handler); @@ -816,7 +816,7 @@ public class HttpParserTest public void testBadHeaderNames() throws Exception { String[] bad = new String[] - { + { "Foo\\Bar: value\r\n", "Foo@Bar: value\r\n", "Foo,Bar: value\r\n", @@ -832,17 +832,17 @@ public class HttpParserTest "Foo/Bar: value\r\n", "Foo]Bar: value\r\n", "Foo[Bar: value\r\n", - }; + }; - for (int i=0; i _complianceViolation = new ArrayList<>(); - + private class Handler implements HttpParser.RequestHandler, HttpParser.ResponseHandler, HttpParser.ComplianceHandler { @Override diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpSchemeTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpSchemeTest.java new file mode 100644 index 00000000000..018f9fbe286 --- /dev/null +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpSchemeTest.java @@ -0,0 +1,80 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.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; + +/** + * Unit tests for class {@link HttpScheme}. + * + * @see HttpScheme + */ +public class HttpSchemeTest +{ + + @Test + public void testIsReturningTrue() + { + HttpScheme httpScheme = HttpScheme.HTTPS; + + assertTrue(httpScheme.is("https")); + assertEquals("https", httpScheme.asString()); + assertEquals("https", httpScheme.toString()); + } + + @Test + public void testIsReturningFalse() + { + HttpScheme httpScheme = HttpScheme.HTTP; + + assertFalse(httpScheme.is(",CPL@@4'U4p")); + } + + @Test + public void testIsWithNull() + { + HttpScheme httpScheme = HttpScheme.HTTPS; + + assertFalse(httpScheme.is(null)); + } + + @Test + public void testAsByteBuffer() + { + HttpScheme httpScheme = HttpScheme.WS; + ByteBuffer byteBuffer = httpScheme.asByteBuffer(); + + assertEquals("ws", httpScheme.asString()); + assertEquals("ws", httpScheme.toString()); + assertEquals(2, byteBuffer.capacity()); + assertEquals(2, byteBuffer.remaining()); + assertEquals(2, byteBuffer.limit()); + assertFalse(byteBuffer.hasArray()); + assertEquals(0, byteBuffer.position()); + assertTrue(byteBuffer.isReadOnly()); + assertFalse(byteBuffer.isDirect()); + assertTrue(byteBuffer.hasRemaining()); + } +} diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpStatusCodeTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpStatusCodeTest.java index b6baef773ca..3e45cbb50d2 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpStatusCodeTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpStatusCodeTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,11 +18,11 @@ package org.eclipse.jetty.http; +import org.junit.jupiter.api.Test; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; -import org.junit.jupiter.api.Test; - public class HttpStatusCodeTest { @Test @@ -31,8 +31,7 @@ public class HttpStatusCodeTest assertNull(HttpStatus.getCode(800), "Invalid code: 800"); assertNull(HttpStatus.getCode(190), "Invalid code: 190"); } - - + @Test public void testImATeapot() { @@ -42,6 +41,6 @@ public class HttpStatusCodeTest public void testHttpMethod() { - assertEquals("GET",HttpMethod.GET.toString()); + assertEquals("GET", HttpMethod.GET.toString()); } } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpTester.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpTester.java index 60d5a50c06e..eee24e824be 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpTester.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpTester.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -27,15 +27,13 @@ import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; - /** - * A HTTP Testing helper class. - * + * An HTTP Testing helper class. + * * Example usage: *
          *        try(Socket socket = new Socket("www.google.com",80))
        @@ -48,7 +46,7 @@ import org.eclipse.jetty.util.log.Logger;
          *          request.put("Content-Type","application/x-www-form-urlencoded");
          *          request.setContent("q=jetty%20server");
          *          ByteBuffer output = request.generate();
        - *          
        + *
          *          socket.getOutputStream().write(output.array(),output.arrayOffset()+output.position(),output.remaining());
          *          HttpTester.Input input = HttpTester.from(socket.getInputStream());
          *          HttpTester.Response response = HttpTester.parseResponse(input);
        @@ -61,15 +59,15 @@ import org.eclipse.jetty.util.log.Logger;
          */
         public class HttpTester
         {
        -    private final static Logger LOG = Log.getLogger(HttpTester.class);
        -    
        +    private static final Logger LOG = Log.getLogger(HttpTester.class);
        +
             private HttpTester()
             {
             }
         
             public static Request newRequest()
             {
        -        Request r=new Request();
        +        Request r = new Request();
                 r.setMethod(HttpMethod.GET.asString());
                 r.setURI("/");
                 r.setVersion(HttpVersion.HTTP_1_1);
        @@ -78,92 +76,106 @@ public class HttpTester
         
             public static Request parseRequest(String request)
             {
        -        Request r=new Request();
        -        HttpParser parser =new HttpParser(r);
        +        Request r = new Request();
        +        HttpParser parser = new HttpParser(r);
                 parser.parseNext(BufferUtil.toBuffer(request));
                 return r;
             }
         
             public static Request parseRequest(ByteBuffer request)
             {
        -        Request r=new Request();
        -        HttpParser parser =new HttpParser(r);
        +        Request r = new Request();
        +        HttpParser parser = new HttpParser(r);
                 parser.parseNext(request);
                 return r;
             }
        -    
        +
             public static Response parseResponse(String response)
             {
        -        Response r=new Response();
        -        HttpParser parser =new HttpParser(r);
        +        Response r = new Response();
        +        HttpParser parser = new HttpParser(r);
                 parser.parseNext(BufferUtil.toBuffer(response));
                 return r;
             }
         
             public static Response parseResponse(ByteBuffer response)
             {
        -        Response r=new Response();
        -        HttpParser parser =new HttpParser(r);
        +        Response r = new Response();
        +        HttpParser parser = new HttpParser(r);
                 parser.parseNext(response);
                 return r;
             }
        -    
        +
             public static Response parseResponse(InputStream responseStream) throws IOException
             {
        -        ByteArrayOutputStream contentStream = new ByteArrayOutputStream();
        -        IO.copy(responseStream, contentStream);
        -        
        -        Response r=new Response();
        -        HttpParser parser =new HttpParser(r);
        -        parser.parseNext(ByteBuffer.wrap(contentStream.toByteArray()));
        -        return r;
        +        Response r = new Response();
        +        HttpParser parser = new HttpParser(r);
        +
        +        // Read and parse a character at a time so we never can read more than we should.
        +        byte[] array = new byte[1];
        +        ByteBuffer buffer = ByteBuffer.wrap(array);
        +        buffer.limit(1);
        +
        +        while (true)
        +        {
        +            buffer.position(1);
        +            int l = responseStream.read(array);
        +            if (l < 0)
        +                parser.atEOF();
        +            else
        +                buffer.position(0);
        +
        +            if (parser.parseNext(buffer))
        +                return r;
        +            else if (l < 0)
        +                return null;
        +        }
             }
        -    
        +
             public abstract static class Input
             {
                 protected final ByteBuffer _buffer;
        -        protected boolean _eof=false;
        +        protected boolean _eof = false;
                 protected HttpParser _parser;
         
                 public Input()
                 {
                     this(BufferUtil.allocate(8192));
                 }
        -        
        +
                 Input(ByteBuffer buffer)
                 {
                     _buffer = buffer;
                 }
        -        
        +
                 public ByteBuffer getBuffer()
                 {
                     return _buffer;
                 }
        -        
        +
                 public void setHttpParser(HttpParser parser)
                 {
        -            _parser=parser;
        +            _parser = parser;
                 }
        -        
        +
                 public HttpParser getHttpParser()
                 {
                     return _parser;
                 }
        -        
        +
                 public HttpParser takeHttpParser()
                 {
        -            HttpParser p=_parser;
        -            _parser=null;
        +            HttpParser p = _parser;
        +            _parser = null;
                     return p;
                 }
        -        
        +
                 public boolean isEOF()
                 {
                     return BufferUtil.isEmpty(_buffer) && _eof;
                 }
        -        
        -        public abstract int fillBuffer() throws IOException; 
        -        
        +
        +        public abstract int fillBuffer() throws IOException;
             }
         
             public static Input from(final ByteBuffer data)
        @@ -173,7 +185,7 @@ public class HttpTester
                     @Override
                     public int fillBuffer() throws IOException
                     {
        -                _eof=true;
        +                _eof = true;
                         return -1;
                     }
                 };
        @@ -187,16 +199,16 @@ public class HttpTester
                     public int fillBuffer() throws IOException
                     {
                         BufferUtil.compact(_buffer);
        -                int len=in.read(_buffer.array(),_buffer.arrayOffset()+_buffer.limit(),BufferUtil.space(_buffer));
        -                if (len<0)
        -                    _eof=true;
        +                int len = in.read(_buffer.array(), _buffer.arrayOffset() + _buffer.limit(), BufferUtil.space(_buffer));
        +                if (len < 0)
        +                    _eof = true;
                         else
        -                    _buffer.limit(_buffer.limit()+len);
        +                    _buffer.limit(_buffer.limit() + len);
                         return len;
                     }
                 };
             }
        -    
        +
             public static Input from(final ReadableByteChannel in)
             {
                 return new Input()
        @@ -205,37 +217,37 @@ public class HttpTester
                     public int fillBuffer() throws IOException
                     {
                         BufferUtil.compact(_buffer);
        -                int pos=BufferUtil.flipToFill(_buffer);
        -                int len=in.read(_buffer);
        -                if (len<0)
        -                    _eof=true;
        -                BufferUtil.flipToFlush(_buffer,pos);
        +                int pos = BufferUtil.flipToFill(_buffer);
        +                int len = in.read(_buffer);
        +                if (len < 0)
        +                    _eof = true;
        +                BufferUtil.flipToFlush(_buffer, pos);
                         return len;
                     }
                 };
             }
        -    
        +
             public static Response parseResponse(Input in) throws IOException
             {
                 Response r;
        -        HttpParser parser=in.takeHttpParser();
        -        if (parser==null)
        +        HttpParser parser = in.takeHttpParser();
        +        if (parser == null)
                 {
        -            r=new Response();
        +            r = new Response();
                     parser = new HttpParser(r);
                 }
                 else
        -            r=(Response)parser.getHandler();
        -        
        +            r = (Response)parser.getHandler();
        +
                 parseResponse(in, parser, r);
        -    
        -        if(r.isComplete())
        +
        +        if (r.isComplete())
                     return r;
        -    
        +
                 in.setHttpParser(parser);
                 return null;
             }
        -    
        +
             public static void parseResponse(Input in, Response response) throws IOException
             {
                 HttpParser parser = in.takeHttpParser();
        @@ -244,24 +256,24 @@ public class HttpTester
                     parser = new HttpParser(response);
                 }
                 parseResponse(in, parser, response);
        -    
        +
                 if (!response.isComplete())
                     in.setHttpParser(parser);
             }
        -    
        +
             private static void parseResponse(Input in, HttpParser parser, Response r) throws IOException
             {
                 ByteBuffer buffer = in.getBuffer();
        -        
        -        while(true)
        +
        +        while (true)
                 {
                     if (BufferUtil.hasContent(buffer))
                         if (parser.parseNext(buffer))
                             break;
        -            int len=in.fillBuffer();
        -            if (len==0)
        +            int len = in.fillBuffer();
        +            if (len == 0)
                         break;
        -            if (len<=0)
        +            if (len <= 0)
                     {
                         parser.atEOF();
                         parser.parseNext(buffer);
        @@ -273,15 +285,15 @@ public class HttpTester
             public abstract static class Message extends HttpFields implements HttpParser.HttpHandler
             {
                 boolean _earlyEOF;
        -        boolean _complete=false;
        +        boolean _complete = false;
                 ByteArrayOutputStream _content;
        -        HttpVersion _version=HttpVersion.HTTP_1_0;
        +        HttpVersion _version = HttpVersion.HTTP_1_0;
         
                 public boolean isComplete()
                 {
                     return _complete;
                 }
        -        
        +
                 public HttpVersion getVersion()
                 {
                     return _version;
        @@ -294,14 +306,14 @@ public class HttpTester
         
                 public void setVersion(HttpVersion version)
                 {
        -            _version=version;
        +            _version = version;
                 }
         
                 public void setContent(byte[] bytes)
                 {
                     try
                     {
        -                _content=new ByteArrayOutputStream();
        +                _content = new ByteArrayOutputStream();
                         _content.write(bytes);
                     }
                     catch (IOException e)
        @@ -314,7 +326,7 @@ public class HttpTester
                 {
                     try
                     {
        -                _content=new ByteArrayOutputStream();
        +                _content = new ByteArrayOutputStream();
                         _content.write(StringUtil.getBytes(content));
                     }
                     catch (IOException e)
        @@ -327,7 +339,7 @@ public class HttpTester
                 {
                     try
                     {
        -                _content=new ByteArrayOutputStream();
        +                _content = new ByteArrayOutputStream();
                         _content.write(BufferUtil.toArray(content));
                     }
                     catch (IOException e)
        @@ -338,28 +350,28 @@ public class HttpTester
         
                 public byte[] getContentBytes()
                 {
        -            if (_content==null)
        +            if (_content == null)
                         return null;
                     return _content.toByteArray();
                 }
         
                 public String getContent()
                 {
        -            if (_content==null)
        +            if (_content == null)
                         return null;
        -            byte[] bytes=_content.toByteArray();
        +            byte[] bytes = _content.toByteArray();
         
        -            String content_type=get(HttpHeader.CONTENT_TYPE);
        -            String encoding=MimeTypes.getCharsetFromContentType(content_type);
        -            Charset charset=encoding==null?StandardCharsets.UTF_8:Charset.forName(encoding);
        +            String content_type = get(HttpHeader.CONTENT_TYPE);
        +            String encoding = MimeTypes.getCharsetFromContentType(content_type);
        +            Charset charset = encoding == null ? StandardCharsets.UTF_8 : Charset.forName(encoding);
         
        -            return new String(bytes,charset);
        +            return new String(bytes, charset);
                 }
        -        
        +
                 @Override
                 public void parsedHeader(HttpField field)
                 {
        -            add(field.getName(),field.getValue());
        +            add(field.getName(), field.getValue());
                 }
         
                 @Override
        @@ -367,18 +379,18 @@ public class HttpTester
                 {
                     return false;
                 }
        -        
        +
                 @Override
                 public boolean messageComplete()
                 {
        -            _complete=true;
        +            _complete = true;
                     return true;
                 }
         
                 @Override
                 public boolean headerComplete()
                 {
        -            _content=new ByteArrayOutputStream();
        +            _content = new ByteArrayOutputStream();
                     return false;
                 }
         
        @@ -387,12 +399,12 @@ public class HttpTester
                 {
                     _earlyEOF = true;
                 }
        -    
        +
                 public boolean isEarlyEOF()
                 {
                     return _earlyEOF;
                 }
        -    
        +
                 @Override
                 public boolean content(ByteBuffer ref)
                 {
        @@ -423,28 +435,28 @@ public class HttpTester
                         // System.err.println(info);
         
                         ByteArrayOutputStream out = new ByteArrayOutputStream();
        -                ByteBuffer header=null;
        -                ByteBuffer chunk=null;
        -                ByteBuffer content=_content==null?null:ByteBuffer.wrap(_content.toByteArray());
        +                ByteBuffer header = null;
        +                ByteBuffer chunk = null;
        +                ByteBuffer content = _content == null ? null : ByteBuffer.wrap(_content.toByteArray());
         
        -
        -                loop: while(!generator.isEnd())
        +                loop:
        +                while (!generator.isEnd())
                         {
        -                    HttpGenerator.Result result =  info instanceof MetaData.Request
        -                        ?generator.generateRequest((MetaData.Request)info,header,chunk,content,true)
        -                        :generator.generateResponse((MetaData.Response)info,false,header,chunk,content,true);
        -                    switch(result)
        +                    HttpGenerator.Result result = info instanceof MetaData.Request
        +                        ? generator.generateRequest((MetaData.Request)info, header, chunk, content, true)
        +                        : generator.generateResponse((MetaData.Response)info, false, header, chunk, content, true);
        +                    switch (result)
                             {
                                 case NEED_HEADER:
        -                            header=BufferUtil.allocate(8192);
        +                            header = BufferUtil.allocate(8192);
                                     continue;
         
                                 case NEED_CHUNK:
        -                            chunk=BufferUtil.allocate(HttpGenerator.CHUNK_SIZE);
        +                            chunk = BufferUtil.allocate(HttpGenerator.CHUNK_SIZE);
                                     continue;
         
                                 case NEED_CHUNK_TRAILER:
        -                            chunk=BufferUtil.allocate(8192);
        +                            chunk = BufferUtil.allocate(8192);
                                     continue;
         
                                 case NEED_INFO:
        @@ -479,16 +491,15 @@ public class HttpTester
                     {
                         throw new RuntimeException(e);
                     }
        -
                 }
        -        abstract public MetaData getInfo();
        +
        +        public abstract MetaData getInfo();
         
                 @Override
                 public int getHeaderCacheSize()
                 {
                     return 0;
                 }
        -
             }
         
             public static class Request extends Message implements HttpParser.RequestHandler
        @@ -499,9 +510,9 @@ public class HttpTester
                 @Override
                 public boolean startRequest(String method, String uri, HttpVersion version)
                 {
        -            _method=method;
        -            _uri=uri.toString();
        -            _version=version;
        +            _method = method;
        +            _uri = uri.toString();
        +            _version = version;
                     return false;
                 }
         
        @@ -517,29 +528,29 @@ public class HttpTester
         
                 public void setMethod(String method)
                 {
        -            _method=method;
        +            _method = method;
                 }
         
                 public void setURI(String uri)
                 {
        -            _uri=uri;
        +            _uri = uri;
                 }
         
                 @Override
                 public MetaData.Request getInfo()
                 {
        -            return new MetaData.Request(_method,new HttpURI(_uri),_version,this,_content==null?0:_content.size());
        +            return new MetaData.Request(_method, new HttpURI(_uri), _version, this, _content == null ? 0 : _content.size());
                 }
         
                 @Override
                 public String toString()
                 {
        -            return String.format("%s %s %s\n%s\n",_method,_uri,_version,super.toString());
        +            return String.format("%s %s %s\n%s\n", _method, _uri, _version, super.toString());
                 }
         
                 public void setHeader(String name, String value)
                 {
        -            put(name,value);
        +            put(name, value);
                 }
             }
         
        @@ -551,9 +562,9 @@ public class HttpTester
                 @Override
                 public boolean startResponse(HttpVersion version, int status, String reason)
                 {
        -            _version=version;
        -            _status=status;
        -            _reason=reason;
        +            _version = version;
        +            _status = status;
        +            _reason = reason;
                     return false;
                 }
         
        @@ -570,13 +581,13 @@ public class HttpTester
                 @Override
                 public MetaData.Response getInfo()
                 {
        -            return new MetaData.Response(_version,_status,_reason,this,_content==null?-1:_content.size());
        +            return new MetaData.Response(_version, _status, _reason, this, _content == null ? -1 : _content.size());
                 }
         
                 @Override
                 public String toString()
                 {
        -            return String.format("%s %s %s\n%s\n",_version,_status,_reason,super.toString());
        +            return String.format("%s %s %s\n%s\n", _version, _status, _reason, super.toString());
                 }
             }
         }
        diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpTesterTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpTesterTest.java
        index 964038ba485..3529964d1cc 100644
        --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpTesterTest.java
        +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpTesterTest.java
        @@ -1,6 +1,6 @@
         //
         //  ========================================================================
        -//  Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
        +//  Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
         //  ------------------------------------------------------------------------
         //  All rights reserved. This program and the accompanying materials
         //  are made available under the terms of the Eclipse Public License v1.0
        @@ -18,10 +18,6 @@
         
         package org.eclipse.jetty.http;
         
        -import static org.hamcrest.Matchers.is;
        -import static org.hamcrest.Matchers.nullValue;
        -import static org.hamcrest.MatcherAssert.assertThat;
        -
         import java.io.ByteArrayInputStream;
         import java.io.IOException;
         import java.io.PipedInputStream;
        @@ -32,223 +28,224 @@ import java.nio.charset.StandardCharsets;
         
         import org.junit.jupiter.api.Test;
         
        +import static org.hamcrest.MatcherAssert.assertThat;
        +import static org.hamcrest.Matchers.is;
        +import static org.hamcrest.Matchers.nullValue;
        +
         public class HttpTesterTest
         {
         
             public void testExampleUsage() throws Exception
             {
        -        try(Socket socket = new Socket("www.google.com",80))
        +        try (Socket socket = new Socket("www.google.com", 80))
                 {
                     HttpTester.Request request = HttpTester.newRequest();
                     request.setMethod("POST");
                     request.setURI("/search");
                     request.setVersion(HttpVersion.HTTP_1_0);
        -            request.put(HttpHeader.HOST,"www.google.com");
        -            request.put("Content-Type","application/x-www-form-urlencoded");
        +            request.put(HttpHeader.HOST, "www.google.com");
        +            request.put("Content-Type", "application/x-www-form-urlencoded");
                     request.setContent("q=jetty%20server");
                     ByteBuffer output = request.generate();
         
        -            socket.getOutputStream().write(output.array(),output.arrayOffset()+output.position(),output.remaining());
        +            socket.getOutputStream().write(output.array(), output.arrayOffset() + output.position(), output.remaining());
                     HttpTester.Input input = HttpTester.from(socket.getInputStream());
                     HttpTester.Response response = HttpTester.parseResponse(input);
        -            System.err.printf("%s %s %s%n",response.getVersion(),response.getStatus(),response.getReason());
        -            for (HttpField field:response)
        -                System.err.printf("%s: %s%n",field.getName(),field.getValue());
        -            System.err.printf("%n%s%n",response.getContent());
        +            System.err.printf("%s %s %s%n", response.getVersion(), response.getStatus(), response.getReason());
        +            for (HttpField field : response)
        +            {
        +                System.err.printf("%s: %s%n", field.getName(), field.getValue());
        +            }
        +            System.err.printf("%n%s%n", response.getContent());
                 }
             }
        -    
        +
             @Test
             public void testGetRequestBuffer10()
             {
        -        HttpTester.Request request =HttpTester.parseRequest(
        -            "GET /uri HTTP/1.0\r\n"+
        -            "Host: localhost\r\n"+
        -            "Connection: keep-alive\r\n"+
        -            "\r\n"+
        -            "GET /some/other/request /HTTP/1.0\r\n"+
        -            "Host: localhost\r\n"+
        -            "\r\n"
        +        HttpTester.Request request = HttpTester.parseRequest(
        +            "GET /uri HTTP/1.0\r\n" +
        +                "Host: localhost\r\n" +
        +                "Connection: keep-alive\r\n" +
        +                "\r\n" +
        +                "GET /some/other/request /HTTP/1.0\r\n" +
        +                "Host: localhost\r\n" +
        +                "\r\n"
                 );
        -        assertThat(request.getMethod(),is("GET"));
        -        assertThat(request.getUri(),is("/uri"));
        -        assertThat(request.getVersion(),is(HttpVersion.HTTP_1_0));
        -        assertThat(request.get(HttpHeader.HOST),is("localhost"));
        -        assertThat(request.getContent(),is(""));
        +        assertThat(request.getMethod(), is("GET"));
        +        assertThat(request.getUri(), is("/uri"));
        +        assertThat(request.getVersion(), is(HttpVersion.HTTP_1_0));
        +        assertThat(request.get(HttpHeader.HOST), is("localhost"));
        +        assertThat(request.getContent(), is(""));
             }
        -    
        +
             @Test
             public void testGetRequestBuffer11()
             {
        -        HttpTester.Request request =HttpTester.parseRequest(
        -            "GET /uri HTTP/1.1\r\n"+
        -            "Host: localhost\r\n"+
        -            "\r\n"+
        -            "GET /some/other/request /HTTP/1.1\r\n"+
        -            "Host: localhost\r\n"+
        -            "\r\n"
        +        HttpTester.Request request = HttpTester.parseRequest(
        +            "GET /uri HTTP/1.1\r\n" +
        +                "Host: localhost\r\n" +
        +                "\r\n" +
        +                "GET /some/other/request /HTTP/1.1\r\n" +
        +                "Host: localhost\r\n" +
        +                "\r\n"
                 );
        -        assertThat(request.getMethod(),is("GET"));
        -        assertThat(request.getUri(),is("/uri"));
        -        assertThat(request.getVersion(),is(HttpVersion.HTTP_1_1));
        -        assertThat(request.get(HttpHeader.HOST),is("localhost"));
        -        assertThat(request.getContent(),is(""));
        +        assertThat(request.getMethod(), is("GET"));
        +        assertThat(request.getUri(), is("/uri"));
        +        assertThat(request.getVersion(), is(HttpVersion.HTTP_1_1));
        +        assertThat(request.get(HttpHeader.HOST), is("localhost"));
        +        assertThat(request.getContent(), is(""));
             }
         
        -    
        -    
             @Test
             public void testPostRequestBuffer10()
             {
        -        HttpTester.Request request =HttpTester.parseRequest(
        -            "POST /uri HTTP/1.0\r\n"+
        -            "Host: localhost\r\n"+
        -            "Connection: keep-alive\r\n"+
        -            "Content-Length: 16\r\n"+
        -            "\r\n"+
        -            "0123456789ABCDEF"+
        -            "\r\n"+
        -            "GET /some/other/request /HTTP/1.0\r\n"+
        -            "Host: localhost\r\n"+
        -            "\r\n"
        +        HttpTester.Request request = HttpTester.parseRequest(
        +            "POST /uri HTTP/1.0\r\n" +
        +                "Host: localhost\r\n" +
        +                "Connection: keep-alive\r\n" +
        +                "Content-Length: 16\r\n" +
        +                "\r\n" +
        +                "0123456789ABCDEF" +
        +                "\r\n" +
        +                "GET /some/other/request /HTTP/1.0\r\n" +
        +                "Host: localhost\r\n" +
        +                "\r\n"
                 );
        -        assertThat(request.getMethod(),is("POST"));
        -        assertThat(request.getUri(),is("/uri"));
        -        assertThat(request.getVersion(),is(HttpVersion.HTTP_1_0));
        -        assertThat(request.get(HttpHeader.HOST),is("localhost"));
        -        assertThat(request.getContent(),is("0123456789ABCDEF"));
        -        
        +        assertThat(request.getMethod(), is("POST"));
        +        assertThat(request.getUri(), is("/uri"));
        +        assertThat(request.getVersion(), is(HttpVersion.HTTP_1_0));
        +        assertThat(request.get(HttpHeader.HOST), is("localhost"));
        +        assertThat(request.getContent(), is("0123456789ABCDEF"));
             }
        -    
        +
             @Test
             public void testPostRequestBuffer11()
             {
        -        HttpTester.Request request =HttpTester.parseRequest(
        -            "POST /uri HTTP/1.1\r\n"+
        -            "Host: localhost\r\n"+
        -            "Transfer-Encoding: chunked\r\n"+
        -            "\r\n"+
        -            "A\r\n"+
        -            "0123456789\r\n"+
        -            "6\r\n"+
        -            "ABCDEF\r\n"+
        -            "0\r\n"+
        -            "\r\n"+
        -            "GET /some/other/request /HTTP/1.1\r\n"+
        -            "Host: localhost\r\n"+
        -            "\r\n"
        +        HttpTester.Request request = HttpTester.parseRequest(
        +            "POST /uri HTTP/1.1\r\n" +
        +                "Host: localhost\r\n" +
        +                "Transfer-Encoding: chunked\r\n" +
        +                "\r\n" +
        +                "A\r\n" +
        +                "0123456789\r\n" +
        +                "6\r\n" +
        +                "ABCDEF\r\n" +
        +                "0\r\n" +
        +                "\r\n" +
        +                "GET /some/other/request /HTTP/1.1\r\n" +
        +                "Host: localhost\r\n" +
        +                "\r\n"
                 );
        -        assertThat(request.getMethod(),is("POST"));
        -        assertThat(request.getUri(),is("/uri"));
        -        assertThat(request.getVersion(),is(HttpVersion.HTTP_1_1));
        -        assertThat(request.get(HttpHeader.HOST),is("localhost"));
        -        assertThat(request.getContent(),is("0123456789ABCDEF"));
        -        
        +        assertThat(request.getMethod(), is("POST"));
        +        assertThat(request.getUri(), is("/uri"));
        +        assertThat(request.getVersion(), is(HttpVersion.HTTP_1_1));
        +        assertThat(request.get(HttpHeader.HOST), is("localhost"));
        +        assertThat(request.getContent(), is("0123456789ABCDEF"));
             }
        -    
         
             @Test
             public void testResponseEOFBuffer()
             {
        -        HttpTester.Response response =HttpTester.parseResponse(
        -            "HTTP/1.1 200 OK\r\n"+
        -            "Header: value\r\n"+
        -            "Connection: close\r\n"+
        -            "\r\n"+
        -            "0123456789ABCDEF"
        +        HttpTester.Response response = HttpTester.parseResponse(
        +            "HTTP/1.1 200 OK\r\n" +
        +                "Header: value\r\n" +
        +                "Connection: close\r\n" +
        +                "\r\n" +
        +                "0123456789ABCDEF"
                 );
         
        -        assertThat(response.getVersion(),is(HttpVersion.HTTP_1_1));
        -        assertThat(response.getStatus(),is(200));
        -        assertThat(response.getReason(),is("OK"));
        -        assertThat(response.get("Header"),is("value"));
        -        assertThat(response.getContent(),is("0123456789ABCDEF")); 
        +        assertThat(response.getVersion(), is(HttpVersion.HTTP_1_1));
        +        assertThat(response.getStatus(), is(200));
        +        assertThat(response.getReason(), is("OK"));
        +        assertThat(response.get("Header"), is("value"));
        +        assertThat(response.getContent(), is("0123456789ABCDEF"));
             }
        -    
        +
             @Test
             public void testResponseLengthBuffer()
             {
        -        HttpTester.Response response =HttpTester.parseResponse(
        -            "HTTP/1.1 200 OK\r\n"+
        -            "Header: value\r\n"+
        -            "Content-Length: 16\r\n"+
        -            "\r\n"+
        -            "0123456789ABCDEF"+
        -            "HTTP/1.1 200 OK\r\n"+
        -            "\r\n"
        +        HttpTester.Response response = HttpTester.parseResponse(
        +            "HTTP/1.1 200 OK\r\n" +
        +                "Header: value\r\n" +
        +                "Content-Length: 16\r\n" +
        +                "\r\n" +
        +                "0123456789ABCDEF" +
        +                "HTTP/1.1 200 OK\r\n" +
        +                "\r\n"
                 );
         
        -        assertThat(response.getVersion(),is(HttpVersion.HTTP_1_1));
        -        assertThat(response.getStatus(),is(200));
        -        assertThat(response.getReason(),is("OK"));
        -        assertThat(response.get("Header"),is("value"));
        -        assertThat(response.getContent(),is("0123456789ABCDEF")); 
        +        assertThat(response.getVersion(), is(HttpVersion.HTTP_1_1));
        +        assertThat(response.getStatus(), is(200));
        +        assertThat(response.getReason(), is("OK"));
        +        assertThat(response.get("Header"), is("value"));
        +        assertThat(response.getContent(), is("0123456789ABCDEF"));
             }
        -    
        +
             @Test
             public void testResponseChunkedBuffer()
             {
        -        HttpTester.Response response =HttpTester.parseResponse(
        -            "HTTP/1.1 200 OK\r\n"+
        -            "Header: value\r\n"+
        -            "Transfer-Encoding: chunked\r\n"+
        -            "\r\n"+
        -            "A\r\n"+
        -            "0123456789\r\n"+
        -            "6\r\n"+
        -            "ABCDEF\r\n"+
        -            "0\r\n"+
        -            "\r\n"+
        -            "HTTP/1.1 200 OK\r\n"+
        -            "\r\n"
        +        HttpTester.Response response = HttpTester.parseResponse(
        +            "HTTP/1.1 200 OK\r\n" +
        +                "Header: value\r\n" +
        +                "Transfer-Encoding: chunked\r\n" +
        +                "\r\n" +
        +                "A\r\n" +
        +                "0123456789\r\n" +
        +                "6\r\n" +
        +                "ABCDEF\r\n" +
        +                "0\r\n" +
        +                "\r\n" +
        +                "HTTP/1.1 200 OK\r\n" +
        +                "\r\n"
                 );
         
        -        assertThat(response.getVersion(),is(HttpVersion.HTTP_1_1));
        -        assertThat(response.getStatus(),is(200));
        -        assertThat(response.getReason(),is("OK"));
        -        assertThat(response.get("Header"),is("value"));
        -        assertThat(response.getContent(),is("0123456789ABCDEF")); 
        +        assertThat(response.getVersion(), is(HttpVersion.HTTP_1_1));
        +        assertThat(response.getStatus(), is(200));
        +        assertThat(response.getReason(), is("OK"));
        +        assertThat(response.get("Header"), is("value"));
        +        assertThat(response.getContent(), is("0123456789ABCDEF"));
             }
         
             @Test
             public void testResponsesInput() throws Exception
             {
                 ByteArrayInputStream stream = new ByteArrayInputStream((
        -            "HTTP/1.1 200 OK\r\n"+
        -            "Header: value\r\n"+
        -            "Transfer-Encoding: chunked\r\n"+
        -            "\r\n"+
        -            "A\r\n"+
        -            "0123456789\r\n"+
        -            "6\r\n"+
        -            "ABCDEF\r\n"+
        -            "0\r\n"+
        -            "\r\n"+
        -            "HTTP/1.1 400 OK\r\n"+
        -            "Next: response\r\n"+
        -            "Content-Length: 16\r\n"+
        -            "\r\n"+
        -            "0123456789ABCDEF").getBytes(StandardCharsets.ISO_8859_1)
        +            "HTTP/1.1 200 OK\r\n" +
        +                "Header: value\r\n" +
        +                "Transfer-Encoding: chunked\r\n" +
        +                "\r\n" +
        +                "A\r\n" +
        +                "0123456789\r\n" +
        +                "6\r\n" +
        +                "ABCDEF\r\n" +
        +                "0\r\n" +
        +                "\r\n" +
        +                "HTTP/1.1 400 OK\r\n" +
        +                "Next: response\r\n" +
        +                "Content-Length: 16\r\n" +
        +                "\r\n" +
        +                "0123456789ABCDEF").getBytes(StandardCharsets.ISO_8859_1)
                 );
         
                 HttpTester.Input in = HttpTester.from(stream);
        -        
        +
                 HttpTester.Response response = HttpTester.parseResponse(in);
        -        
        -        assertThat(response.getVersion(),is(HttpVersion.HTTP_1_1));
        -        assertThat(response.getStatus(),is(200));
        -        assertThat(response.getReason(),is("OK"));
        -        assertThat(response.get("Header"),is("value"));
        -        assertThat(response.getContent(),is("0123456789ABCDEF")); 
        -        
        +
        +        assertThat(response.getVersion(), is(HttpVersion.HTTP_1_1));
        +        assertThat(response.getStatus(), is(200));
        +        assertThat(response.getReason(), is("OK"));
        +        assertThat(response.get("Header"), is("value"));
        +        assertThat(response.getContent(), is("0123456789ABCDEF"));
        +
                 response = HttpTester.parseResponse(in);
        -        assertThat(response.getVersion(),is(HttpVersion.HTTP_1_1));
        -        assertThat(response.getStatus(),is(400));
        -        assertThat(response.getReason(),is("OK"));
        -        assertThat(response.get("Next"),is("response"));
        -        assertThat(response.getContent(),is("0123456789ABCDEF"));    
        +        assertThat(response.getVersion(), is(HttpVersion.HTTP_1_1));
        +        assertThat(response.getStatus(), is(400));
        +        assertThat(response.getReason(), is("OK"));
        +        assertThat(response.get("Next"), is("response"));
        +        assertThat(response.getContent(), is("0123456789ABCDEF"));
             }
        -    
        +
             @Test
             public void testResponsesSplitInput() throws Exception
             {
        @@ -258,66 +255,60 @@ public class HttpTesterTest
                     @Override
                     public synchronized int read(byte[] b, int off, int len) throws IOException
                     {
        -                if (available()==0)
        +                if (available() == 0)
                             return 0;
        -                return super.read(b,off,len);
        +                return super.read(b, off, len);
                     }
                 };
        -        
        +
                 HttpTester.Input in = HttpTester.from(stream);
        -        
        +
                 src.write((
        -            "HTTP/1.1 200 OK\r\n"+
        -            "Header: value\r\n"+
        -            "Transfer-Encoding: chunked\r\n"+
        -            "\r\n"+
        -            "A\r\n"+
        -            "0123456789\r\n"+
        -            "6\r\n"+
        -            "ABC"
        +                "HTTP/1.1 200 OK\r\n" +
        +                    "Header: value\r\n" +
        +                    "Transfer-Encoding: chunked\r\n" +
        +                    "\r\n" +
        +                    "A\r\n" +
        +                    "0123456789\r\n" +
        +                    "6\r\n" +
        +                    "ABC"
                     ).getBytes(StandardCharsets.ISO_8859_1)
                 );
         
                 HttpTester.Response response = HttpTester.parseResponse(in);
        -        assertThat(response,nullValue());
        +        assertThat(response, nullValue());
                 src.write((
        -            "DEF\r\n"+
        -            "0\r\n"+
        -            "\r\n"+
        -            "HTTP/1.1 400 OK\r\n"+
        -            "Next: response\r\n"+
        -            "Content-Length: 16\r\n"+
        -            "\r\n"+
        -            "0123456789"
        +                "DEF\r\n" +
        +                    "0\r\n" +
        +                    "\r\n" +
        +                    "HTTP/1.1 400 OK\r\n" +
        +                    "Next: response\r\n" +
        +                    "Content-Length: 16\r\n" +
        +                    "\r\n" +
        +                    "0123456789"
                     ).getBytes(StandardCharsets.ISO_8859_1)
                 );
        -        
        -        
        -        response = HttpTester.parseResponse(in);
        -        assertThat(response.getVersion(),is(HttpVersion.HTTP_1_1));
        -        assertThat(response.getStatus(),is(200));
        -        assertThat(response.getReason(),is("OK"));
        -        assertThat(response.get("Header"),is("value"));
        -        assertThat(response.getContent(),is("0123456789ABCDEF")); 
        -        
        -        response = HttpTester.parseResponse(in);
        -        assertThat(response,nullValue());
        -        
        -        src.write((
        -            "ABCDEF"
        -            ).getBytes(StandardCharsets.ISO_8859_1)
        -        );
        -        
        -        response = HttpTester.parseResponse(in);
        -        assertThat(response.getVersion(),is(HttpVersion.HTTP_1_1));
        -        assertThat(response.getStatus(),is(400));
        -        assertThat(response.getReason(),is("OK"));
        -        assertThat(response.get("Next"),is("response"));
        -        assertThat(response.getContent(),is("0123456789ABCDEF"));    
        -    }
        -    
        -    
        -    
        -    
         
        +        response = HttpTester.parseResponse(in);
        +        assertThat(response.getVersion(), is(HttpVersion.HTTP_1_1));
        +        assertThat(response.getStatus(), is(200));
        +        assertThat(response.getReason(), is("OK"));
        +        assertThat(response.get("Header"), is("value"));
        +        assertThat(response.getContent(), is("0123456789ABCDEF"));
        +
        +        response = HttpTester.parseResponse(in);
        +        assertThat(response, nullValue());
        +
        +        src.write((
        +                "ABCDEF"
        +            ).getBytes(StandardCharsets.ISO_8859_1)
        +        );
        +
        +        response = HttpTester.parseResponse(in);
        +        assertThat(response.getVersion(), is(HttpVersion.HTTP_1_1));
        +        assertThat(response.getStatus(), is(400));
        +        assertThat(response.getReason(), is("OK"));
        +        assertThat(response.get("Next"), is("response"));
        +        assertThat(response.getContent(), is("0123456789ABCDEF"));
        +    }
         }
        diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURIParseTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURIParseTest.java
        index 6510679f850..6b37be93102 100644
        --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURIParseTest.java
        +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURIParseTest.java
        @@ -1,6 +1,6 @@
         //
         //  ========================================================================
        -//  Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
        +//  Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
         //  ------------------------------------------------------------------------
         //  All rights reserved. This program and the accompanying materials
         //  are made available under the terms of the Eclipse Public License v1.0
        @@ -16,15 +16,8 @@
         //  ========================================================================
         //
         
        -
         package org.eclipse.jetty.http;
         
        -import static org.hamcrest.MatcherAssert.assertThat;
        -import static org.hamcrest.Matchers.is;
        -import static org.hamcrest.Matchers.notNullValue;
        -import static org.hamcrest.Matchers.nullValue;
        -import static org.junit.jupiter.api.Assumptions.assumeTrue;
        -
         import java.net.URI;
         import java.net.URISyntaxException;
         import java.util.stream.Stream;
        @@ -33,166 +26,172 @@ 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.is;
        +import static org.hamcrest.Matchers.notNullValue;
        +import static org.hamcrest.Matchers.nullValue;
        +import static org.junit.jupiter.api.Assumptions.assumeTrue;
        +
         public class HttpURIParseTest
         {
             public static Stream data()
             {
                 return Stream.of(
         
        -        // Nothing but path
        -        Arguments.of("path",null,null,"-1","path",null,null,null),
        -        Arguments.of("path/path",null,null,"-1","path/path",null,null,null),
        -        Arguments.of("%65ncoded/path",null,null,"-1","%65ncoded/path",null,null,null),
        -                
        -        // Basic path reference     
        -        Arguments.of("/path/to/context",null,null,"-1","/path/to/context",null,null,null),
        -        
        -        // Basic with encoded query 
        -        Arguments.of("http://example.com/path/to/context;param?query=%22value%22#fragment","http","example.com","-1","/path/to/context;param","param","query=%22value%22","fragment"),
        -        Arguments.of("http://[::1]/path/to/context;param?query=%22value%22#fragment","http","[::1]","-1","/path/to/context;param","param","query=%22value%22","fragment"),
        -        
        -        // Basic with parameters and query
        -        Arguments.of("http://example.com:8080/path/to/context;param?query=%22value%22#fragment","http","example.com","8080","/path/to/context;param","param","query=%22value%22","fragment"),
        -        Arguments.of("http://[::1]:8080/path/to/context;param?query=%22value%22#fragment","http","[::1]","8080","/path/to/context;param","param","query=%22value%22","fragment"),
        -        
        -        // Path References
        -        Arguments.of("/path/info",null,null,null,"/path/info",null,null,null),
        -        Arguments.of("/path/info#fragment",null,null,null,"/path/info",null,null,"fragment"),
        -        Arguments.of("/path/info?query",null,null,null,"/path/info",null,"query",null),
        -        Arguments.of("/path/info?query#fragment",null,null,null,"/path/info",null,"query","fragment"),
        -        Arguments.of("/path/info;param",null,null,null,"/path/info;param","param",null,null),
        -        Arguments.of("/path/info;param#fragment",null,null,null,"/path/info;param","param",null,"fragment"),
        -        Arguments.of("/path/info;param?query",null,null,null,"/path/info;param","param","query",null),
        -        Arguments.of("/path/info;param?query#fragment",null,null,null,"/path/info;param","param","query","fragment"),
        -        Arguments.of("/path/info;a=b/foo;c=d",null,null,null,"/path/info;a=b/foo;c=d","c=d",null,null), // TODO #405
        +            // Nothing but path
        +            Arguments.of("path", null, null, "-1", "path", null, null, null),
        +            Arguments.of("path/path", null, null, "-1", "path/path", null, null, null),
        +            Arguments.of("%65ncoded/path", null, null, "-1", "%65ncoded/path", null, null, null),
         
        -        // Protocol Less (aka scheme-less) URIs
        -        Arguments.of("//host/path/info",null,"host",null,"/path/info",null,null,null),
        -        Arguments.of("//user@host/path/info",null,"host",null,"/path/info",null,null,null),
        -        Arguments.of("//user@host:8080/path/info",null,"host","8080","/path/info",null,null,null),
        -        Arguments.of("//host:8080/path/info",null,"host","8080","/path/info",null,null,null),
        -        
        -        // Host Less 
        -        Arguments.of("http:/path/info","http",null,null,"/path/info",null,null,null),
        -        Arguments.of("http:/path/info#fragment","http",null,null,"/path/info",null,null,"fragment"),
        -        Arguments.of("http:/path/info?query","http",null,null,"/path/info",null,"query",null),
        -        Arguments.of("http:/path/info?query#fragment","http",null,null,"/path/info",null,"query","fragment"),
        -        Arguments.of("http:/path/info;param","http",null,null,"/path/info;param","param",null,null),
        -        Arguments.of("http:/path/info;param#fragment","http",null,null,"/path/info;param","param",null,"fragment"),
        -        Arguments.of("http:/path/info;param?query","http",null,null,"/path/info;param","param","query",null),
        -        Arguments.of("http:/path/info;param?query#fragment","http",null,null,"/path/info;param","param","query","fragment"),
        -        
        -        // Everything and the kitchen sink
        -        Arguments.of("http://user@host:8080/path/info;param?query#fragment","http","host","8080","/path/info;param","param","query","fragment"),
        -        Arguments.of("xxxxx://user@host:8080/path/info;param?query#fragment","xxxxx","host","8080","/path/info;param","param","query","fragment"),
        -        
        -        // No host, parameter with no content
        -        Arguments.of("http:///;?#","http",null,null,"/;","","",""),
        -        
        -        // Path with query that has no value
        -        Arguments.of("/path/info?a=?query",null,null,null,"/path/info",null,"a=?query",null),
        -        
        -        // Path with query alt syntax
        -        Arguments.of("/path/info?a=;query",null,null,null,"/path/info",null,"a=;query",null),
        +            // Basic path reference
        +            Arguments.of("/path/to/context", null, null, "-1", "/path/to/context", null, null, null),
         
        -        // URI with host character
        -        Arguments.of("/@path/info",null,null,null,"/@path/info",null,null,null),
        -        Arguments.of("/user@path/info",null,null,null,"/user@path/info",null,null,null),
        -        Arguments.of("//user@host/info",null,"host",null,"/info",null,null,null),
        -        Arguments.of("//@host/info",null,"host",null,"/info",null,null,null),
        -        Arguments.of("@host/info",null,null,null,"@host/info",null,null,null),
        -        
        -        // Scheme-less, with host and port (overlapping with path)
        -        Arguments.of("//host:8080//",null,"host","8080","//",null,null,null),
        -        
        -        // File reference
        -        Arguments.of("file:///path/info","file",null,null,"/path/info",null,null,null),
        -        Arguments.of("file:/path/info","file",null,null,"/path/info",null,null,null),
        -        
        -        // Bad URI (no scheme, no host, no path) 
        -        Arguments.of("//",null,null,null,null,null,null,null),
        -        
        -        // Simple localhost references
        -        Arguments.of("http://localhost/","http","localhost",null,"/",null,null,null),
        -        Arguments.of("http://localhost:8080/", "http", "localhost","8080","/", null, null,null),
        -        Arguments.of("http://localhost/?x=y", "http", "localhost",null,"/", null,"x=y",null),
        -        
        -        // Simple path with parameter 
        -        Arguments.of("/;param",null, null,null,"/;param", "param",null,null),
        -        Arguments.of(";param",null, null,null,";param", "param",null,null),
        -        
        -        // Simple path with query
        -        Arguments.of("/?x=y",null, null,null,"/", null,"x=y",null),
        -        Arguments.of("/?abc=test",null, null,null,"/", null,"abc=test",null),
        -        
        -        // Simple path with fragment
        -        Arguments.of("/#fragment",null, null,null,"/", null,null,"fragment"),
        -        
        -        // Simple IPv4 host with port (default path)
        -        Arguments.of("http://192.0.0.1:8080/","http","192.0.0.1","8080","/",null,null,null),
        -        
        -        // Simple IPv6 host with port (default path)
        -        
        -        Arguments.of("http://[2001:db8::1]:8080/","http","[2001:db8::1]","8080","/",null,null,null),
        -        // IPv6 authenticated host with port (default path)
        -        
        -        Arguments.of("http://user@[2001:db8::1]:8080/","http","[2001:db8::1]","8080","/",null,null,null),
        -        
        -        // Simple IPv6 host no port (default path)
        -        Arguments.of("http://[2001:db8::1]/","http","[2001:db8::1]",null,"/",null,null,null),
        -        
        -        // Scheme-less IPv6, host with port (default path)
        -        Arguments.of("//[2001:db8::1]:8080/",null,"[2001:db8::1]","8080","/",null,null,null),
        -        
        -        // Interpreted as relative path of "*" (no host/port/scheme/query/fragment)
        -        Arguments.of("*",null,null,null,"*",null, null,null),
        +            // Basic with encoded query
        +            Arguments.of("http://example.com/path/to/context;param?query=%22value%22#fragment", "http", "example.com", "-1", "/path/to/context;param", "param", "query=%22value%22", "fragment"),
        +            Arguments.of("http://[::1]/path/to/context;param?query=%22value%22#fragment", "http", "[::1]", "-1", "/path/to/context;param", "param", "query=%22value%22", "fragment"),
         
        -        // Path detection Tests (seen from JSP/JSTL and  use)
        -        Arguments.of("http://host:8080/path/info?q1=v1&q2=v2","http","host","8080","/path/info",null,"q1=v1&q2=v2",null),
        -        Arguments.of("/path/info?q1=v1&q2=v2",null,null,null,"/path/info",null,"q1=v1&q2=v2",null),
        -        Arguments.of("/info?q1=v1&q2=v2",null,null,null,"/info",null,"q1=v1&q2=v2",null),
        -        Arguments.of("info?q1=v1&q2=v2",null,null,null,"info",null,"q1=v1&q2=v2",null),
        -        Arguments.of("info;q1=v1?q2=v2",null,null,null,"info;q1=v1","q1=v1","q2=v2",null),
        -        
        -        // Path-less, query only (seen from JSP/JSTL and  use)
        -        Arguments.of("?q1=v1&q2=v2",null,null,null,"",null,"q1=v1&q2=v2",null)
        +            // Basic with parameters and query
        +            Arguments.of("http://example.com:8080/path/to/context;param?query=%22value%22#fragment", "http", "example.com", "8080", "/path/to/context;param", "param", "query=%22value%22", "fragment"),
        +            Arguments.of("http://[::1]:8080/path/to/context;param?query=%22value%22#fragment", "http", "[::1]", "8080", "/path/to/context;param", "param", "query=%22value%22", "fragment"),
        +
        +            // Path References
        +            Arguments.of("/path/info", null, null, null, "/path/info", null, null, null),
        +            Arguments.of("/path/info#fragment", null, null, null, "/path/info", null, null, "fragment"),
        +            Arguments.of("/path/info?query", null, null, null, "/path/info", null, "query", null),
        +            Arguments.of("/path/info?query#fragment", null, null, null, "/path/info", null, "query", "fragment"),
        +            Arguments.of("/path/info;param", null, null, null, "/path/info;param", "param", null, null),
        +            Arguments.of("/path/info;param#fragment", null, null, null, "/path/info;param", "param", null, "fragment"),
        +            Arguments.of("/path/info;param?query", null, null, null, "/path/info;param", "param", "query", null),
        +            Arguments.of("/path/info;param?query#fragment", null, null, null, "/path/info;param", "param", "query", "fragment"),
        +            Arguments.of("/path/info;a=b/foo;c=d", null, null, null, "/path/info;a=b/foo;c=d", "c=d", null, null), // TODO #405
        +
        +            // Protocol Less (aka scheme-less) URIs
        +            Arguments.of("//host/path/info", null, "host", null, "/path/info", null, null, null),
        +            Arguments.of("//user@host/path/info", null, "host", null, "/path/info", null, null, null),
        +            Arguments.of("//user@host:8080/path/info", null, "host", "8080", "/path/info", null, null, null),
        +            Arguments.of("//host:8080/path/info", null, "host", "8080", "/path/info", null, null, null),
        +
        +            // Host Less
        +            Arguments.of("http:/path/info", "http", null, null, "/path/info", null, null, null),
        +            Arguments.of("http:/path/info#fragment", "http", null, null, "/path/info", null, null, "fragment"),
        +            Arguments.of("http:/path/info?query", "http", null, null, "/path/info", null, "query", null),
        +            Arguments.of("http:/path/info?query#fragment", "http", null, null, "/path/info", null, "query", "fragment"),
        +            Arguments.of("http:/path/info;param", "http", null, null, "/path/info;param", "param", null, null),
        +            Arguments.of("http:/path/info;param#fragment", "http", null, null, "/path/info;param", "param", null, "fragment"),
        +            Arguments.of("http:/path/info;param?query", "http", null, null, "/path/info;param", "param", "query", null),
        +            Arguments.of("http:/path/info;param?query#fragment", "http", null, null, "/path/info;param", "param", "query", "fragment"),
        +
        +            // Everything and the kitchen sink
        +            Arguments.of("http://user@host:8080/path/info;param?query#fragment", "http", "host", "8080", "/path/info;param", "param", "query", "fragment"),
        +            Arguments.of("xxxxx://user@host:8080/path/info;param?query#fragment", "xxxxx", "host", "8080", "/path/info;param", "param", "query", "fragment"),
        +
        +            // No host, parameter with no content
        +            Arguments.of("http:///;?#", "http", null, null, "/;", "", "", ""),
        +
        +            // Path with query that has no value
        +            Arguments.of("/path/info?a=?query", null, null, null, "/path/info", null, "a=?query", null),
        +
        +            // Path with query alt syntax
        +            Arguments.of("/path/info?a=;query", null, null, null, "/path/info", null, "a=;query", null),
        +
        +            // URI with host character
        +            Arguments.of("/@path/info", null, null, null, "/@path/info", null, null, null),
        +            Arguments.of("/user@path/info", null, null, null, "/user@path/info", null, null, null),
        +            Arguments.of("//user@host/info", null, "host", null, "/info", null, null, null),
        +            Arguments.of("//@host/info", null, "host", null, "/info", null, null, null),
        +            Arguments.of("@host/info", null, null, null, "@host/info", null, null, null),
        +
        +            // Scheme-less, with host and port (overlapping with path)
        +            Arguments.of("//host:8080//", null, "host", "8080", "//", null, null, null),
        +
        +            // File reference
        +            Arguments.of("file:///path/info", "file", null, null, "/path/info", null, null, null),
        +            Arguments.of("file:/path/info", "file", null, null, "/path/info", null, null, null),
        +
        +            // Bad URI (no scheme, no host, no path)
        +            Arguments.of("//", null, null, null, null, null, null, null),
        +
        +            // Simple localhost references
        +            Arguments.of("http://localhost/", "http", "localhost", null, "/", null, null, null),
        +            Arguments.of("http://localhost:8080/", "http", "localhost", "8080", "/", null, null, null),
        +            Arguments.of("http://localhost/?x=y", "http", "localhost", null, "/", null, "x=y", null),
        +
        +            // Simple path with parameter
        +            Arguments.of("/;param", null, null, null, "/;param", "param", null, null),
        +            Arguments.of(";param", null, null, null, ";param", "param", null, null),
        +
        +            // Simple path with query
        +            Arguments.of("/?x=y", null, null, null, "/", null, "x=y", null),
        +            Arguments.of("/?abc=test", null, null, null, "/", null, "abc=test", null),
        +
        +            // Simple path with fragment
        +            Arguments.of("/#fragment", null, null, null, "/", null, null, "fragment"),
        +
        +            // Simple IPv4 host with port (default path)
        +            Arguments.of("http://192.0.0.1:8080/", "http", "192.0.0.1", "8080", "/", null, null, null),
        +
        +            // Simple IPv6 host with port (default path)
        +
        +            Arguments.of("http://[2001:db8::1]:8080/", "http", "[2001:db8::1]", "8080", "/", null, null, null),
        +            // IPv6 authenticated host with port (default path)
        +
        +            Arguments.of("http://user@[2001:db8::1]:8080/", "http", "[2001:db8::1]", "8080", "/", null, null, null),
        +
        +            // Simple IPv6 host no port (default path)
        +            Arguments.of("http://[2001:db8::1]/", "http", "[2001:db8::1]", null, "/", null, null, null),
        +
        +            // Scheme-less IPv6, host with port (default path)
        +            Arguments.of("//[2001:db8::1]:8080/", null, "[2001:db8::1]", "8080", "/", null, null, null),
        +
        +            // Interpreted as relative path of "*" (no host/port/scheme/query/fragment)
        +            Arguments.of("*", null, null, null, "*", null, null, null),
        +
        +            // Path detection Tests (seen from JSP/JSTL and  use)
        +            Arguments.of("http://host:8080/path/info?q1=v1&q2=v2", "http", "host", "8080", "/path/info", null, "q1=v1&q2=v2", null),
        +            Arguments.of("/path/info?q1=v1&q2=v2", null, null, null, "/path/info", null, "q1=v1&q2=v2", null),
        +            Arguments.of("/info?q1=v1&q2=v2", null, null, null, "/info", null, "q1=v1&q2=v2", null),
        +            Arguments.of("info?q1=v1&q2=v2", null, null, null, "info", null, "q1=v1&q2=v2", null),
        +            Arguments.of("info;q1=v1?q2=v2", null, null, null, "info;q1=v1", "q1=v1", "q2=v2", null),
        +
        +            // Path-less, query only (seen from JSP/JSTL and  use)
        +            Arguments.of("?q1=v1&q2=v2", null, null, null, "", null, "q1=v1&q2=v2", null)
                 );
             }
        -    
        +
             @ParameterizedTest
             @MethodSource("data")
             public void testParseString(String input, String scheme, String host, Integer port, String path, String param, String query, String fragment) throws Exception
             {
                 HttpURI httpUri = new HttpURI(input);
        -        
        +
                 try
                 {
                     new URI(input);
                     // URI is valid (per java.net.URI parsing)
        -            
        +
                     // Test case sanity check
        -            assertThat("[" + input + "] expected path (test case) cannot be null",path,notNullValue());
        +            assertThat("[" + input + "] expected path (test case) cannot be null", path, notNullValue());
         
                     // Assert expectations
        -            assertThat("[" + input + "] .scheme",httpUri.getScheme(),is(scheme));
        -            assertThat("[" + input + "] .host",httpUri.getHost(),is(host));
        -            assertThat("[" + input + "] .port",httpUri.getPort(),is(port == null ? -1 : port));
        -            assertThat("[" + input + "] .path",httpUri.getPath(),is(path));
        -            assertThat("[" + input + "] .param",httpUri.getParam(),is(param));
        -            assertThat("[" + input + "] .query",httpUri.getQuery(),is(query));
        -            assertThat("[" + input + "] .fragment",httpUri.getFragment(),is(fragment));
        -            assertThat("[" + input + "] .toString",httpUri.toString(),is(input));
        +            assertThat("[" + input + "] .scheme", httpUri.getScheme(), is(scheme));
        +            assertThat("[" + input + "] .host", httpUri.getHost(), is(host));
        +            assertThat("[" + input + "] .port", httpUri.getPort(), is(port == null ? -1 : port));
        +            assertThat("[" + input + "] .path", httpUri.getPath(), is(path));
        +            assertThat("[" + input + "] .param", httpUri.getParam(), is(param));
        +            assertThat("[" + input + "] .query", httpUri.getQuery(), is(query));
        +            assertThat("[" + input + "] .fragment", httpUri.getFragment(), is(fragment));
        +            assertThat("[" + input + "] .toString", httpUri.toString(), is(input));
                 }
                 catch (URISyntaxException e)
                 {
                     // Assert HttpURI values for invalid URI (such as "//")
        -            assertThat("[" + input + "] .scheme",httpUri.getScheme(),is(nullValue()));
        -            assertThat("[" + input + "] .host",httpUri.getHost(),is(nullValue()));
        -            assertThat("[" + input + "] .port",httpUri.getPort(),is(-1));
        -            assertThat("[" + input + "] .path",httpUri.getPath(),is(nullValue()));
        -            assertThat("[" + input + "] .param",httpUri.getParam(),is(nullValue()));
        -            assertThat("[" + input + "] .query",httpUri.getQuery(),is(nullValue()));
        -            assertThat("[" + input + "] .fragment",httpUri.getFragment(),is(nullValue()));
        +            assertThat("[" + input + "] .scheme", httpUri.getScheme(), is(nullValue()));
        +            assertThat("[" + input + "] .host", httpUri.getHost(), is(nullValue()));
        +            assertThat("[" + input + "] .port", httpUri.getPort(), is(-1));
        +            assertThat("[" + input + "] .path", httpUri.getPath(), is(nullValue()));
        +            assertThat("[" + input + "] .param", httpUri.getParam(), is(nullValue()));
        +            assertThat("[" + input + "] .query", httpUri.getQuery(), is(nullValue()));
        +            assertThat("[" + input + "] .fragment", httpUri.getFragment(), is(nullValue()));
                 }
             }
         
        @@ -213,15 +212,15 @@ public class HttpURIParseTest
         
                 HttpURI httpUri = new HttpURI(javaUri);
         
        -        assertThat("[" + input + "] .scheme",httpUri.getScheme(),is(scheme));
        -        assertThat("[" + input + "] .host",httpUri.getHost(),is(host));
        -        assertThat("[" + input + "] .port",httpUri.getPort(),is(port == null ? -1 : port));
        -        assertThat("[" + input + "] .path",httpUri.getPath(),is(path));
        -        assertThat("[" + input + "] .param",httpUri.getParam(),is(param));
        -        assertThat("[" + input + "] .query",httpUri.getQuery(),is(query));
        -        assertThat("[" + input + "] .fragment",httpUri.getFragment(),is(fragment));
        -        
        -        assertThat("[" + input + "] .toString",httpUri.toString(),is(input));
        +        assertThat("[" + input + "] .scheme", httpUri.getScheme(), is(scheme));
        +        assertThat("[" + input + "] .host", httpUri.getHost(), is(host));
        +        assertThat("[" + input + "] .port", httpUri.getPort(), is(port == null ? -1 : port));
        +        assertThat("[" + input + "] .path", httpUri.getPath(), is(path));
        +        assertThat("[" + input + "] .param", httpUri.getParam(), is(param));
        +        assertThat("[" + input + "] .query", httpUri.getQuery(), is(query));
        +        assertThat("[" + input + "] .fragment", httpUri.getFragment(), is(fragment));
        +
        +        assertThat("[" + input + "] .toString", httpUri.toString(), is(input));
             }
         
             @ParameterizedTest
        @@ -240,14 +239,14 @@ public class HttpURIParseTest
                 assumeTrue(javaUri != null, "Skipping, not a valid input URI");
         
                 HttpURI httpUri = new HttpURI(javaUri);
        -        
        -        assertThat("[" + input + "] .scheme",httpUri.getScheme(),is(javaUri.getScheme()));
        -        assertThat("[" + input + "] .host",httpUri.getHost(),is(javaUri.getHost()));
        -        assertThat("[" + input + "] .port",httpUri.getPort(),is(javaUri.getPort()));
        -        assertThat("[" + input + "] .path",httpUri.getPath(),is(javaUri.getRawPath()));
        +
        +        assertThat("[" + input + "] .scheme", httpUri.getScheme(), is(javaUri.getScheme()));
        +        assertThat("[" + input + "] .host", httpUri.getHost(), is(javaUri.getHost()));
        +        assertThat("[" + input + "] .port", httpUri.getPort(), is(javaUri.getPort()));
        +        assertThat("[" + input + "] .path", httpUri.getPath(), is(javaUri.getRawPath()));
                 // Not Relevant for java.net.URI -- assertThat("["+input+"] .param", httpUri.getParam(), is(param));
        -        assertThat("[" + input + "] .query",httpUri.getQuery(),is(javaUri.getRawQuery()));
        -        assertThat("[" + input + "] .fragment",httpUri.getFragment(),is(javaUri.getFragment()));
        -        assertThat("[" + input + "] .toString",httpUri.toString(),is(javaUri.toASCIIString()));
        +        assertThat("[" + input + "] .query", httpUri.getQuery(), is(javaUri.getRawQuery()));
        +        assertThat("[" + input + "] .fragment", httpUri.getFragment(), is(javaUri.getFragment()));
        +        assertThat("[" + input + "] .toString", httpUri.toString(), is(javaUri.toASCIIString()));
             }
        -}
        \ No newline at end of file
        +}
        diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURITest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURITest.java
        index b9f93871d4a..0a7910f7e25 100644
        --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURITest.java
        +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURITest.java
        @@ -1,6 +1,6 @@
         //
         //  ========================================================================
        -//  Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
        +//  Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
         //  ------------------------------------------------------------------------
         //  All rights reserved. This program and the accompanying materials
         //  are made available under the terms of the Eclipse Public License v1.0
        @@ -16,22 +16,21 @@
         //  ========================================================================
         //
         
        -
         package org.eclipse.jetty.http;
         
        -import static org.hamcrest.Matchers.is;
        -import static org.hamcrest.Matchers.nullValue;
        -import static org.junit.jupiter.api.Assertions.assertEquals;
        -import static org.hamcrest.MatcherAssert.assertThat;
        -import static org.junit.jupiter.api.Assertions.assertTrue;
        -import static org.junit.jupiter.api.Assertions.fail;
        -
         import java.net.URLEncoder;
         import java.nio.charset.StandardCharsets;
         
         import org.eclipse.jetty.util.MultiMap;
         import org.junit.jupiter.api.Test;
         
        +import static org.hamcrest.MatcherAssert.assertThat;
        +import static org.hamcrest.Matchers.is;
        +import static org.hamcrest.Matchers.nullValue;
        +import static org.junit.jupiter.api.Assertions.assertEquals;
        +import static org.junit.jupiter.api.Assertions.assertTrue;
        +import static org.junit.jupiter.api.Assertions.fail;
        +
         public class HttpURITest
         {
             @Test
        @@ -62,20 +61,20 @@ public class HttpURITest
                 HttpURI uri = new HttpURI();
         
                 uri.parse("*");
        -        assertThat(uri.getHost(),nullValue());
        -        assertThat(uri.getPath(),is("*"));
        -        
        +        assertThat(uri.getHost(), nullValue());
        +        assertThat(uri.getPath(), is("*"));
        +
                 uri.parse("/foo/bar");
        -        assertThat(uri.getHost(),nullValue());
        -        assertThat(uri.getPath(),is("/foo/bar"));
        -        
        +        assertThat(uri.getHost(), nullValue());
        +        assertThat(uri.getPath(), is("/foo/bar"));
        +
                 uri.parse("//foo/bar");
        -        assertThat(uri.getHost(),is("foo"));
        -        assertThat(uri.getPath(),is("/bar"));
        -        
        +        assertThat(uri.getHost(), is("foo"));
        +        assertThat(uri.getPath(), is("/bar"));
        +
                 uri.parse("http://foo/bar");
        -        assertThat(uri.getHost(),is("foo"));
        -        assertThat(uri.getPath(),is("/bar"));
        +        assertThat(uri.getHost(), is("foo"));
        +        assertThat(uri.getPath(), is("/bar"));
             }
         
             @Test
        @@ -83,33 +82,33 @@ public class HttpURITest
             {
                 HttpURI uri = new HttpURI();
         
        -        uri.parseRequestTarget("GET","*");
        -        assertThat(uri.getHost(),nullValue());
        -        assertThat(uri.getPath(),is("*"));
        -        
        -        uri.parseRequestTarget("GET","/foo/bar");
        -        assertThat(uri.getHost(),nullValue());
        -        assertThat(uri.getPath(),is("/foo/bar"));
        -        
        -        uri.parseRequestTarget("GET","//foo/bar");
        -        assertThat(uri.getHost(),nullValue());
        -        assertThat(uri.getPath(),is("//foo/bar"));
        -        
        -        uri.parseRequestTarget("GET","http://foo/bar");
        -        assertThat(uri.getHost(),is("foo"));
        -        assertThat(uri.getPath(),is("/bar"));
        +        uri.parseRequestTarget("GET", "*");
        +        assertThat(uri.getHost(), nullValue());
        +        assertThat(uri.getPath(), is("*"));
        +
        +        uri.parseRequestTarget("GET", "/foo/bar");
        +        assertThat(uri.getHost(), nullValue());
        +        assertThat(uri.getPath(), is("/foo/bar"));
        +
        +        uri.parseRequestTarget("GET", "//foo/bar");
        +        assertThat(uri.getHost(), nullValue());
        +        assertThat(uri.getPath(), is("//foo/bar"));
        +
        +        uri.parseRequestTarget("GET", "http://foo/bar");
        +        assertThat(uri.getHost(), is("foo"));
        +        assertThat(uri.getPath(), is("/bar"));
             }
         
             @Test
             public void testExtB() throws Exception
             {
        -        for (String value: new String[]{"a","abcdABCD","\u00C0","\u697C","\uD869\uDED5","\uD840\uDC08"} )
        +        for (String value : new String[]{"a", "abcdABCD", "\u00C0", "\u697C", "\uD869\uDED5", "\uD840\uDC08"})
                 {
        -            HttpURI uri = new HttpURI("/path?value="+URLEncoder.encode(value,"UTF-8"));
        +            HttpURI uri = new HttpURI("/path?value=" + URLEncoder.encode(value, "UTF-8"));
         
                     MultiMap parameters = new MultiMap<>();
        -            uri.decodeQueryTo(parameters,StandardCharsets.UTF_8);
        -            assertEquals(value,parameters.getString("value"));
        +            uri.decodeQueryTo(parameters, StandardCharsets.UTF_8);
        +            assertEquals(value, parameters.getString("value"));
                 }
             }
         
        @@ -117,103 +116,102 @@ public class HttpURITest
             public void testAt() throws Exception
             {
                 HttpURI uri = new HttpURI("/@foo/bar");
        -        assertEquals("/@foo/bar",uri.getPath());
        +        assertEquals("/@foo/bar", uri.getPath());
             }
         
             @Test
             public void testParams() throws Exception
             {
                 HttpURI uri = new HttpURI("/foo/bar");
        -        assertEquals("/foo/bar",uri.getPath());
        -        assertEquals("/foo/bar",uri.getDecodedPath());
        -        assertEquals(null,uri.getParam());
        -        
        +        assertEquals("/foo/bar", uri.getPath());
        +        assertEquals("/foo/bar", uri.getDecodedPath());
        +        assertEquals(null, uri.getParam());
        +
                 uri = new HttpURI("/foo/bar;jsessionid=12345");
        -        assertEquals("/foo/bar;jsessionid=12345",uri.getPath());
        -        assertEquals("/foo/bar",uri.getDecodedPath());
        -        assertEquals("jsessionid=12345",uri.getParam());
        -        
        +        assertEquals("/foo/bar;jsessionid=12345", uri.getPath());
        +        assertEquals("/foo/bar", uri.getDecodedPath());
        +        assertEquals("jsessionid=12345", uri.getParam());
        +
                 uri = new HttpURI("/foo;abc=123/bar;jsessionid=12345");
        -        assertEquals("/foo;abc=123/bar;jsessionid=12345",uri.getPath());
        -        assertEquals("/foo/bar",uri.getDecodedPath());
        -        assertEquals("jsessionid=12345",uri.getParam());
        -        
        +        assertEquals("/foo;abc=123/bar;jsessionid=12345", uri.getPath());
        +        assertEquals("/foo/bar", uri.getDecodedPath());
        +        assertEquals("jsessionid=12345", uri.getParam());
        +
                 uri = new HttpURI("/foo;abc=123/bar;jsessionid=12345?name=value");
        -        assertEquals("/foo;abc=123/bar;jsessionid=12345",uri.getPath());
        -        assertEquals("/foo/bar",uri.getDecodedPath());
        -        assertEquals("jsessionid=12345",uri.getParam());
        -        
        +        assertEquals("/foo;abc=123/bar;jsessionid=12345", uri.getPath());
        +        assertEquals("/foo/bar", uri.getDecodedPath());
        +        assertEquals("jsessionid=12345", uri.getParam());
        +
                 uri = new HttpURI("/foo;abc=123/bar;jsessionid=12345#target");
        -        assertEquals("/foo;abc=123/bar;jsessionid=12345",uri.getPath());
        -        assertEquals("/foo/bar",uri.getDecodedPath());
        -        assertEquals("jsessionid=12345",uri.getParam());
        +        assertEquals("/foo;abc=123/bar;jsessionid=12345", uri.getPath());
        +        assertEquals("/foo/bar", uri.getDecodedPath());
        +        assertEquals("jsessionid=12345", uri.getParam());
             }
        -    
        +
             @Test
             public void testMutableURI()
             {
                 HttpURI uri = new HttpURI("/foo/bar");
        -        assertEquals("/foo/bar",uri.toString());
        -        assertEquals("/foo/bar",uri.getPath());
        -        assertEquals("/foo/bar",uri.getDecodedPath());
        +        assertEquals("/foo/bar", uri.toString());
        +        assertEquals("/foo/bar", uri.getPath());
        +        assertEquals("/foo/bar", uri.getDecodedPath());
         
                 uri.setScheme("http");
        -        assertEquals("http:/foo/bar",uri.toString());
        -        assertEquals("/foo/bar",uri.getPath());
        -        assertEquals("/foo/bar",uri.getDecodedPath());
        +        assertEquals("http:/foo/bar", uri.toString());
        +        assertEquals("/foo/bar", uri.getPath());
        +        assertEquals("/foo/bar", uri.getDecodedPath());
         
        -        uri.setAuthority("host",0);
        -        assertEquals("http://host/foo/bar",uri.toString());
        -        assertEquals("/foo/bar",uri.getPath());
        -        assertEquals("/foo/bar",uri.getDecodedPath());
        +        uri.setAuthority("host", 0);
        +        assertEquals("http://host/foo/bar", uri.toString());
        +        assertEquals("/foo/bar", uri.getPath());
        +        assertEquals("/foo/bar", uri.getDecodedPath());
        +
        +        uri.setAuthority("host", 8888);
        +        assertEquals("http://host:8888/foo/bar", uri.toString());
        +        assertEquals("/foo/bar", uri.getPath());
        +        assertEquals("/foo/bar", uri.getDecodedPath());
         
        -        uri.setAuthority("host",8888);
        -        assertEquals("http://host:8888/foo/bar",uri.toString());
        -        assertEquals("/foo/bar",uri.getPath());
        -        assertEquals("/foo/bar",uri.getDecodedPath());
        -        
                 uri.setPathQuery("/f%30%30;p0/bar;p1;p2");
        -        assertEquals("http://host:8888/f%30%30;p0/bar;p1;p2",uri.toString());
        -        assertEquals("/f%30%30;p0/bar;p1;p2",uri.getPath());
        -        assertEquals("/f00/bar",uri.getDecodedPath());
        -        assertEquals("p2",uri.getParam());
        -        assertEquals(null,uri.getQuery());
        -        
        +        assertEquals("http://host:8888/f%30%30;p0/bar;p1;p2", uri.toString());
        +        assertEquals("/f%30%30;p0/bar;p1;p2", uri.getPath());
        +        assertEquals("/f00/bar", uri.getDecodedPath());
        +        assertEquals("p2", uri.getParam());
        +        assertEquals(null, uri.getQuery());
        +
                 uri.setPathQuery("/f%30%30;p0/bar;p1;p2?name=value");
        -        assertEquals("http://host:8888/f%30%30;p0/bar;p1;p2?name=value",uri.toString());
        -        assertEquals("/f%30%30;p0/bar;p1;p2",uri.getPath());
        -        assertEquals("/f00/bar",uri.getDecodedPath());
        -        assertEquals("p2",uri.getParam());
        -        assertEquals("name=value",uri.getQuery());
        -        
        +        assertEquals("http://host:8888/f%30%30;p0/bar;p1;p2?name=value", uri.toString());
        +        assertEquals("/f%30%30;p0/bar;p1;p2", uri.getPath());
        +        assertEquals("/f00/bar", uri.getDecodedPath());
        +        assertEquals("p2", uri.getParam());
        +        assertEquals("name=value", uri.getQuery());
        +
                 uri.setQuery("other=123456");
        -        assertEquals("http://host:8888/f%30%30;p0/bar;p1;p2?other=123456",uri.toString());
        -        assertEquals("/f%30%30;p0/bar;p1;p2",uri.getPath());
        -        assertEquals("/f00/bar",uri.getDecodedPath());
        -        assertEquals("p2",uri.getParam());
        -        assertEquals("other=123456",uri.getQuery());
        +        assertEquals("http://host:8888/f%30%30;p0/bar;p1;p2?other=123456", uri.toString());
        +        assertEquals("/f%30%30;p0/bar;p1;p2", uri.getPath());
        +        assertEquals("/f00/bar", uri.getDecodedPath());
        +        assertEquals("p2", uri.getParam());
        +        assertEquals("other=123456", uri.getQuery());
             }
         
             @Test
             public void testSchemeAndOrAuthority() throws Exception
             {
                 HttpURI uri = new HttpURI("/path/info");
        -        assertEquals("/path/info",uri.toString());
        -        
        -        uri.setAuthority("host",0);
        -        assertEquals("//host/path/info",uri.toString());
        -        
        -        uri.setAuthority("host",8888);
        -        assertEquals("//host:8888/path/info",uri.toString());
        -        
        +        assertEquals("/path/info", uri.toString());
        +
        +        uri.setAuthority("host", 0);
        +        assertEquals("//host/path/info", uri.toString());
        +
        +        uri.setAuthority("host", 8888);
        +        assertEquals("//host:8888/path/info", uri.toString());
        +
                 uri.setScheme("http");
        -        assertEquals("http://host:8888/path/info",uri.toString());
        -        
        -        uri.setAuthority(null,0);
        -        assertEquals("http:/path/info",uri.toString());
        -        
        +        assertEquals("http://host:8888/path/info", uri.toString());
        +
        +        uri.setAuthority(null, 0);
        +        assertEquals("http:/path/info", uri.toString());
             }
        -    
        +
             @Test
             public void testBasicAuthCredentials() throws Exception
             {
        diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MimeTypesTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MimeTypesTest.java
        index a27ff28f876..89720e31a6a 100644
        --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MimeTypesTest.java
        +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MimeTypesTest.java
        @@ -1,6 +1,6 @@
         //
         //  ========================================================================
        -//  Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
        +//  Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
         //  ------------------------------------------------------------------------
         //  All rights reserved. This program and the accompanying materials
         //  are made available under the terms of the Eclipse Public License v1.0
        @@ -18,49 +18,49 @@
         
         package org.eclipse.jetty.http;
         
        -import static org.hamcrest.CoreMatchers.is;
        +import org.junit.jupiter.api.Test;
        +
        +import static org.hamcrest.MatcherAssert.assertThat;
        +import static org.hamcrest.Matchers.is;
         import static org.junit.jupiter.api.Assertions.assertEquals;
         import static org.junit.jupiter.api.Assertions.assertNotNull;
         import static org.junit.jupiter.api.Assertions.assertNull;
        -import static org.hamcrest.MatcherAssert.assertThat;
        -
        -import org.junit.jupiter.api.Test;
         
         public class MimeTypesTest
         {
             @Test
             public void testGetMimeByExtension_Gzip()
             {
        -        assertMimeTypeByExtension("application/gzip","test.gz");
        +        assertMimeTypeByExtension("application/gzip", "test.gz");
             }
         
             @Test
             public void testGetMimeByExtension_Png()
             {
        -        assertMimeTypeByExtension("image/png","test.png");
        -        assertMimeTypeByExtension("image/png","TEST.PNG");
        -        assertMimeTypeByExtension("image/png","Test.Png");
        +        assertMimeTypeByExtension("image/png", "test.png");
        +        assertMimeTypeByExtension("image/png", "TEST.PNG");
        +        assertMimeTypeByExtension("image/png", "Test.Png");
             }
         
             @Test
             public void testGetMimeByExtension_Png_MultiDot()
             {
        -        assertMimeTypeByExtension("image/png","org.eclipse.jetty.Logo.png");
        +        assertMimeTypeByExtension("image/png", "org.eclipse.jetty.Logo.png");
             }
         
             @Test
             public void testGetMimeByExtension_Png_DeepPath()
             {
        -        assertMimeTypeByExtension("image/png","/org/eclipse/jetty/Logo.png");
        +        assertMimeTypeByExtension("image/png", "/org/eclipse/jetty/Logo.png");
             }
         
             @Test
             public void testGetMimeByExtension_Text()
             {
        -        assertMimeTypeByExtension("text/plain","test.txt");
        -        assertMimeTypeByExtension("text/plain","TEST.TXT");
        +        assertMimeTypeByExtension("text/plain", "test.txt");
        +        assertMimeTypeByExtension("text/plain", "TEST.TXT");
             }
        -    
        +
             @Test
             public void testGetMimeByExtension_NoExtension()
             {
        @@ -74,14 +74,14 @@ public class MimeTypesTest
                 MimeTypes mimetypes = new MimeTypes();
                 String contentType = mimetypes.getMimeByExtension(filename);
                 String prefix = "MimeTypes.getMimeByExtension(" + filename + ")";
        -        assertNotNull(contentType,prefix);
        -        assertEquals(expectedMimeType,contentType,prefix);
        +        assertNotNull(contentType, prefix);
        +        assertEquals(expectedMimeType, contentType, prefix);
             }
        -    
        +
             private void assertCharsetFromContentType(String contentType, String expectedCharset)
             {
                 assertThat("getCharsetFromContentType(\"" + contentType + "\")",
        -                MimeTypes.getCharsetFromContentType(contentType), is(expectedCharset));
        +            MimeTypes.getCharsetFromContentType(contentType), is(expectedCharset));
             }
         
             @Test
        @@ -110,19 +110,19 @@ public class MimeTypesTest
             @Test
             public void testContentTypeWithoutCharset()
             {
        -        assertEquals("foo/bar;some=else",MimeTypes.getContentTypeWithoutCharset("foo/bar;charset=abc;some=else"));
        -        assertEquals("foo/bar",MimeTypes.getContentTypeWithoutCharset("foo/bar;charset=abc"));
        -        assertEquals("foo/bar",MimeTypes.getContentTypeWithoutCharset("foo/bar ; charset = abc"));
        -        assertEquals("foo/bar;some=else",MimeTypes.getContentTypeWithoutCharset("foo/bar ; charset = abc ; some=else"));
        -        assertEquals("foo/bar;other=param;some=else",MimeTypes.getContentTypeWithoutCharset("foo/bar;other=param;charset=abc;some=else"));
        -        assertEquals("foo/bar;other=param",MimeTypes.getContentTypeWithoutCharset("foo/bar;other=param;charset=abc"));
        -        assertEquals("foo/bar ; other = param",MimeTypes.getContentTypeWithoutCharset("foo/bar ; other = param ; charset = abc"));
        -        assertEquals("foo/bar ; other = param;some=else",MimeTypes.getContentTypeWithoutCharset("foo/bar ; other = param ; charset = abc ; some=else"));
        -        assertEquals("foo/bar ; other = param",MimeTypes.getContentTypeWithoutCharset("foo/bar ; other = param ; charset = abc"));
        -        assertEquals("foo/bar ; other = param;some=else",MimeTypes.getContentTypeWithoutCharset("foo/bar ; other = param ; charset = \"abc\" ; some=else"));
        -        assertEquals("foo/bar",MimeTypes.getContentTypeWithoutCharset("foo/bar"));
        -        assertEquals("foo/bar",MimeTypes.getContentTypeWithoutCharset("foo/bar;charset=uTf8"));
        -        assertEquals("foo/bar;other=\"charset=abc\"",MimeTypes.getContentTypeWithoutCharset("foo/bar;other=\"charset=abc\";charset=uTf8"));
        -        assertEquals("text/html",MimeTypes.getContentTypeWithoutCharset("text/html;charset=utf-8"));
        +        assertEquals("foo/bar;some=else", MimeTypes.getContentTypeWithoutCharset("foo/bar;charset=abc;some=else"));
        +        assertEquals("foo/bar", MimeTypes.getContentTypeWithoutCharset("foo/bar;charset=abc"));
        +        assertEquals("foo/bar", MimeTypes.getContentTypeWithoutCharset("foo/bar ; charset = abc"));
        +        assertEquals("foo/bar;some=else", MimeTypes.getContentTypeWithoutCharset("foo/bar ; charset = abc ; some=else"));
        +        assertEquals("foo/bar;other=param;some=else", MimeTypes.getContentTypeWithoutCharset("foo/bar;other=param;charset=abc;some=else"));
        +        assertEquals("foo/bar;other=param", MimeTypes.getContentTypeWithoutCharset("foo/bar;other=param;charset=abc"));
        +        assertEquals("foo/bar ; other = param", MimeTypes.getContentTypeWithoutCharset("foo/bar ; other = param ; charset = abc"));
        +        assertEquals("foo/bar ; other = param;some=else", MimeTypes.getContentTypeWithoutCharset("foo/bar ; other = param ; charset = abc ; some=else"));
        +        assertEquals("foo/bar ; other = param", MimeTypes.getContentTypeWithoutCharset("foo/bar ; other = param ; charset = abc"));
        +        assertEquals("foo/bar ; other = param;some=else", MimeTypes.getContentTypeWithoutCharset("foo/bar ; other = param ; charset = \"abc\" ; some=else"));
        +        assertEquals("foo/bar", MimeTypes.getContentTypeWithoutCharset("foo/bar"));
        +        assertEquals("foo/bar", MimeTypes.getContentTypeWithoutCharset("foo/bar;charset=uTf8"));
        +        assertEquals("foo/bar;other=\"charset=abc\"", MimeTypes.getContentTypeWithoutCharset("foo/bar;other=\"charset=abc\";charset=uTf8"));
        +        assertEquals("text/html", MimeTypes.getContentTypeWithoutCharset("text/html;charset=utf-8"));
             }
         }
        diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartCaptureTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartCaptureTest.java
        index 8715794d88e..15006461dca 100644
        --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartCaptureTest.java
        +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartCaptureTest.java
        @@ -1,6 +1,6 @@
         //
         //  ========================================================================
        -//  Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
        +//  Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
         //  ------------------------------------------------------------------------
         //  All rights reserved. This program and the accompanying materials
         //  are made available under the terms of the Eclipse Public License v1.0
        @@ -18,12 +18,6 @@
         
         package org.eclipse.jetty.http;
         
        -import static java.nio.charset.StandardCharsets.UTF_8;
        -import static org.hamcrest.MatcherAssert.assertThat;
        -import static org.hamcrest.Matchers.containsString;
        -import static org.hamcrest.Matchers.is;
        -import static org.hamcrest.Matchers.notNullValue;
        -
         import java.io.BufferedReader;
         import java.io.IOException;
         import java.io.InputStream;
        @@ -39,7 +33,6 @@ import java.util.Locale;
         import java.util.Objects;
         import java.util.function.Function;
         import java.util.stream.Stream;
        -
         import javax.servlet.MultipartConfigElement;
         import javax.servlet.http.Part;
         
        @@ -56,6 +49,12 @@ import org.junit.jupiter.params.ParameterizedTest;
         import org.junit.jupiter.params.provider.Arguments;
         import org.junit.jupiter.params.provider.MethodSource;
         
        +import static java.nio.charset.StandardCharsets.UTF_8;
        +import static org.hamcrest.MatcherAssert.assertThat;
        +import static org.hamcrest.Matchers.containsString;
        +import static org.hamcrest.Matchers.is;
        +import static org.hamcrest.Matchers.notNullValue;
        +
         @ExtendWith(WorkDirExtension.class)
         public class MultiPartCaptureTest
         {
        @@ -166,10 +165,10 @@ public class MultiPartCaptureTest
                 MultipartConfigElement config = newMultipartConfigElement(outputDir);
                 try (InputStream in = Files.newInputStream(multipartRawFile))
                 {
        -            org.eclipse.jetty.util.MultiPartInputStreamParser parser = new org.eclipse.jetty.util.MultiPartInputStreamParser(in,multipartExpectations.contentType,config,outputDir.toFile());
        +            org.eclipse.jetty.util.MultiPartInputStreamParser parser = new org.eclipse.jetty.util.MultiPartInputStreamParser(in, multipartExpectations.contentType, config, outputDir.toFile());
         
        -            multipartExpectations.checkParts(parser.getParts(),s->
        -            { 
        +            multipartExpectations.checkParts(parser.getParts(), s ->
        +            {
                         try
                         {
                             return parser.getPart(s);
        @@ -177,7 +176,7 @@ public class MultiPartCaptureTest
                         catch (Exception e)
                         {
                             throw new RuntimeException(e);
        -                } 
        +                }
                     });
                 }
             }
        @@ -196,8 +195,8 @@ public class MultiPartCaptureTest
                 {
                     MultiPartFormInputStream parser = new MultiPartFormInputStream(in, multipartExpectations.contentType, config, outputDir.toFile());
         
        -            multipartExpectations.checkParts(parser.getParts(),s->
        -            { 
        +            multipartExpectations.checkParts(parser.getParts(), s ->
        +            {
                         try
                         {
                             return parser.getPart(s);
        @@ -205,11 +204,11 @@ public class MultiPartCaptureTest
                         catch (Exception e)
                         {
                             throw new RuntimeException(e);
        -                } 
        +                }
                     });
                 }
             }
        -    
        +
             private MultipartConfigElement newMultipartConfigElement(Path path)
             {
                 return new MultipartConfigElement(path.toString(), MAX_FILE_SIZE, MAX_REQUEST_SIZE, FILE_SIZE_THRESHOLD);
        @@ -246,11 +245,11 @@ public class MultiPartCaptureTest
                                 continue;
                             }
         
        -                    String split[] = line.split("\\|");
        +                    String[] split = line.split("\\|");
                             switch (split[0])
                             {
                                 case "Request-Header":
        -                            if(split[1].equalsIgnoreCase("Content-Type"))
        +                            if (split[1].equalsIgnoreCase("Content-Type"))
                                     {
                                         parsedContentType = split[2];
                                     }
        @@ -306,12 +305,11 @@ public class MultiPartCaptureTest
         
                     String defaultCharset = UTF_8.toString();
                     Part charSetPart = getPart.apply("_charset_");
        -            if(charSetPart != null)
        +            if (charSetPart != null)
                     {
                         defaultCharset = IO.toString(charSetPart.getInputStream());
                     }
         
        -
                     // Evaluate expected Contents
                     for (NameValue expected : partContainsContents)
                     {
        @@ -352,16 +350,16 @@ public class MultiPartCaptureTest
         
                 private String getCharsetFromContentType(String contentType, String defaultCharset)
                 {
        -            if(StringUtil.isBlank(contentType))
        +            if (StringUtil.isBlank(contentType))
                     {
                         return defaultCharset;
                     }
         
                     QuotedStringTokenizer tok = new QuotedStringTokenizer(contentType, ";", false, false);
        -            while(tok.hasMoreTokens())
        +            while (tok.hasMoreTokens())
                     {
                         String str = tok.nextToken().trim();
        -                if(str.startsWith("charset="))
        +                if (str.startsWith("charset="))
                         {
                             return str.substring("charset=".length());
                         }
        diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartFormInputStreamTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartFormInputStreamTest.java
        index 87ca092a65f..a8c1d986119 100644
        --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartFormInputStreamTest.java
        +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartFormInputStreamTest.java
        @@ -1,6 +1,6 @@
         //
         //  ========================================================================
        -//  Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
        +//  Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
         //  ------------------------------------------------------------------------
         //  All rights reserved. This program and the accompanying materials
         //  are made available under the terms of the Eclipse Public License v1.0
        @@ -18,6 +18,24 @@
         
         package org.eclipse.jetty.http;
         
        +import java.io.ByteArrayInputStream;
        +import java.io.ByteArrayOutputStream;
        +import java.io.File;
        +import java.io.IOException;
        +import java.io.InputStream;
        +import java.util.Base64;
        +import java.util.Collection;
        +import java.util.concurrent.TimeUnit;
        +import javax.servlet.MultipartConfigElement;
        +import javax.servlet.ReadListener;
        +import javax.servlet.ServletInputStream;
        +import javax.servlet.http.Part;
        +
        +import org.eclipse.jetty.http.MultiPartFormInputStream.MultiPart;
        +import org.eclipse.jetty.util.IO;
        +import org.junit.jupiter.api.Test;
        +
        +import static java.nio.charset.StandardCharsets.ISO_8859_1;
         import static org.hamcrest.MatcherAssert.assertThat;
         import static org.hamcrest.Matchers.containsString;
         import static org.hamcrest.Matchers.is;
        @@ -33,24 +51,6 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
         import static org.junit.jupiter.api.Assertions.assertTrue;
         import static org.junit.jupiter.api.Assertions.fail;
         
        -import java.io.ByteArrayInputStream;
        -import java.io.ByteArrayOutputStream;
        -import java.io.File;
        -import java.io.IOException;
        -import java.io.InputStream;
        -import java.util.Collection;
        -import java.util.concurrent.TimeUnit;
        -
        -import javax.servlet.MultipartConfigElement;
        -import javax.servlet.ReadListener;
        -import javax.servlet.ServletInputStream;
        -import javax.servlet.http.Part;
        -
        -import org.eclipse.jetty.http.MultiPartFormInputStream.MultiPart;
        -import org.eclipse.jetty.util.B64Code;
        -import org.eclipse.jetty.util.IO;
        -import org.junit.jupiter.api.Test;
        -
         /**
          * MultiPartInputStreamTest
          */
        @@ -62,124 +62,121 @@ public class MultiPartFormInputStreamTest
             // TODO: move to testing dir concept
             protected String _dirname = System.getProperty("java.io.tmpdir") + File.separator + "myfiles-" + TimeUnit.NANOSECONDS.toMillis(System.nanoTime());
             protected File _tmpDir = new File(_dirname);
        -    
        +
             public MultiPartFormInputStreamTest()
             {
                 _tmpDir.deleteOnExit();
             }
        -    
        +
             @Test
             public void testBadMultiPartRequest()
        -            throws Exception
        +        throws Exception
             {
                 String boundary = "X0Y0";
                 String str = "--" + boundary + "\r\n" +
        -                "Content-Disposition: form-data; name=\"fileup\"; filename=\"test.upload\"\r\n" +
        -                "Content-Type: application/octet-stream\r\n\r\n" +
        -                "How now brown cow." +
        -                "\r\n--" + boundary + "-\r\n"
        -                + "Content-Disposition: form-data; name=\"fileup\"; filename=\"test.upload\"\r\n"
        -                + "\r\n";
        +            "Content-Disposition: form-data; name=\"fileup\"; filename=\"test.upload\"\r\n" +
        +            "Content-Type: application/octet-stream\r\n\r\n" +
        +            "How now brown cow." +
        +            "\r\n--" + boundary + "-\r\n" +
        +            "Content-Disposition: form-data; name=\"fileup\"; filename=\"test.upload\"\r\n" +
        +            "\r\n";
         
                 MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
                 MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(str.getBytes()),
        -                "multipart/form-data, boundary=" + boundary,
        -                config,
        -                _tmpDir);
        +            "multipart/form-data, boundary=" + boundary,
        +            config,
        +            _tmpDir);
                 mpis.setDeleteOnExit(true);
         
                 IOException x = assertThrows(IOException.class,
        -                ()-> mpis.getParts(),
        -                "Incomplete Multipart");
        +            () -> mpis.getParts(),
        +            "Incomplete Multipart");
                 assertThat(x.getMessage(), startsWith("Incomplete"));
             }
         
        -
             @Test
             public void testFinalBoundaryOnly()
        -            throws Exception
        +        throws Exception
             {
                 String delimiter = "\r\n";
                 final String boundary = "MockMultiPartTestBoundary";
         
        -
                 // Malformed multipart request body containing only an arbitrary string of text, followed by the final boundary marker, delimited by empty lines.
                 String str =
        +            delimiter +
        +                "Hello world" +
        +                delimiter +        // Two delimiter markers, which make an empty line.
                         delimiter +
        -                        "Hello world" +
        -                        delimiter +        // Two delimiter markers, which make an empty line.
        -                        delimiter +
        -                        "--" + boundary + "--" + delimiter;
        +                "--" + boundary + "--" + delimiter;
         
                 MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
                 MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(str.getBytes()),
        -                "multipart/form-data, boundary=" + boundary,
        -                config,
        -                _tmpDir);
        +            "multipart/form-data, boundary=" + boundary,
        +            config,
        +            _tmpDir);
                 mpis.setDeleteOnExit(true);
                 assertTrue(mpis.getParts().isEmpty());
             }
        -    
        -    
        +
             @Test
             public void testEmpty()
        -            throws Exception
        +        throws Exception
             {
                 String delimiter = "\r\n";
                 final String boundary = "MockMultiPartTestBoundary";
         
                 String str =
        -                delimiter +
        -                        "--" + boundary + "--" + delimiter;
        +            delimiter +
        +                "--" + boundary + "--" + delimiter;
         
                 MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
                 MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(str.getBytes()),
        -                "multipart/form-data, boundary=" + boundary,
        -                config,
        -                _tmpDir);
        +            "multipart/form-data, boundary=" + boundary,
        +            config,
        +            _tmpDir);
                 mpis.setDeleteOnExit(true);
                 assertTrue(mpis.getParts().isEmpty());
             }
         
             @Test
             public void testNoBoundaryRequest()
        -            throws Exception
        +        throws Exception
             {
                 String str = "--\r\n" +
        -                "Content-Disposition: form-data; name=\"fileName\"\r\n" +
        -                "Content-Type: text/plain; charset=US-ASCII\r\n" +
        -                "Content-Transfer-Encoding: 8bit\r\n" +
        -                "\r\n" +
        -                "abc\r\n" +
        -                "--\r\n" +
        -                "Content-Disposition: form-data; name=\"desc\"\r\n" +
        -                "Content-Type: text/plain; charset=US-ASCII\r\n" +
        -                "Content-Transfer-Encoding: 8bit\r\n" +
        -                "\r\n" +
        -                "123\r\n" +
        -                "--\r\n" +
        -                "Content-Disposition: form-data; name=\"title\"\r\n" +
        -                "Content-Type: text/plain; charset=US-ASCII\r\n" +
        -                "Content-Transfer-Encoding: 8bit\r\n" +
        -                "\r\n" +
        -                "ttt\r\n" +
        -                "--\r\n" +
        -                "Content-Disposition: form-data; name=\"datafile5239138112980980385.txt\"; filename=\"datafile5239138112980980385.txt\"\r\n" +
        -                "Content-Type: application/octet-stream; charset=ISO-8859-1\r\n" +
        -                "Content-Transfer-Encoding: binary\r\n" +
        -                "\r\n" +
        -                "000\r\n" +
        -                "----\r\n";
        -        
        +            "Content-Disposition: form-data; name=\"fileName\"\r\n" +
        +            "Content-Type: text/plain; charset=US-ASCII\r\n" +
        +            "Content-Transfer-Encoding: 8bit\r\n" +
        +            "\r\n" +
        +            "abc\r\n" +
        +            "--\r\n" +
        +            "Content-Disposition: form-data; name=\"desc\"\r\n" +
        +            "Content-Type: text/plain; charset=US-ASCII\r\n" +
        +            "Content-Transfer-Encoding: 8bit\r\n" +
        +            "\r\n" +
        +            "123\r\n" +
        +            "--\r\n" +
        +            "Content-Disposition: form-data; name=\"title\"\r\n" +
        +            "Content-Type: text/plain; charset=US-ASCII\r\n" +
        +            "Content-Transfer-Encoding: 8bit\r\n" +
        +            "\r\n" +
        +            "ttt\r\n" +
        +            "--\r\n" +
        +            "Content-Disposition: form-data; name=\"datafile5239138112980980385.txt\"; filename=\"datafile5239138112980980385.txt\"\r\n" +
        +            "Content-Type: application/octet-stream; charset=ISO-8859-1\r\n" +
        +            "Content-Transfer-Encoding: binary\r\n" +
        +            "\r\n" +
        +            "000\r\n" +
        +            "----\r\n";
        +
                 MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
                 MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(str.getBytes()),
        -                "multipart/form-data",
        -                config,
        -                _tmpDir);
        +            "multipart/form-data",
        +            config,
        +            _tmpDir);
                 mpis.setDeleteOnExit(true);
                 Collection parts = mpis.getParts();
                 assertThat(parts.size(), is(4));
        -        
        +
                 ByteArrayOutputStream baos = new ByteArrayOutputStream();
                 Part fileName = mpis.getPart("fileName");
                 assertThat(fileName, notNullValue());
        @@ -193,7 +190,7 @@ public class MultiPartFormInputStreamTest
                 assertThat(desc.getSize(), is(3L));
                 IO.copy(desc.getInputStream(), baos);
                 assertThat(baos.toString("US-ASCII"), is("123"));
        -        
        +
                 baos = new ByteArrayOutputStream();
                 Part title = mpis.getPart("title");
                 assertThat(title, notNullValue());
        @@ -204,37 +201,37 @@ public class MultiPartFormInputStreamTest
         
             @Test
             public void testNonMultiPartRequest()
        -            throws Exception
        +        throws Exception
             {
                 MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
                 MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(_multi.getBytes()),
        -                "Content-type: text/plain",
        -                config,
        -                _tmpDir);
        +            "Content-type: text/plain",
        +            config,
        +            _tmpDir);
                 mpis.setDeleteOnExit(true);
                 assertTrue(mpis.getParts().isEmpty());
             }
         
             @Test
             public void testNoBody()
        +        throws Exception
             {
                 String body = "";
         
                 MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
                 MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(body.getBytes()),
        -                _contentType,
        -                config,
        -                _tmpDir);
        +            _contentType,
        +            config,
        +            _tmpDir);
                 mpis.setDeleteOnExit(true);
         
        -        IOException x = assertThrows(IOException.class, ()-> mpis.getParts());
        +        IOException x = assertThrows(IOException.class, () -> mpis.getParts());
                 assertThat(x.getMessage(), containsString("Missing initial multi part boundary"));
             }
        -    
        -    
        +
             @Test
             public void testBodyAlreadyConsumed()
        -            throws Exception
        +        throws Exception
             {
                 ServletInputStream is = new ServletInputStream()
                 {
        @@ -261,79 +258,78 @@ public class MultiPartFormInputStreamTest
                     {
                         return 0;
                     }
        -            
                 };
        -        
        +
                 MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
                 MultiPartFormInputStream mpis = new MultiPartFormInputStream(is,
        -                _contentType,
        -                config,
        -                _tmpDir);
        +            _contentType,
        +            config,
        +            _tmpDir);
                 mpis.setDeleteOnExit(true);
                 Collection parts = mpis.getParts();
                 assertEquals(0, parts.size());
             }
        -    
         
             @Test
             public void testWhitespaceBodyWithCRLF()
        +        throws Exception
             {
                 String whitespace = "              \n\n\n\r\n\r\n\r\n\r\n";
         
                 MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
                 MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(whitespace.getBytes()),
        -                _contentType,
        -                config,
        -                _tmpDir);
        +            _contentType,
        +            config,
        +            _tmpDir);
                 mpis.setDeleteOnExit(true);
        -        IOException x = assertThrows(IOException.class, ()-> mpis.getParts());
        +        IOException x = assertThrows(IOException.class, () -> mpis.getParts());
                 assertThat(x.getMessage(), containsString("Missing initial multi part boundary"));
             }
         
             @Test
             public void testWhitespaceBody()
        +        throws Exception
             {
                 String whitespace = " ";
         
                 MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
                 MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(whitespace.getBytes()),
        -                _contentType,
        -                config,
        -                _tmpDir);
        +            _contentType,
        +            config,
        +            _tmpDir);
                 mpis.setDeleteOnExit(true);
        -        IOException x = assertThrows(IOException.class, ()-> mpis.getParts());
        +        IOException x = assertThrows(IOException.class, () -> mpis.getParts());
                 assertThat(x.getMessage(), containsString("Missing initial"));
             }
         
             @Test
             public void testLeadingWhitespaceBodyWithCRLF()
        -            throws Exception
        +        throws Exception
             {
                 String body = "              \n\n\n\r\n\r\n\r\n\r\n" +
        -                "--AaB03x\r\n" +
        -                "content-disposition: form-data; name=\"field1\"\r\n" +
        -                "\r\n" +
        -                "Joe Blow\r\n" +
        -                "--AaB03x\r\n" +
        -                "content-disposition: form-data; name=\"stuff\"; filename=\"" + "foo.txt" + "\"\r\n" +
        -                "Content-Type: text/plain\r\n" +
        -                "\r\n" + "aaaa" +
        -                "bbbbb" + "\r\n" +
        -                "--AaB03x--\r\n";
        -
        +            "--AaB03x\r\n" +
        +            "content-disposition: form-data; name=\"field1\"\r\n" +
        +            "\r\n" +
        +            "Joe Blow\r\n" +
        +            "--AaB03x\r\n" +
        +            "content-disposition: form-data; name=\"stuff\"; filename=\"" + "foo.txt" + "\"\r\n" +
        +            "Content-Type: text/plain\r\n" +
        +            "\r\n" + "aaaa" +
        +            "bbbbb" + "\r\n" +
        +            "--AaB03x--\r\n";
         
                 MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
                 MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(body.getBytes()),
        -                _contentType,
        -                config,
        -                _tmpDir);
        +            _contentType,
        +            config,
        +            _tmpDir);
                 mpis.setDeleteOnExit(true);
         
                 Collection parts = mpis.getParts();
                 assertThat(parts, notNullValue());
                 assertThat(parts.size(), is(2));
         
        -        try(ByteArrayOutputStream baos = new ByteArrayOutputStream())
        +        try (ByteArrayOutputStream baos = new ByteArrayOutputStream())
                 {
                     Part field1 = mpis.getPart("field1");
                     assertThat(field1, notNullValue());
        @@ -341,7 +337,7 @@ public class MultiPartFormInputStreamTest
                     assertThat(baos.toString("US-ASCII"), is("Joe Blow"));
                 }
         
        -        try(ByteArrayOutputStream baos = new ByteArrayOutputStream())
        +        try (ByteArrayOutputStream baos = new ByteArrayOutputStream())
                 {
                     Part stuff = mpis.getPart("stuff");
                     assertThat(stuff, notNullValue());
        @@ -349,28 +345,27 @@ public class MultiPartFormInputStreamTest
                     assertThat(baos.toString("US-ASCII"), containsString("aaaa"));
                 }
             }
        -    
         
             @Test
             public void testLeadingWhitespaceBodyWithoutCRLF() throws Exception
             {
        -        String body = "            "+
        -                "--AaB03x\r\n"+
        -                "content-disposition: form-data; name=\"field1\"\r\n"+
        -                "\r\n"+
        -                "Joe Blow\r\n"+
        -                "--AaB03x\r\n"+
        -                "content-disposition: form-data; name=\"stuff\"; filename=\"" + "foo.txt" + "\"\r\n"+
        -                "Content-Type: text/plain\r\n"+
        -                "\r\n"+"aaaa"+
        -                "bbbbb"+"\r\n" +
        -                "--AaB03x--\r\n";
        +        String body = "            " +
        +            "--AaB03x\r\n" +
        +            "content-disposition: form-data; name=\"field1\"\r\n" +
        +            "\r\n" +
        +            "Joe Blow\r\n" +
        +            "--AaB03x\r\n" +
        +            "content-disposition: form-data; name=\"stuff\"; filename=\"" + "foo.txt" + "\"\r\n" +
        +            "Content-Type: text/plain\r\n" +
        +            "\r\n" + "aaaa" +
        +            "bbbbb" + "\r\n" +
        +            "--AaB03x--\r\n";
         
                 MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
                 MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(body.getBytes()),
        -                _contentType,
        -                config,
        -                _tmpDir);
        +            _contentType,
        +            config,
        +            _tmpDir);
                 mpis.setDeleteOnExit(true);
         
                 Collection parts = mpis.getParts();
        @@ -386,86 +381,89 @@ public class MultiPartFormInputStreamTest
         
             @Test
             public void testNoLimits()
        -            throws Exception
        +        throws Exception
             {
                 MultipartConfigElement config = new MultipartConfigElement(_dirname);
                 MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(_multi.getBytes()),
        -                _contentType,
        -                config,
        -                _tmpDir);
        +            _contentType,
        +            config,
        +            _tmpDir);
                 mpis.setDeleteOnExit(true);
                 Collection parts = mpis.getParts();
                 assertFalse(parts.isEmpty());
             }
         
             @Test
        -    public void testRequestTooBig ()
        +    public void testRequestTooBig()
        +        throws Exception
             {
                 MultipartConfigElement config = new MultipartConfigElement(_dirname, 60, 100, 50);
                 MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(_multi.getBytes()),
        -                _contentType,
        -                config,
        -                _tmpDir);
        +            _contentType,
        +            config,
        +            _tmpDir);
                 mpis.setDeleteOnExit(true);
         
        -        IllegalStateException x = assertThrows(IllegalStateException.class, ()-> mpis.getParts());
        +        IllegalStateException x = assertThrows(IllegalStateException.class, () -> mpis.getParts());
                 assertThat(x.getMessage(), containsString("Request exceeds maxRequestSize"));
             }
        -    
        -    
        +
             @Test
        -    public void testRequestTooBigThrowsErrorOnGetParts ()
        +    public void testRequestTooBigThrowsErrorOnGetParts()
        +        throws Exception
             {
                 MultipartConfigElement config = new MultipartConfigElement(_dirname, 60, 100, 50);
                 MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(_multi.getBytes()),
        -                _contentType,
        -                config,
        -                _tmpDir);
        +            _contentType,
        +            config,
        +            _tmpDir);
                 mpis.setDeleteOnExit(true);
         
                 //cause parsing
        -        IllegalStateException x = assertThrows(IllegalStateException.class, ()-> mpis.getParts());
        +        IllegalStateException x = assertThrows(IllegalStateException.class, () -> mpis.getParts());
                 assertThat(x.getMessage(), containsString("Request exceeds maxRequestSize"));
         
                 //try again
        -        x = assertThrows(IllegalStateException.class, ()-> mpis.getParts());
        +        x = assertThrows(IllegalStateException.class, () -> mpis.getParts());
                 assertThat(x.getMessage(), containsString("Request exceeds maxRequestSize"));
             }
         
             @Test
             public void testFileTooBig()
        +        throws Exception
             {
                 MultipartConfigElement config = new MultipartConfigElement(_dirname, 40, 1024, 30);
                 MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(_multi.getBytes()),
        -                _contentType,
        -                config,
        -                _tmpDir);
        +            _contentType,
        +            config,
        +            _tmpDir);
                 mpis.setDeleteOnExit(true);
                 IllegalStateException x = assertThrows(IllegalStateException.class,
        -                ()-> mpis.getParts(),
        -                "stuff.txt should have been larger than maxFileSize");
        +            () -> mpis.getParts(),
        +            "stuff.txt should have been larger than maxFileSize");
                 assertThat(x.getMessage(), startsWith("Multipart Mime part"));
             }
        -    
        +
             @Test
             public void testFileTooBigThrowsErrorOnGetParts()
        +        throws Exception
             {
                 MultipartConfigElement config = new MultipartConfigElement(_dirname, 40, 1024, 30);
                 MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(_multi.getBytes()),
        -                _contentType,
        -                config,
        -                _tmpDir);
        +            _contentType,
        +            config,
        +            _tmpDir);
                 mpis.setDeleteOnExit(true);
                 // Caused parsing
                 IllegalStateException x = assertThrows(IllegalStateException.class,
        -                ()-> mpis.getParts(),
        -                "stuff.txt should have been larger than maxFileSize");
        +            () -> mpis.getParts(),
        +            "stuff.txt should have been larger than maxFileSize");
                 assertThat(x.getMessage(), startsWith("Multipart Mime part"));
         
                 //test again after the parsing
                 x = assertThrows(IllegalStateException.class,
        -                ()-> mpis.getParts(),
        -                "stuff.txt should have been larger than maxFileSize");
        +            () -> mpis.getParts(),
        +            "stuff.txt should have been larger than maxFileSize");
                 assertThat(x.getMessage(), startsWith("Multipart Mime part"));
             }
         
        @@ -474,12 +472,12 @@ public class MultiPartFormInputStreamTest
             {
                 MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
                 MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(createMultipartRequestString("tptfd").getBytes()),
        -                _contentType,
        -                config,
        -                _tmpDir);
        +            _contentType,
        +            config,
        +            _tmpDir);
                 mpis.setDeleteOnExit(true);
                 mpis.getParts();
        -        
        +
                 MultiPart part = (MultiPart)mpis.getPart("stuff");
                 File stuff = part.getFile();
                 assertThat(stuff, notNullValue()); // longer than 100 bytes, should already be a tmp file
        @@ -491,15 +489,15 @@ public class MultiPartFormInputStreamTest
                 assertThat(tptfd.exists(), is(true));  //explicitly written file did not get removed after cleanup
                 tptfd.deleteOnExit(); //clean up test
             }
        -    
        +
             @Test
             public void testPartTmpFileDeletion() throws Exception
             {
                 MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
                 MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(createMultipartRequestString("tptfd").getBytes()),
        -                _contentType,
        -                config,
        -                _tmpDir);
        +            _contentType,
        +            config,
        +            _tmpDir);
                 mpis.setDeleteOnExit(true);
                 mpis.getParts();
         
        @@ -510,26 +508,26 @@ public class MultiPartFormInputStreamTest
                 part.cleanUp();
                 assertThat(stuff.exists(), is(false));  //tmp file was removed after cleanup
             }
        -    
        +
             @Test
             public void testLFOnlyRequest()
        -            throws Exception
        +        throws Exception
             {
                 String str = "--AaB03x\n" +
        -                "content-disposition: form-data; name=\"field1\"\n" +
        -                "\n" +
        -                "Joe Blow" +
        -                "\r\n--AaB03x\n" +
        -                "content-disposition: form-data; name=\"field2\"\n" +
        -                "\n" +
        -                "Other" +
        -                "\r\n--AaB03x--\n";
        +            "content-disposition: form-data; name=\"field1\"\n" +
        +            "\n" +
        +            "Joe Blow" +
        +            "\r\n--AaB03x\n" +
        +            "content-disposition: form-data; name=\"field2\"\n" +
        +            "\n" +
        +            "Other" +
        +            "\r\n--AaB03x--\n";
         
                 MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
                 MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(str.getBytes()),
        -                _contentType,
        -                config,
        -                _tmpDir);
        +            _contentType,
        +            config,
        +            _tmpDir);
                 mpis.setDeleteOnExit(true);
                 Collection parts = mpis.getParts();
                 assertThat(parts.size(), is(2));
        @@ -544,63 +542,63 @@ public class MultiPartFormInputStreamTest
                 baos = new ByteArrayOutputStream();
                 IO.copy(p2.getInputStream(), baos);
                 assertThat(baos.toString("UTF-8"), is("Other"));
        -
        -
             }
        -    
        +
             @Test
             public void testCROnlyRequest()
        +        throws Exception
             {
                 String str = "--AaB03x\r" +
        -                "content-disposition: form-data; name=\"field1\"\r" +
        -                "\r" +
        -                "Joe Blow\r" +
        -                "--AaB03x\r" +
        -                "content-disposition: form-data; name=\"field2\"\r" +
        -                "\r" +
        -                "Other\r" +
        -                "--AaB03x--\r";
        +            "content-disposition: form-data; name=\"field1\"\r" +
        +            "\r" +
        +            "Joe Blow\r" +
        +            "--AaB03x\r" +
        +            "content-disposition: form-data; name=\"field2\"\r" +
        +            "\r" +
        +            "Other\r" +
        +            "--AaB03x--\r";
         
                 MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
                 MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(str.getBytes()),
        -                _contentType,
        -                config,
        -                _tmpDir);
        +            _contentType,
        +            config,
        +            _tmpDir);
                 mpis.setDeleteOnExit(true);
         
                 IllegalStateException x = assertThrows(IllegalStateException.class,
        -                ()-> mpis.getParts(),
        -                "Improper EOL");
        +            () -> mpis.getParts(),
        +            "Improper EOL");
                 assertThat(x.getMessage(), containsString("Bad EOL"));
             }
         
             @Test
             public void testCRandLFMixRequest()
        +        throws Exception
             {
                 String str = "--AaB03x\r" +
        -                "content-disposition: form-data; name=\"field1\"\r" +
        -                "\r" +
        -                "\nJoe Blow\n" +
        -                "\r" +
        -                "--AaB03x\r" +
        -                "content-disposition: form-data; name=\"field2\"\r" +
        -                "\r" +
        -                "Other\r" +
        -                "--AaB03x--\r";
        -        
        +            "content-disposition: form-data; name=\"field1\"\r" +
        +            "\r" +
        +            "\nJoe Blow\n" +
        +            "\r" +
        +            "--AaB03x\r" +
        +            "content-disposition: form-data; name=\"field2\"\r" +
        +            "\r" +
        +            "Other\r" +
        +            "--AaB03x--\r";
        +
                 MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
                 MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(str.getBytes()),
        -                _contentType,
        -                config,
        -                _tmpDir);
        +            _contentType,
        +            config,
        +            _tmpDir);
                 mpis.setDeleteOnExit(true);
         
                 IllegalStateException x = assertThrows(IllegalStateException.class,
        -                ()-> mpis.getParts(),
        -                "Improper EOL");
        +            () -> mpis.getParts(),
        +            "Improper EOL");
                 assertThat(x.getMessage(), containsString("Bad EOL"));
             }
        -    
        +
             @Test
             public void testBufferOverflowNoCRLF() throws Exception
             {
        @@ -610,79 +608,78 @@ public class MultiPartFormInputStreamTest
                 {
                     baos.write('a');
                 }
        -        
        +
                 MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
                 MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(baos.toByteArray()),
        -                _contentType,
        -                config,
        -                _tmpDir);
        +            _contentType,
        +            config,
        +            _tmpDir);
                 mpis.setDeleteOnExit(true);
                 IllegalStateException x = assertThrows(IllegalStateException.class,
        -                ()-> mpis.getParts(),
        -                "Header Line Exceeded Max Length");
        +            () -> mpis.getParts(),
        +            "Header Line Exceeded Max Length");
                 assertThat(x.getMessage(), containsString("Header Line Exceeded Max Length"));
             }
        -    
        +
             @Test
             public void testCharsetEncoding() throws Exception
             {
                 String contentType = "multipart/form-data; boundary=TheBoundary; charset=ISO-8859-1";
                 String str = "--TheBoundary\r\n" +
        -                "content-disposition: form-data; name=\"field1\"\r\n" +
        -                "\r\n" +
        -                "\nJoe Blow\n" +
        -                "\r\n" +
        -                "--TheBoundary--\r\n";
        -        
        +            "content-disposition: form-data; name=\"field1\"\r\n" +
        +            "\r\n" +
        +            "\nJoe Blow\n" +
        +            "\r\n" +
        +            "--TheBoundary--\r\n";
        +
                 MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
                 MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(str.getBytes()),
        -                contentType,
        -                config,
        -                _tmpDir);
        +            contentType,
        +            config,
        +            _tmpDir);
                 mpis.setDeleteOnExit(true);
                 Collection parts = mpis.getParts();
                 assertThat(parts.size(), is(1));
             }
        -    
        -    
        +
             @Test
             public void testBadlyEncodedFilename() throws Exception
             {
        -        
        +
                 String contents = "--AaB03x\r\n" +
        -                "content-disposition: form-data; name=\"stuff\"; filename=\"" + "Taken on Aug 22 \\ 2012.jpg" + "\"\r\n" +
        -                "Content-Type: text/plain\r\n" +
        -                "\r\n" + "stuff" +
        -                "aaa" + "\r\n" +
        -                "--AaB03x--\r\n";
        -        
        +            "content-disposition: form-data; name=\"stuff\"; filename=\"" + "Taken on Aug 22 \\ 2012.jpg" + "\"\r\n" +
        +            "Content-Type: text/plain\r\n" +
        +            "\r\n" + "stuff" +
        +            "aaa" + "\r\n" +
        +            "--AaB03x--\r\n";
        +
                 MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
                 MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(contents.getBytes()),
        -                _contentType,
        -                config,
        -                _tmpDir);
        +            _contentType,
        +            config,
        +            _tmpDir);
                 mpis.setDeleteOnExit(true);
                 Collection parts = mpis.getParts();
                 assertThat(parts.size(), is(1));
                 assertThat(parts.iterator().next().getSubmittedFileName(), is("Taken on Aug 22 \\ 2012.jpg"));
             }
        -    
        +
             @Test
             public void testBadlyEncodedMSFilename() throws Exception
             {
        -        
        +
                 String contents = "--AaB03x\r\n" +
        -                "content-disposition: form-data; name=\"stuff\"; filename=\"" + "c:\\this\\really\\is\\some\\path\\to\\a\\file.txt" + "\"\r\n" +
        -                "Content-Type: text/plain\r\n" +
        -                "\r\n" + "stuff" +
        -                "aaa" + "\r\n" +
        -                "--AaB03x--\r\n";
        -        
        +            "content-disposition: form-data; name=\"stuff\"; filename=\"" + "c:\\this\\really\\is\\some\\path\\to\\a\\file.txt" + "\"\r\n" +
        +            "Content-Type: text/plain\r\n" +
        +            "\r\n" + "stuff" +
        +            "aaa" + "\r\n" +
        +            "--AaB03x--\r\n";
        +
                 MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
                 MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(contents.getBytes()),
        -                _contentType,
        -                config,
        -                _tmpDir);
        +            _contentType,
        +            config,
        +            _tmpDir);
                 mpis.setDeleteOnExit(true);
                 Collection parts = mpis.getParts();
                 assertThat(parts.size(), is(1));
        @@ -693,17 +690,17 @@ public class MultiPartFormInputStreamTest
             public void testCorrectlyEncodedMSFilename() throws Exception
             {
                 String contents = "--AaB03x\r\n" +
        -                "content-disposition: form-data; name=\"stuff\"; filename=\"" + "c:\\\\this\\\\really\\\\is\\\\some\\\\path\\\\to\\\\a\\\\file.txt" + "\"\r\n" +
        -                "Content-Type: text/plain\r\n" +
        -                "\r\n" + "stuff" +
        -                "aaa" + "\r\n" +
        -                "--AaB03x--\r\n";
        -        
        +            "content-disposition: form-data; name=\"stuff\"; filename=\"" + "c:\\\\this\\\\really\\\\is\\\\some\\\\path\\\\to\\\\a\\\\file.txt" + "\"\r\n" +
        +            "Content-Type: text/plain\r\n" +
        +            "\r\n" + "stuff" +
        +            "aaa" + "\r\n" +
        +            "--AaB03x--\r\n";
        +
                 MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
                 MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(contents.getBytes()),
        -                _contentType,
        -                config,
        -                _tmpDir);
        +            _contentType,
        +            config,
        +            _tmpDir);
                 mpis.setDeleteOnExit(true);
                 Collection parts = mpis.getParts();
                 assertThat(parts.size(), is(1));
        @@ -716,27 +713,26 @@ public class MultiPartFormInputStreamTest
                 testMulti("stuff with spaces.txt");
             }
         
        -    
             @Test
             public void testWriteFilesIfContentDispositionFilename()
        -            throws Exception
        +        throws Exception
             {
                 String s = "--AaB03x\r\n" +
        -                "content-disposition: form-data; name=\"field1\"; filename=\"frooble.txt\"\r\n" +
        -                "\r\n" +
        -                "Joe Blow\r\n" +
        -                "--AaB03x\r\n" +
        -                "content-disposition: form-data; name=\"stuff\"\r\n" +
        -                "Content-Type: text/plain\r\n" +
        -                "\r\n" + "sss" +
        -                "aaa" + "\r\n" +
        -                "--AaB03x--\r\n";
        +            "content-disposition: form-data; name=\"field1\"; filename=\"frooble.txt\"\r\n" +
        +            "\r\n" +
        +            "Joe Blow\r\n" +
        +            "--AaB03x\r\n" +
        +            "content-disposition: form-data; name=\"stuff\"\r\n" +
        +            "Content-Type: text/plain\r\n" +
        +            "\r\n" + "sss" +
        +            "aaa" + "\r\n" +
        +            "--AaB03x--\r\n";
                 //all default values for multipartconfig, ie file size threshold 0
                 MultipartConfigElement config = new MultipartConfigElement(_dirname);
                 MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(s.getBytes()),
        -                _contentType,
        -                config,
        -                _tmpDir);
        +            _contentType,
        +            config,
        +            _tmpDir);
                 mpis.setDeleteOnExit(true);
                 mpis.setWriteFilesWithFilenames(true);
                 Collection parts = mpis.getParts();
        @@ -744,20 +740,19 @@ public class MultiPartFormInputStreamTest
                 Part field1 = mpis.getPart("field1"); //has a filename, should be written to a file
                 File f = ((MultiPartFormInputStream.MultiPart)field1).getFile();
                 assertThat(f, notNullValue()); // longer than 100 bytes, should already be a tmp file
        -        
        +
                 Part stuff = mpis.getPart("stuff");
                 f = ((MultiPartFormInputStream.MultiPart)stuff).getFile(); //should only be in memory, no filename
                 assertThat(f, nullValue());
             }
        -    
        -    
        +
             private void testMulti(String filename) throws IOException
             {
                 MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
                 MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(createMultipartRequestString(filename).getBytes()),
        -                _contentType,
        -                config,
        -                _tmpDir);
        +            _contentType,
        +            config,
        +            _tmpDir);
                 mpis.setDeleteOnExit(true);
                 Collection parts = mpis.getParts();
                 assertThat(parts.size(), is(2));
        @@ -791,10 +786,12 @@ public class MultiPartFormInputStreamTest
                 assertThat(stuff.getContentType(), is("text/plain"));
                 assertThat(stuff.getHeader("Content-Type"), is("text/plain"));
                 assertThat(stuff.getHeaders("content-type").size(), is(1));
        +        assertNotNull(stuff.getHeaders("non existing part"));
        +        assertThat(stuff.getHeaders("non existing part").size(), is(0));
                 assertThat(stuff.getHeader("content-disposition"), is("form-data; name=\"stuff\"; filename=\"" + filename + "\""));
                 assertThat(stuff.getHeaderNames().size(), is(2));
                 assertThat(stuff.getSize(), is(51L));
        -        
        +
                 File tmpfile = stuff.getFile();
                 assertThat(tmpfile, notNullValue()); // longer than 50 bytes, should already be a tmp file
                 assertThat(stuff.getBytes(), nullValue()); //not in an internal buffer
        @@ -817,30 +814,32 @@ public class MultiPartFormInputStreamTest
         
             @Test
             public void testMultiSameNames()
        -            throws Exception
        +        throws Exception
             {
                 String sameNames = "--AaB03x\r\n" +
        -                "content-disposition: form-data; name=\"stuff\"; filename=\"stuff1.txt\"\r\n" +
        -                "Content-Type: text/plain\r\n" +
        -                "\r\n" +
        -                "00000\r\n" +
        -                "--AaB03x\r\n" +
        -                "content-disposition: form-data; name=\"stuff\"; filename=\"stuff2.txt\"\r\n" +
        -                "Content-Type: text/plain\r\n" +
        -                "\r\n" +
        -                "110000000000000000000000000000000000000000000000000\r\n" +
        -                "--AaB03x--\r\n";
        +            "content-disposition: form-data; name=\"stuff\"; filename=\"stuff1.txt\"\r\n" +
        +            "Content-Type: text/plain\r\n" +
        +            "\r\n" +
        +            "00000\r\n" +
        +            "--AaB03x\r\n" +
        +            "content-disposition: form-data; name=\"stuff\"; filename=\"stuff2.txt\"\r\n" +
        +            "Content-Type: text/plain\r\n" +
        +            "\r\n" +
        +            "110000000000000000000000000000000000000000000000000\r\n" +
        +            "--AaB03x--\r\n";
         
                 MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
                 MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(sameNames.getBytes()),
        -                _contentType,
        -                config,
        -                _tmpDir);
        +            _contentType,
        +            config,
        +            _tmpDir);
                 mpis.setDeleteOnExit(true);
                 Collection parts = mpis.getParts();
                 assertEquals(2, parts.size());
                 for (Part p : parts)
        +        {
                     assertEquals("stuff", p.getName());
        +        }
         
                 //if they all have the name name, then only retrieve the first one
                 Part p = mpis.getPart("stuff");
        @@ -852,29 +851,29 @@ public class MultiPartFormInputStreamTest
             public void testBase64EncodedContent() throws Exception
             {
                 String contentWithEncodedPart =
        +            "--AaB03x\r\n" +
        +                "Content-disposition: form-data; name=\"other\"\r\n" +
        +                "Content-Type: text/plain\r\n" +
        +                "\r\n" +
        +                "other" + "\r\n" +
                         "--AaB03x\r\n" +
        -                        "Content-disposition: form-data; name=\"other\"\r\n" +
        -                        "Content-Type: text/plain\r\n" +
        -                        "\r\n" +
        -                        "other" + "\r\n" +
        -                        "--AaB03x\r\n" +
        -                        "Content-disposition: form-data; name=\"stuff\"; filename=\"stuff.txt\"\r\n" +
        -                        "Content-Transfer-Encoding: base64\r\n" +
        -                        "Content-Type: application/octet-stream\r\n" +
        -                        "\r\n" +
        -                        B64Code.encode("hello jetty") + "\r\n" +
        -                        "--AaB03x\r\n" +
        -                        "Content-disposition: form-data; name=\"final\"\r\n" +
        -                        "Content-Type: text/plain\r\n" +
        -                        "\r\n" +
        -                        "the end" + "\r\n" +
        -                        "--AaB03x--\r\n";
        +                "Content-disposition: form-data; name=\"stuff\"; filename=\"stuff.txt\"\r\n" +
        +                "Content-Transfer-Encoding: base64\r\n" +
        +                "Content-Type: application/octet-stream\r\n" +
        +                "\r\n" +
        +                Base64.getEncoder().encodeToString("hello jetty".getBytes(ISO_8859_1)) + "\r\n" +
        +                "--AaB03x\r\n" +
        +                "Content-disposition: form-data; name=\"final\"\r\n" +
        +                "Content-Type: text/plain\r\n" +
        +                "\r\n" +
        +                "the end" + "\r\n" +
        +                "--AaB03x--\r\n";
         
                 MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
                 MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(contentWithEncodedPart.getBytes()),
        -                _contentType,
        -                config,
        -                _tmpDir);
        +            _contentType,
        +            config,
        +            _tmpDir);
                 mpis.setDeleteOnExit(true);
                 Collection parts = mpis.getParts();
                 assertEquals(3, parts.size());
        @@ -889,36 +888,36 @@ public class MultiPartFormInputStreamTest
                 assertNotNull(p2);
                 baos = new ByteArrayOutputStream();
                 IO.copy(p2.getInputStream(), baos);
        -        assertEquals(B64Code.encode("hello jetty"), baos.toString("US-ASCII"));
        -        
        +        assertEquals(Base64.getEncoder().encodeToString("hello jetty".getBytes(ISO_8859_1)), baos.toString("US-ASCII"));
        +
                 Part p3 = mpis.getPart("final");
                 assertNotNull(p3);
                 baos = new ByteArrayOutputStream();
                 IO.copy(p3.getInputStream(), baos);
                 assertEquals("the end", baos.toString("US-ASCII"));
             }
        -    
        +
             @Test
             public void testQuotedPrintableEncoding() throws Exception
             {
                 String contentWithEncodedPart =
        +            "--AaB03x\r\n" +
        +                "Content-disposition: form-data; name=\"other\"\r\n" +
        +                "Content-Type: text/plain\r\n" +
        +                "\r\n" +
        +                "other" + "\r\n" +
                         "--AaB03x\r\n" +
        -                        "Content-disposition: form-data; name=\"other\"\r\n" +
        -                        "Content-Type: text/plain\r\n" +
        -                        "\r\n" +
        -                        "other" + "\r\n" +
        -                        "--AaB03x\r\n" +
        -                        "Content-disposition: form-data; name=\"stuff\"; filename=\"stuff.txt\"\r\n" +
        -                        "Content-Transfer-Encoding: quoted-printable\r\n" +
        -                        "Content-Type: text/plain\r\n" +
        -                        "\r\n" +
        -                        "truth=3Dbeauty" + "\r\n" +
        -                        "--AaB03x--\r\n";
        +                "Content-disposition: form-data; name=\"stuff\"; filename=\"stuff.txt\"\r\n" +
        +                "Content-Transfer-Encoding: quoted-printable\r\n" +
        +                "Content-Type: text/plain\r\n" +
        +                "\r\n" +
        +                "truth=3Dbeauty" + "\r\n" +
        +                "--AaB03x--\r\n";
                 MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
                 MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(contentWithEncodedPart.getBytes()),
        -                _contentType,
        -                config,
        -                _tmpDir);
        +            _contentType,
        +            config,
        +            _tmpDir);
                 mpis.setDeleteOnExit(true);
                 Collection parts = mpis.getParts();
                 assertEquals(2, parts.size());
        @@ -936,43 +935,40 @@ public class MultiPartFormInputStreamTest
                 assertEquals("truth=3Dbeauty", baos.toString("US-ASCII"));
             }
         
        -
             @Test
             public void testGeneratedForm()
        -            throws Exception
        +        throws Exception
             {
                 String contentType = "multipart/form-data, boundary=WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW";
                 String body = "Content-Type: multipart/form-data; boundary=WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW\r\n" +
        -                "\r\n" +
        -                "--WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW\r\n" +
        -                "Content-Disposition: form-data; name=\"part1\"\r\n" +
        -                "\n" +
        -                "wNfミxVam﾿t\r\n" +
        -                "--WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW\n" +
        -                "Content-Disposition: form-data; name=\"part2\"\r\n" +
        -                "\r\n" +
        -                "&ᄈᄎ￙ᅱᅢO\r\n" +
        -                "--WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW--";
        -
        +            "\r\n" +
        +            "--WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW\r\n" +
        +            "Content-Disposition: form-data; name=\"part1\"\r\n" +
        +            "\n" +
        +            "wNfミxVam﾿t\r\n" +
        +            "--WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW\n" +
        +            "Content-Disposition: form-data; name=\"part2\"\r\n" +
        +            "\r\n" +
        +            "&ᄈᄎ￙ᅱᅢO\r\n" +
        +            "--WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW--";
         
                 MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
                 MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(body.getBytes()),
        -                contentType,
        -                config,
        -                _tmpDir);
        +            contentType,
        +            config,
        +            _tmpDir);
                 mpis.setDeleteOnExit(true);
         
                 Collection parts = mpis.getParts();
                 assertThat(parts, notNullValue());
                 assertThat(parts.size(), is(2));
        -        
        +
                 Part part1 = mpis.getPart("part1");
                 assertThat(part1, notNullValue());
                 Part part2 = mpis.getPart("part2");
                 assertThat(part2, notNullValue());
             }
         
        -    
             private static String createMultipartRequestString(String filename)
             {
                 int length = filename.length();
        @@ -986,16 +982,16 @@ public class MultiPartFormInputStreamTest
                     filler.append("0");
                     i++;
                 }
        -        
        +
                 return "--AaB03x\r\n" +
        -                "content-disposition: form-data; name=\"field1\"; filename=\"frooble.txt\"\r\n" +
        -                "\r\n" +
        -                "Joe Blow\r\n" +
        -                "--AaB03x\r\n" +
        -                "content-disposition: form-data; name=\"stuff\"; filename=\"" + filename + "\"\r\n" +
        -                "Content-Type: text/plain\r\n" +
        -                "\r\n" + name +
        -                filler.toString() + "\r\n" +
        -                "--AaB03x--\r\n";
        +            "content-disposition: form-data; name=\"field1\"; filename=\"frooble.txt\"\r\n" +
        +            "\r\n" +
        +            "Joe Blow\r\n" +
        +            "--AaB03x\r\n" +
        +            "content-disposition: form-data; name=\"stuff\"; filename=\"" + filename + "\"\r\n" +
        +            "Content-Type: text/plain\r\n" +
        +            "\r\n" + name +
        +            filler.toString() + "\r\n" +
        +            "--AaB03x--\r\n";
             }
         }
        diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java
        index e54f17989e1..09e61f59572 100644
        --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java
        +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java
        @@ -1,6 +1,6 @@
         //
         //  ========================================================================
        -//  Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
        +//  Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
         //  ------------------------------------------------------------------------
         //  All rights reserved. This program and the accompanying materials
         //  are made available under the terms of the Eclipse Public License v1.0
        @@ -18,12 +18,6 @@
         
         package org.eclipse.jetty.http;
         
        -import static org.hamcrest.MatcherAssert.assertThat;
        -import static org.hamcrest.Matchers.containsString;
        -import static org.hamcrest.Matchers.is;
        -import static org.junit.jupiter.api.Assertions.assertThrows;
        -import static org.junit.jupiter.api.Assertions.assertTrue;
        -
         import java.nio.ByteBuffer;
         import java.util.ArrayList;
         import java.util.List;
        @@ -34,6 +28,12 @@ import org.eclipse.jetty.util.BufferUtil;
         import org.hamcrest.Matchers;
         import org.junit.jupiter.api.Test;
         
        +import static org.hamcrest.MatcherAssert.assertThat;
        +import static org.hamcrest.Matchers.containsString;
        +import static org.hamcrest.Matchers.is;
        +import static org.junit.jupiter.api.Assertions.assertThrows;
        +import static org.junit.jupiter.api.Assertions.assertTrue;
        +
         public class MultiPartParserTest
         {
         
        @@ -44,7 +44,7 @@ public class MultiPartParserTest
                 {
                 }, "BOUNDARY");
                 ByteBuffer data = BufferUtil.toBuffer("");
        -        
        +
                 parser.parse(data, false);
                 assertThat(parser.getState(), is(State.PREAMBLE));
             }
        @@ -56,12 +56,12 @@ public class MultiPartParserTest
                 {
                 }, "BOUNDARY");
                 ByteBuffer data = BufferUtil.toBuffer("--BOUNDARY   \r\n");
        -        
        +
                 parser.parse(data, false);
                 assertTrue(parser.isState(State.BODY_PART));
                 assertThat(data.remaining(), is(0));
             }
        -    
        +
             @Test
             public void testPreamble()
             {
        @@ -69,27 +69,27 @@ public class MultiPartParserTest
                 {
                 }, "BOUNDARY");
                 ByteBuffer data;
        -        
        +
                 data = BufferUtil.toBuffer("This is not part of a part\r\n");
                 parser.parse(data, false);
                 assertThat(parser.getState(), is(State.PREAMBLE));
                 assertThat(data.remaining(), is(0));
        -        
        +
                 data = BufferUtil.toBuffer("More data that almost includes \n--BOUNDARY but no CR before.");
                 parser.parse(data, false);
                 assertThat(parser.getState(), is(State.PREAMBLE));
                 assertThat(data.remaining(), is(0));
        -        
        +
                 data = BufferUtil.toBuffer("Could be a boundary \r\n--BOUNDAR");
                 parser.parse(data, false);
                 assertThat(parser.getState(), is(State.PREAMBLE));
                 assertThat(data.remaining(), is(0));
        -        
        +
                 data = BufferUtil.toBuffer("but not it isn't \r\n--BOUN");
                 parser.parse(data, false);
                 assertThat(parser.getState(), is(State.PREAMBLE));
                 assertThat(data.remaining(), is(0));
        -        
        +
                 data = BufferUtil.toBuffer("DARX nor is this");
                 parser.parse(data, false);
                 assertThat(parser.getState(), is(State.PREAMBLE));
        @@ -103,12 +103,12 @@ public class MultiPartParserTest
                 {
                 }, "BOUNDARY");
                 ByteBuffer data = BufferUtil.toBuffer("This is not part of a part\r\n--BOUNDARY  \r\n");
        -        
        +
                 parser.parse(data, false);
                 assertThat(parser.getState(), is(State.BODY_PART));
                 assertThat(data.remaining(), is(0));
             }
        -    
        +
             @Test
             public void testPreambleSplitBoundary()
             {
        @@ -153,12 +153,12 @@ public class MultiPartParserTest
                 {
                 }, "BOUNDARY");
                 ByteBuffer data = BufferUtil.toBuffer("--BOUNDARY\r\n\r\n");
        -        
        +
                 parser.parse(data, false);
                 assertThat(parser.getState(), is(State.FIRST_OCTETS));
                 assertThat(data.remaining(), is(0));
             }
        -    
        +
             @Test
             public void testFirstPartFields()
             {
        @@ -172,55 +172,54 @@ public class MultiPartParserTest
                     }
                 };
                 MultiPartParser parser = new MultiPartParser(handler, "BOUNDARY");
        -        
        -        ByteBuffer data = BufferUtil.toBuffer("--BOUNDARY\r\n"
        -                + "name0: value0\r\n"
        -                + "name1 :value1 \r\n"
        -                + "name2:value\r\n"
        -                + " 2\r\n"
        -                + "\r\n"
        -                + "Content");
        +
        +        ByteBuffer data = BufferUtil.toBuffer("--BOUNDARY\r\n" +
        +                "name0: value0\r\n" +
        +                "name1 :value1 \r\n" +
        +                "name2:value\r\n" +
        +                " 2\r\n" +
        +                "\r\n" +
        +                "Content");
         
                 parser.parse(data, false);
                 assertThat(parser.getState(), is(State.FIRST_OCTETS));
                 assertThat(data.remaining(), is(7));
                 assertThat(handler.fields, Matchers.contains("name0: value0", "name1: value1", "name2: value 2", "<>"));
             }
        -    
        +
             @Test
             public void testFirstPartNoContent()
             {
                 TestHandler handler = new TestHandler();
                 MultiPartParser parser = new MultiPartParser(handler, "BOUNDARY");
        -        
        -        ByteBuffer data = BufferUtil.toBuffer("--BOUNDARY\r\n"
        -                + "name: value\r\n"
        -                + "\r\n"
        -                + "\r\n"
        -                + "--BOUNDARY");
        +
        +        ByteBuffer data = BufferUtil.toBuffer("--BOUNDARY\r\n" +
        +                "name: value\r\n" +
        +                "\r\n" +
        +                "\r\n" +
        +                "--BOUNDARY");
                 parser.parse(data, false);
                 assertThat(parser.getState(), is(State.DELIMITER));
                 assertThat(data.remaining(), is(0));
                 assertThat(handler.fields, Matchers.contains("name: value", "<>"));
                 assertThat(handler.content, Matchers.contains("<>"));
             }
        -    
        +
             @Test
             public void testFirstPartNoContentNoCRLF()
             {
                 TestHandler handler = new TestHandler();
                 MultiPartParser parser = new MultiPartParser(handler, "BOUNDARY");
        -        
        -        ByteBuffer data = BufferUtil.toBuffer("--BOUNDARY\r\n"
        -                + "name: value\r\n"
        -                + "\r\n"
        -                + "--BOUNDARY");
        +
        +        ByteBuffer data = BufferUtil.toBuffer("--BOUNDARY\r\n" +
        +                "name: value\r\n" +
        +                "\r\n" +
        +                "--BOUNDARY");
                 parser.parse(data, false);
                 assertThat(parser.getState(), is(State.DELIMITER));
                 assertThat(data.remaining(), is(0));
                 assertThat(handler.fields, Matchers.contains("name: value", "<>"));
                 assertThat(handler.content, Matchers.contains("<>"));
        -        
             }
         
             @Test
        @@ -228,16 +227,15 @@ public class MultiPartParserTest
             {
                 TestHandler handler = new TestHandler();
                 MultiPartParser parser = new MultiPartParser(handler, "BOUNDARY");
        -        
        -        ByteBuffer data = BufferUtil.toBuffer("--BOUNDARY\r\n"
        -                + "name: value\r\n"
        -                + "\r\n"
        -                + "-");
        +
        +        ByteBuffer data = BufferUtil.toBuffer("--BOUNDARY\r\n" +
        +                "name: value\r\n" +
        +                "\r\n" +
        +                "-");
                 parser.parse(data, false);
                 data = BufferUtil.toBuffer("Content!");
                 parser.parse(data, false);
        -        
        -        
        +
                 assertThat(parser.getState(), is(State.OCTETS));
                 assertThat(data.remaining(), is(0));
                 assertThat(handler.fields, Matchers.contains("name: value", "<>"));
        @@ -249,11 +247,11 @@ public class MultiPartParserTest
             {
                 TestHandler handler = new TestHandler();
                 MultiPartParser parser = new MultiPartParser(handler, "BOUNDARY");
        -        
        -        ByteBuffer data = BufferUtil.toBuffer("--BOUNDARY\r\n"
        -                + "name: value\n"
        -                + "\r\n"
        -                + "Hello\r\n");
        +
        +        ByteBuffer data = BufferUtil.toBuffer("--BOUNDARY\r\n" +
        +                "name: value\n" +
        +                "\r\n" +
        +                "Hello\r\n");
                 parser.parse(data, false);
                 assertThat(parser.getState(), is(State.OCTETS));
                 assertThat(data.remaining(), is(0));
        @@ -261,18 +259,18 @@ public class MultiPartParserTest
                 assertThat(handler.content, Matchers.contains("Hello"));
         
                 data = BufferUtil.toBuffer(
        -                "Now is the time for all good ment to come to the aid of the party.\r\n"
        -                        + "How now brown cow.\r\n"
        -                        + "The quick brown fox jumped over the lazy dog.\r\n"
        -                        + "this is not a --BOUNDARY\r\n");
        +            "Now is the time for all good ment to come to the aid of the party.\r\n" +
        +                    "How now brown cow.\r\n" +
        +                    "The quick brown fox jumped over the lazy dog.\r\n" +
        +                    "this is not a --BOUNDARY\r\n");
                 parser.parse(data, false);
                 assertThat(parser.getState(), is(State.OCTETS));
                 assertThat(data.remaining(), is(0));
                 assertThat(handler.fields, Matchers.contains("name: value", "<>"));
        -        assertThat(handler.content, Matchers.contains("Hello", "\r\n", "Now is the time for all good ment to come to the aid of the party.\r\n"
        -                + "How now brown cow.\r\n"
        -                + "The quick brown fox jumped over the lazy dog.\r\n"
        -                + "this is not a --BOUNDARY"));
        +        assertThat(handler.content, Matchers.contains("Hello", "\r\n", "Now is the time for all good ment to come to the aid of the party.\r\n" +
        +                "How now brown cow.\r\n" +
        +                "The quick brown fox jumped over the lazy dog.\r\n" +
        +                "this is not a --BOUNDARY"));
             }
         
             @Test
        @@ -280,43 +278,42 @@ public class MultiPartParserTest
             {
                 TestHandler handler = new TestHandler();
                 MultiPartParser parser = new MultiPartParser(handler, "BOUNDARY");
        -        
        -        ByteBuffer data = BufferUtil.toBuffer("--BOUNDARY\r\n"
        -                + "name: value\n"
        -                + "\r\n"
        -                + "Hello\r\n"
        -                + "--BOUNDARY");
        +
        +        ByteBuffer data = BufferUtil.toBuffer("--BOUNDARY\r\n" +
        +                "name: value\n" +
        +                "\r\n" +
        +                "Hello\r\n" +
        +                "--BOUNDARY");
                 parser.parse(data, false);
                 assertThat(parser.getState(), is(State.DELIMITER));
                 assertThat(data.remaining(), is(0));
                 assertThat(handler.fields, Matchers.contains("name: value", "<>"));
                 assertThat(handler.content, Matchers.contains("Hello", "<>"));
             }
        -    
         
             @Test
             public void testFirstPartLongContent()
             {
                 TestHandler handler = new TestHandler();
                 MultiPartParser parser = new MultiPartParser(handler, "BOUNDARY");
        -        
        -        ByteBuffer data = BufferUtil.toBuffer("--BOUNDARY\r\n"
        -                + "name: value\n"
        -                + "\r\n"
        -                + "Now is the time for all good ment to come to the aid of the party.\r\n"
        -                + "How now brown cow.\r\n"
        -                + "The quick brown fox jumped over the lazy dog.\r\n"
        -                + "\r\n"
        -                + "--BOUNDARY");
        +
        +        ByteBuffer data = BufferUtil.toBuffer("--BOUNDARY\r\n" +
        +                "name: value\n" +
        +                "\r\n" +
        +                "Now is the time for all good ment to come to the aid of the party.\r\n" +
        +                "How now brown cow.\r\n" +
        +                "The quick brown fox jumped over the lazy dog.\r\n" +
        +                "\r\n" +
        +                "--BOUNDARY");
                 parser.parse(data, false);
                 assertThat(parser.getState(), is(State.DELIMITER));
                 assertThat(data.remaining(), is(0));
                 assertThat(handler.fields, Matchers.contains("name: value", "<>"));
        -        assertThat(handler.content, Matchers.contains("Now is the time for all good ment to come to the aid of the party.\r\n"
        -                + "How now brown cow.\r\n"
        -                + "The quick brown fox jumped over the lazy dog.\r\n", "<>"));
        +        assertThat(handler.content, Matchers.contains("Now is the time for all good ment to come to the aid of the party.\r\n" +
        +                "How now brown cow.\r\n" +
        +                "The quick brown fox jumped over the lazy dog.\r\n", "<>"));
             }
        -    
        +
             @Test
             public void testFirstPartLongContentNoCarriageReturn()
             {
        @@ -324,24 +321,23 @@ public class MultiPartParserTest
                 MultiPartParser parser = new MultiPartParser(handler, "BOUNDARY");
         
                 //boundary still requires carriage return
        -        ByteBuffer data = BufferUtil.toBuffer("--BOUNDARY\n"
        -                + "name: value\n"
        -                + "\n"
        -                + "Now is the time for all good men to come to the aid of the party.\n"
        -                + "How now brown cow.\n"
        -                + "The quick brown fox jumped over the lazy dog.\n"
        -                + "\r\n"
        -                + "--BOUNDARY");
        +        ByteBuffer data = BufferUtil.toBuffer("--BOUNDARY\n" +
        +                "name: value\n" +
        +                "\n" +
        +                "Now is the time for all good men to come to the aid of the party.\n" +
        +                "How now brown cow.\n" +
        +                "The quick brown fox jumped over the lazy dog.\n" +
        +                "\r\n" +
        +                "--BOUNDARY");
                 parser.parse(data, false);
                 assertThat(parser.getState(), is(State.DELIMITER));
                 assertThat(data.remaining(), is(0));
                 assertThat(handler.fields, Matchers.contains("name: value", "<>"));
        -        assertThat(handler.content, Matchers.contains("Now is the time for all good men to come to the aid of the party.\n"
        -                + "How now brown cow.\n"
        -                + "The quick brown fox jumped over the lazy dog.\n", "<>"));
        +        assertThat(handler.content, Matchers.contains("Now is the time for all good men to come to the aid of the party.\n" +
        +                "How now brown cow.\n" +
        +                "The quick brown fox jumped over the lazy dog.\n", "<>"));
             }
         
        -    
             @Test
             public void testBinaryPart()
             {
        @@ -349,7 +345,7 @@ public class MultiPartParserTest
                 final ByteBuffer bytes = BufferUtil.allocate(random.length);
                 ThreadLocalRandom.current().nextBytes(random);
                 // Arrays.fill(random,(byte)'X');
        -        
        +
                 TestHandler handler = new TestHandler()
                 {
                     @Override
        @@ -360,89 +356,86 @@ public class MultiPartParserTest
                     }
                 };
                 MultiPartParser parser = new MultiPartParser(handler, "BOUNDARY");
        -        
        +
                 String preamble = "Blah blah blah\r\n--BOUNDARY\r\n\r\n";
                 String epilogue = "\r\n--BOUNDARY\r\nBlah blah blah!\r\n";
        -        
        +
                 ByteBuffer data = BufferUtil.allocate(preamble.length() + random.length + epilogue.length());
                 BufferUtil.append(data, BufferUtil.toBuffer(preamble));
                 BufferUtil.append(data, ByteBuffer.wrap(random));
                 BufferUtil.append(data, BufferUtil.toBuffer(epilogue));
        -        
        +
                 parser.parse(data, true);
                 assertThat(parser.getState(), is(State.DELIMITER));
                 assertThat(data.remaining(), is(19));
                 assertThat(bytes.array(), is(random));
             }
        -    
        +
             @Test
             public void testEpilogue()
             {
                 TestHandler handler = new TestHandler();
                 MultiPartParser parser = new MultiPartParser(handler, "BOUNDARY");
        -        
        -        ByteBuffer data = BufferUtil.toBuffer(""
        -                + "--BOUNDARY\r\n"
        -                + "name: value\n"
        -                + "\r\n"
        -                + "Hello\r\n"
        -                + "--BOUNDARY--"
        -                + "epilogue here:"
        -                + "\r\n"
        -                + "--BOUNDARY--"
        -                + "\r\n"
        -                + "--BOUNDARY");
        -        
        -        
        +
        +        ByteBuffer data = BufferUtil.toBuffer("" +
        +                "--BOUNDARY\r\n" +
        +                "name: value\n" +
        +                "\r\n" +
        +                "Hello\r\n" +
        +                "--BOUNDARY--" +
        +                "epilogue here:" +
        +                "\r\n" +
        +                "--BOUNDARY--" +
        +                "\r\n" +
        +                "--BOUNDARY");
        +
                 parser.parse(data, false);
                 assertThat(parser.getState(), is(State.DELIMITER));
                 assertThat(handler.fields, Matchers.contains("name: value", "<>"));
                 assertThat(handler.content, Matchers.contains("Hello", "<>"));
        -        
        +
                 parser.parse(data, true);
                 assertThat(parser.getState(), is(State.END));
             }
        -    
        -    
        +
             @Test
             public void testMultipleContent()
             {
                 TestHandler handler = new TestHandler();
                 MultiPartParser parser = new MultiPartParser(handler, "BOUNDARY");
        -        
        -        ByteBuffer data = BufferUtil.toBuffer(""
        -                + "--BOUNDARY\r\n"
        -                + "name: value\n"
        -                + "\r\n"
        -                + "Hello"
        -                + "\r\n"
        -                + "--BOUNDARY\r\n"
        -                + "powerLevel: 9001\n"
        -                + "\r\n"
        -                + "secondary"
        -                + "\r\n"
        -                + "content"
        -                + "\r\n--BOUNDARY--"
        -                + "epilogue here");
        -        
        +
        +        ByteBuffer data = BufferUtil.toBuffer("" +
        +                "--BOUNDARY\r\n" +
        +                "name: value\n" +
        +                "\r\n" +
        +                "Hello" +
        +                "\r\n" +
        +                "--BOUNDARY\r\n" +
        +                "powerLevel: 9001\n" +
        +                "\r\n" +
        +                "secondary" +
        +                "\r\n" +
        +                "content" +
        +                "\r\n--BOUNDARY--" +
        +                "epilogue here");
        +
                 /* Test First Content Section */
                 parser.parse(data, false);
                 assertThat(parser.getState(), is(State.DELIMITER));
                 assertThat(handler.fields, Matchers.contains("name: value", "<>"));
                 assertThat(handler.content, Matchers.contains("Hello", "<>"));
        -        
        +
                 /* Test Second Content Section */
                 parser.parse(data, false);
                 assertThat(parser.getState(), is(State.DELIMITER));
                 assertThat(handler.fields, Matchers.contains("name: value", "<>", "powerLevel: 9001", "<>"));
                 assertThat(handler.content, Matchers.contains("Hello", "<>", "secondary\r\ncontent", "<>"));
        -        
        +
                 /* Test Progression to END State */
                 parser.parse(data, true);
                 assertThat(parser.getState(), is(State.END));
                 assertThat(data.remaining(), is(0));
             }
        -    
         
             @Test
             public void testCrAsLineTermination()
        @@ -463,17 +456,17 @@ public class MultiPartParserTest
                     }
                 };
                 MultiPartParser parser = new MultiPartParser(handler, "AaB03x");
        -        
        -        ByteBuffer data =  BufferUtil.toBuffer(
        -                "--AaB03x\r\n"+
        -                "content-disposition: form-data; name=\"field1\"\r\n"+
        -                "\r"+
        -                "Joe Blow\r\n"+
        +
        +        ByteBuffer data = BufferUtil.toBuffer(
        +            "--AaB03x\r\n" +
        +                "content-disposition: form-data; name=\"field1\"\r\n" +
        +                "\r" +
        +                "Joe Blow\r\n" +
                         "--AaB03x--\r\n");
         
                 BadMessageException x = assertThrows(BadMessageException.class,
        -                ()-> parser.parse(data,true),
        -                "Invalid EOL");
        +            () -> parser.parse(data, true),
        +            "Invalid EOL");
                 assertThat(x.getMessage(), containsString("Bad EOL"));
             }
         
        @@ -481,38 +474,38 @@ public class MultiPartParserTest
             public void testBadHeaderNames() throws Exception
             {
                 String[] bad = new String[]
        -                {
        -                        "Foo\\Bar: value\r\n",
        -                        "Foo@Bar: value\r\n",
        -                        "Foo,Bar: value\r\n",
        -                        "Foo}Bar: value\r\n",
        -                        "Foo{Bar: value\r\n",
        -                        "Foo=Bar: value\r\n",
        -                        "Foo>Bar: value\r\n",
        -                        "FooBar: value\r\n",
        +                "Foo>"
        -                    , "Content-Disposition: form-data; name=\"file1\"; filename=\"a.txt\""
        -                    , "Content-Type: text/plain", "<>"
        -                    , "Content-Disposition: form-data; name=\"file2\"; filename=\"a.html\""
        -                    , "Content-Type: text/html", "<>"
        -                    , "Field1: value1", "Field2: value2", "Field3: value3"
        -                    , "Field4: value4", "Field5: value5", "Field6: value6"
        -                    , "Field7: value7", "Field8: value8", "Field9: value 9", "<>"
        -                    , "Field1: value1", "<>"));
        +            assertThat(handler.fields, Matchers.contains("Content-Disposition: form-data; name=\"text\"", "<>",
        +                    "Content-Disposition: form-data; name=\"file1\"; filename=\"a.txt\"",
        +                    "Content-Type: text/plain", "<>",
        +                    "Content-Disposition: form-data; name=\"file2\"; filename=\"a.html\"",
        +                    "Content-Type: text/html", "<>",
        +                    "Field1: value1", "Field2: value2", "Field3: value3",
        +                    "Field4: value4", "Field5: value5", "Field6: value6",
        +                    "Field7: value7", "Field8: value8", "Field9: value 9", "<>",
        +                    "Field1: value1", "<>"));
         
        -
        -            assertThat(handler.contentString(), is("text default" + "<>"
        -                    + "Content of a.txt.\n" + "<>"
        -                    + "Content of a.html.\n" + "<>"
        -                    + "<>"
        -                    + "But the amount of denudation which the strata have\n" +
        -                    "in many places suffered, independently of the rate\n" +
        -                    "of accumulation of the degraded matter, probably\n" +
        -                    "offers the best evidence of the lapse of time. I remember\n" +
        -                    "having been much struck with the evidence of\n" +
        -                    "denudation, when viewing volcanic islands, which\n" +
        -                    "have been worn by the waves and pared all round\n" +
        -                    "into perpendicular cliffs of one or two thousand feet\n" +
        -                    "in height; for the gentle slope of the lava-streams,\n" +
        -                    "due to their formerly liquid state, showed at a glance\n" +
        -                    "how far the hard, rocky beds had once extended into\n" +
        -                    "the open ocean.\n" + "<>"));
        +            assertThat(handler.contentString(), is("text default" + "<>" +
        +                    "Content of a.txt.\n" + "<>" +
        +                    "Content of a.html.\n" + "<>" +
        +                    "<>" +
        +                    "But the amount of denudation which the strata have\n" +
        +                "in many places suffered, independently of the rate\n" +
        +                "of accumulation of the degraded matter, probably\n" +
        +                "offers the best evidence of the lapse of time. I remember\n" +
        +                "having been much struck with the evidence of\n" +
        +                "denudation, when viewing volcanic islands, which\n" +
        +                "have been worn by the waves and pared all round\n" +
        +                "into perpendicular cliffs of one or two thousand feet\n" +
        +                "in height; for the gentle slope of the lava-streams,\n" +
        +                "due to their formerly liquid state, showed at a glance\n" +
        +                "how far the hard, rocky beds had once extended into\n" +
        +                "the open ocean.\n" + "<>"));
         
                     handler.clear();
                     parser.reset();
                 }
             }
        -    
         
             @Test
             public void testGeneratedForm()
        @@ -671,17 +661,17 @@ public class MultiPartParserTest
                         super.content(buffer, last);
                         return false;
                     }
        -            
        +
                     @Override
                     public boolean headerComplete()
                     {
                         return false;
                     }
                 };
        -        
        +
                 MultiPartParser parser = new MultiPartParser(handler, "WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW");
        -        ByteBuffer data = BufferUtil.toBuffer(""
        -                + "Content-Type: multipart/form-data; boundary=WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW\r\n" +
        +        ByteBuffer data = BufferUtil.toBuffer("" +
        +                "Content-Type: multipart/form-data; boundary=WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW\r\n" +
                         "\r\n" +
                         "--WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW\r\n" +
                         "Content-Disposition: form-data; name=\"part1\"\r\n" +
        @@ -696,10 +686,8 @@ public class MultiPartParserTest
                 parser.parse(data, true);
                 assertThat(parser.getState(), is(State.END));
                 assertThat(handler.fields.size(), is(2));
        -
             }
        -    
        -    
        +
             static class TestHandler implements MultiPartParser.Handler
             {
                 List fields = new ArrayList<>();
        @@ -715,7 +703,9 @@ public class MultiPartParserTest
                 {
                     StringBuilder sb = new StringBuilder();
                     for (String s : content)
        +            {
                         sb.append(s);
        +            }
                     return sb.toString();
                 }
         
        @@ -735,7 +725,7 @@ public class MultiPartParserTest
                         content.add("<>");
                     return last;
                 }
        -        
        +
                 public void clear()
                 {
                     fields.clear();
        diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/PathMapTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/PathMapTest.java
        index b507bd8d348..c5e1b1c52b5 100644
        --- a/jetty-http/src/test/java/org/eclipse/jetty/http/PathMapTest.java
        +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/PathMapTest.java
        @@ -1,6 +1,6 @@
         //
         //  ========================================================================
        -//  Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
        +//  Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
         //  ------------------------------------------------------------------------
         //  All rights reserved. This program and the accompanying materials
         //  are made available under the terms of the Eclipse Public License v1.0
        @@ -18,12 +18,12 @@
         
         package org.eclipse.jetty.http;
         
        +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;
         
        -import org.junit.jupiter.api.Test;
        -
         /**
          *
          */
        @@ -47,26 +47,26 @@ public class PathMapTest
                 p.put("/\u20ACuro/*", "11");
         
                 String[][] tests = {
        -                { "/abs/path", "1"},
        -                { "/abs/path/xxx", "8"},
        -                { "/abs/pith", "8"},
        -                { "/abs/path/longer", "2"},
        -                { "/abs/path/", "8"},
        -                { "/abs/path/xxx", "8"},
        -                { "/animal/bird/eagle/bald", "3"},
        -                { "/animal/fish/shark/grey", "4"},
        -                { "/animal/insect/bug", "5"},
        -                { "/animal", "5"},
        -                { "/animal/", "5"},
        -                { "/animal/x", "5"},
        -                { "/animal/*", "5"},
        -                { "/suffix/path.tar.gz", "6"},
        -                { "/suffix/path.gz", "7"},
        -                { "/animal/path.gz", "5"},
        -                { "/Other/path", "8"},
        -                { "/\u20ACuro/path", "11"},
        -                { "/", "10"},
        -                };
        +            {"/abs/path", "1"},
        +            {"/abs/path/xxx", "8"},
        +            {"/abs/pith", "8"},
        +            {"/abs/path/longer", "2"},
        +            {"/abs/path/", "8"},
        +            {"/abs/path/xxx", "8"},
        +            {"/animal/bird/eagle/bald", "3"},
        +            {"/animal/fish/shark/grey", "4"},
        +            {"/animal/insect/bug", "5"},
        +            {"/animal", "5"},
        +            {"/animal/", "5"},
        +            {"/animal/x", "5"},
        +            {"/animal/*", "5"},
        +            {"/suffix/path.tar.gz", "6"},
        +            {"/suffix/path.gz", "7"},
        +            {"/animal/path.gz", "5"},
        +            {"/Other/path", "8"},
        +            {"/\u20ACuro/path", "11"},
        +            {"/", "10"},
        +            };
         
                 for (String[] test : tests)
                 {
        @@ -138,12 +138,13 @@ public class PathMapTest
                 assertTrue(!PathMap.match("*.foo", "anything.bar"), "!match *.foo");
         
                 assertEquals("10", p.getMatch("/").getValue(), "match / with ''");
        -        
        -        assertTrue(PathMap.match("", "/"),"match \"\"");
        +
        +        assertTrue(PathMap.match("", "/"), "match \"\"");
             }
         
             /**
              * See JIRA issue: JETTY-88.
        +     *
              * @throws Exception failed test
              */
             @Test
        @@ -169,35 +170,33 @@ public class PathMapTest
             public void testPrecidenceVsOrdering() throws Exception
             {
                 PathMap p = new PathMap<>();
        -        p.put("/dump/gzip/*","prefix");
        -        p.put("*.txt","suffix");
        -       
        -        assertEquals(null,p.getMatch("/foo/bar"));
        -        assertEquals("prefix",p.getMatch("/dump/gzip/something").getValue());
        -        assertEquals("suffix",p.getMatch("/foo/something.txt").getValue());
        -        assertEquals("prefix",p.getMatch("/dump/gzip/something.txt").getValue());
        -        
        +        p.put("/dump/gzip/*", "prefix");
        +        p.put("*.txt", "suffix");
        +
        +        assertEquals(null, p.getMatch("/foo/bar"));
        +        assertEquals("prefix", p.getMatch("/dump/gzip/something").getValue());
        +        assertEquals("suffix", p.getMatch("/foo/something.txt").getValue());
        +        assertEquals("prefix", p.getMatch("/dump/gzip/something.txt").getValue());
        +
                 p = new PathMap<>();
        -        p.put("*.txt","suffix");
        -        p.put("/dump/gzip/*","prefix");
        -       
        -        assertEquals(null,p.getMatch("/foo/bar"));
        -        assertEquals("prefix",p.getMatch("/dump/gzip/something").getValue());
        -        assertEquals("suffix",p.getMatch("/foo/something.txt").getValue());
        -        assertEquals("prefix",p.getMatch("/dump/gzip/something.txt").getValue());
        +        p.put("*.txt", "suffix");
        +        p.put("/dump/gzip/*", "prefix");
        +
        +        assertEquals(null, p.getMatch("/foo/bar"));
        +        assertEquals("prefix", p.getMatch("/dump/gzip/something").getValue());
        +        assertEquals("suffix", p.getMatch("/foo/something.txt").getValue());
        +        assertEquals("prefix", p.getMatch("/dump/gzip/something.txt").getValue());
             }
        -    
        -    
        -    
        +
             private void assertMatch(String spec, String path)
             {
                 boolean match = PathMap.match(spec, path);
        -        assertTrue(match,"PathSpec '" + spec + "' should match path '" + path + "'");
        +        assertTrue(match, "PathSpec '" + spec + "' should match path '" + path + "'");
             }
         
             private void assertNotMatch(String spec, String path)
             {
                 boolean match = PathMap.match(spec, path);
        -        assertFalse(match,"PathSpec '" + spec + "' should not match path '" + path + "'");
        +        assertFalse(match, "PathSpec '" + spec + "' should not match path '" + path + "'");
             }
         }
        diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/QuotedCSVTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/QuotedCSVTest.java
        index 29b17a6ccae..e71a178cee5 100644
        --- a/jetty-http/src/test/java/org/eclipse/jetty/http/QuotedCSVTest.java
        +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/QuotedCSVTest.java
        @@ -1,6 +1,6 @@
         //
         //  ========================================================================
        -//  Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
        +//  Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
         //  ------------------------------------------------------------------------
         //  All rights reserved. This program and the accompanying materials
         //  are made available under the terms of the Eclipse Public License v1.0
        @@ -18,13 +18,13 @@
         
         package org.eclipse.jetty.http;
         
        -import static org.hamcrest.Matchers.is;
        -import static org.hamcrest.MatcherAssert.assertThat;
        -
        +import org.eclipse.jetty.util.StringUtil;
         import org.hamcrest.Matchers;
        -
         import org.junit.jupiter.api.Test;
         
        +import static org.hamcrest.MatcherAssert.assertThat;
        +import static org.hamcrest.Matchers.is;
        +
         public class QuotedCSVTest
         {
             @Test
        @@ -32,61 +32,61 @@ public class QuotedCSVTest
             {
                 QuotedCSV values = new QuotedCSV();
                 values.addValue("  value 0.5  ;  pqy = vwz  ;  q =0.5  ,  value 1.0 ,  other ; param ");
        -        assertThat(values,Matchers.contains(
        -                "value 0.5;pqy=vwz;q=0.5",
        -                "value 1.0",
        -                "other;param"));
        +        assertThat(values, Matchers.contains(
        +            "value 0.5;pqy=vwz;q=0.5",
        +            "value 1.0",
        +            "other;param"));
             }
        -    
        +
             @Test
             public void testEmpty()
             {
                 QuotedCSV values = new QuotedCSV();
                 values.addValue(",aaaa,  , bbbb ,,cccc,");
        -        assertThat(values,Matchers.contains(
        -                "aaaa",
        -                "bbbb",
        -                "cccc"));
        +        assertThat(values, Matchers.contains(
        +            "aaaa",
        +            "bbbb",
        +            "cccc"));
             }
        -        
        +
             @Test
             public void testQuoted()
             {
                 QuotedCSV values = new QuotedCSV();
                 values.addValue("A;p=\"v\",B,\"C, D\"");
        -        assertThat(values,Matchers.contains(
        -                "A;p=\"v\"",
        -                "B",
        -                "\"C, D\""));
        +        assertThat(values, Matchers.contains(
        +            "A;p=\"v\"",
        +            "B",
        +            "\"C, D\""));
             }
        -    
        +
             @Test
             public void testOpenQuote()
             {
                 QuotedCSV values = new QuotedCSV();
                 values.addValue("value;p=\"v");
        -        assertThat(values,Matchers.contains(
        -                "value;p=\"v"));
        +        assertThat(values, Matchers.contains(
        +            "value;p=\"v"));
             }
        -    
        +
             @Test
             public void testQuotedNoQuotes()
             {
                 QuotedCSV values = new QuotedCSV(false);
                 values.addValue("A;p=\"v\",B,\"C, D\"");
        -        assertThat(values,Matchers.contains(
        -                "A;p=v",
        -                "B",
        -                "C, D"));
        +        assertThat(values, Matchers.contains(
        +            "A;p=v",
        +            "B",
        +            "C, D"));
             }
        -    
        +
             @Test
             public void testOpenQuoteNoQuotes()
             {
                 QuotedCSV values = new QuotedCSV(false);
                 values.addValue("value;p=\"v");
        -        assertThat(values,Matchers.contains(
        -                "value;p=v"));
        +        assertThat(values, Matchers.contains(
        +            "value;p=v"));
             }
         
             @Test
        @@ -94,10 +94,10 @@ public class QuotedCSVTest
             {
                 QuotedCSV values = new QuotedCSV(false);
                 values.addValue("for=192.0.2.43, for=\"[2001:db8:cafe::17]\", for=unknown");
        -        assertThat(values,Matchers.contains(
        -                "for=192.0.2.43",
        -                "for=[2001:db8:cafe::17]",
        -                "for=unknown"));
        +        assertThat(values, Matchers.contains(
        +            "for=192.0.2.43",
        +            "for=[2001:db8:cafe::17]",
        +            "for=unknown"));
             }
         
             @Test
        @@ -111,13 +111,13 @@ public class QuotedCSVTest
                     {
                         if (buffer.toString().contains("DELETE"))
                         {
        -                    String s = buffer.toString().replace("DELETE","");
        +                    String s = StringUtil.strip(buffer.toString(), "DELETE");
                             buffer.setLength(0);
                             buffer.append(s);
                         }
                         if (buffer.toString().contains("APPEND"))
                         {
        -                    String s = buffer.toString().replace("APPEND","Append")+"!";
        +                    String s = StringUtil.replace(buffer.toString(), "APPEND", "Append") + "!";
                             buffer.setLength(0);
                             buffer.append(s);
                         }
        @@ -126,30 +126,27 @@ public class QuotedCSVTest
                     @Override
                     protected void parsedParam(StringBuffer buffer, int valueLength, int paramName, int paramValue)
                     {
        -                String name = paramValue>0?buffer.substring(paramName,paramValue-1):buffer.substring(paramName);
        +                String name = paramValue > 0 ? buffer.substring(paramName, paramValue - 1) : buffer.substring(paramName);
                         if ("IGNORE".equals(name))
        -                    buffer.setLength(paramName-1);
        +                    buffer.setLength(paramName - 1);
                     }
        -            
                 };
        -            
        +
                 values.addValue("normal;param=val, testAPPENDandDELETEvalue ; n=v; IGNORE = this; x=y ");
        -        assertThat(values,Matchers.contains(
        -                "normal;param=val",
        -                "testAppendandvalue!;n=v;x=y"));
        +        assertThat(values, Matchers.contains(
        +            "normal;param=val",
        +            "testAppendandvalue!;n=v;x=y"));
             }
        -    
        -    
        +
             @Test
             public void testUnQuote()
             {
        -        assertThat(QuotedCSV.unquote(""),is(""));
        -        assertThat(QuotedCSV.unquote("\"\""),is(""));
        -        assertThat(QuotedCSV.unquote("foo"),is("foo"));
        -        assertThat(QuotedCSV.unquote("\"foo\""),is("foo"));
        -        assertThat(QuotedCSV.unquote("f\"o\"o"),is("foo"));
        -        assertThat(QuotedCSV.unquote("\"\\\"foo\""),is("\"foo"));
        -        assertThat(QuotedCSV.unquote("\\foo"),is("\\foo"));
        +        assertThat(QuotedCSV.unquote(""), is(""));
        +        assertThat(QuotedCSV.unquote("\"\""), is(""));
        +        assertThat(QuotedCSV.unquote("foo"), is("foo"));
        +        assertThat(QuotedCSV.unquote("\"foo\""), is("foo"));
        +        assertThat(QuotedCSV.unquote("f\"o\"o"), is("foo"));
        +        assertThat(QuotedCSV.unquote("\"\\\"foo\""), is("\"foo"));
        +        assertThat(QuotedCSV.unquote("\\foo"), is("\\foo"));
             }
        -    
         }
        diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/QuotedQualityCSVTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/QuotedQualityCSVTest.java
        index 334cb5b9a87..67497db75df 100644
        --- a/jetty-http/src/test/java/org/eclipse/jetty/http/QuotedQualityCSVTest.java
        +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/QuotedQualityCSVTest.java
        @@ -1,6 +1,6 @@
         //
         //  ========================================================================
        -//  Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
        +//  Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
         //  ------------------------------------------------------------------------
         //  All rights reserved. This program and the accompanying materials
         //  are made available under the terms of the Eclipse Public License v1.0
        @@ -18,13 +18,12 @@
         
         package org.eclipse.jetty.http;
         
        +import java.util.ArrayList;
        +import java.util.List;
         
         import org.hamcrest.Matchers;
         import org.junit.jupiter.api.Test;
         
        -import java.util.ArrayList;
        -import java.util.List;
        -
         import static org.hamcrest.MatcherAssert.assertThat;
         import static org.hamcrest.Matchers.contains;
         
        @@ -36,7 +35,7 @@ public class QuotedQualityCSVTest
             {
                 QuotedQualityCSV values = new QuotedQualityCSV();
                 values.addValue(" audio/*; q=0.2, audio/basic");
        -        assertThat(values,Matchers.contains("audio/basic","audio/*"));
        +        assertThat(values, Matchers.contains("audio/basic", "audio/*"));
             }
         
             @Test
        @@ -45,43 +44,43 @@ public class QuotedQualityCSVTest
                 QuotedQualityCSV values = new QuotedQualityCSV();
                 values.addValue("text/plain; q=0.5, text/html,");
                 values.addValue("text/x-dvi; q=0.8, text/x-c");
        -        assertThat(values,Matchers.contains("text/html","text/x-c","text/x-dvi","text/plain"));
        +        assertThat(values, Matchers.contains("text/html", "text/x-c", "text/x-dvi", "text/plain"));
             }
        -    
        +
             @Test
             public void test7231_5_3_2_example3()
             {
                 QuotedQualityCSV values = new QuotedQualityCSV();
                 values.addValue("text/*, text/plain, text/plain;format=flowed, */*");
        -        
        +
                 // Note this sort is only on quality and not the most specific type as per 5.3.2
        -        assertThat(values,Matchers.contains("text/*","text/plain","text/plain;format=flowed","*/*"));
        +        assertThat(values, Matchers.contains("text/*", "text/plain", "text/plain;format=flowed", "*/*"));
             }
        -    
        +
             @Test
             public void test7231_5_3_2_example3_most_specific()
             {
        -        QuotedQualityCSV values = new QuotedQualityCSV(QuotedQualityCSV.MOST_SPECIFIC);
        +        QuotedQualityCSV values = new QuotedQualityCSV(QuotedQualityCSV.MOST_SPECIFIC_MIME_ORDERING);
                 values.addValue("text/*, text/plain, text/plain;format=flowed, */*");
        -        
        -        assertThat(values,Matchers.contains("text/plain;format=flowed","text/plain","text/*","*/*"));
        +
        +        assertThat(values, Matchers.contains("text/plain;format=flowed", "text/plain", "text/*", "*/*"));
             }
        -    
        +
             @Test
             public void test7231_5_3_2_example4()
             {
                 QuotedQualityCSV values = new QuotedQualityCSV();
                 values.addValue("text/*;q=0.3, text/html;q=0.7, text/html;level=1,");
                 values.addValue("text/html;level=2;q=0.4, */*;q=0.5");
        -        assertThat(values,Matchers.contains(
        -                "text/html;level=1",
        -                "text/html",
        -                "*/*",
        -                "text/html;level=2",
        -                "text/*"
        -                ));
        +        assertThat(values, Matchers.contains(
        +            "text/html;level=1",
        +            "text/html",
        +            "*/*",
        +            "text/html;level=2",
        +            "text/*"
        +        ));
             }
        -    
        +
             @Test
             public void test7231_5_3_4_example1()
             {
        @@ -91,16 +90,16 @@ public class QuotedQualityCSVTest
                 values.addValue("*");
                 values.addValue("compress;q=0.5, gzip;q=1.0");
                 values.addValue("gzip;q=1.0, identity; q=0.5, *;q=0");
        -        
        -        assertThat(values,Matchers.contains(
        -                "compress",
        -                "gzip",
        -                "*",
        -                "gzip",
        -                "gzip",
        -                "compress",
        -                "identity"
        -                ));
        +
        +        assertThat(values, Matchers.contains(
        +            "compress",
        +            "gzip",
        +            "*",
        +            "gzip",
        +            "gzip",
        +            "compress",
        +            "identity"
        +        ));
             }
         
             @Test
        @@ -108,66 +107,65 @@ public class QuotedQualityCSVTest
             {
                 QuotedQualityCSV values = new QuotedQualityCSV();
                 values.addValue("  value 0.5  ;  p = v  ;  q =0.5  ,  value 1.0 ");
        -        assertThat(values,Matchers.contains(
        -                "value 1.0",
        -                "value 0.5;p=v"));
        +        assertThat(values, Matchers.contains(
        +            "value 1.0",
        +            "value 0.5;p=v"));
             }
        -    
        +
             @Test
             public void testEmpty()
             {
                 QuotedQualityCSV values = new QuotedQualityCSV();
                 values.addValue(",aaaa,  , bbbb ,,cccc,");
        -        assertThat(values,Matchers.contains(
        -                "aaaa",
        -                "bbbb",
        -                "cccc"));
        +        assertThat(values, Matchers.contains(
        +            "aaaa",
        +            "bbbb",
        +            "cccc"));
             }
        -        
        +
             @Test
             public void testQuoted()
             {
                 QuotedQualityCSV values = new QuotedQualityCSV();
                 values.addValue("  value 0.5  ;  p = \"v  ;  q = \\\"0.5\\\"  ,  value 1.0 \"  ");
        -        assertThat(values,Matchers.contains(
        -                "value 0.5;p=\"v  ;  q = \\\"0.5\\\"  ,  value 1.0 \""));
        +        assertThat(values, Matchers.contains(
        +            "value 0.5;p=\"v  ;  q = \\\"0.5\\\"  ,  value 1.0 \""));
             }
        -    
        +
             @Test
             public void testOpenQuote()
             {
                 QuotedQualityCSV values = new QuotedQualityCSV();
                 values.addValue("value;p=\"v");
        -        assertThat(values,Matchers.contains(
        -                "value;p=\"v"));
        +        assertThat(values, Matchers.contains(
        +            "value;p=\"v"));
             }
        -    
        +
             @Test
             public void testQuotedQuality()
             {
                 QuotedQualityCSV values = new QuotedQualityCSV();
                 values.addValue("  value 0.5  ;  p = v  ;  q = \"0.5\"  ,  value 1.0 ");
        -        assertThat(values,Matchers.contains(
        -                "value 1.0",
        -                "value 0.5;p=v"));
        +        assertThat(values, Matchers.contains(
        +            "value 1.0",
        +            "value 0.5;p=v"));
             }
        -    
        +
             @Test
             public void testBadQuality()
             {
                 QuotedQualityCSV values = new QuotedQualityCSV();
                 values.addValue("value0.5;p=v;q=0.5,value1.0,valueBad;q=X");
        -        assertThat(values,Matchers.contains(
        -                "value1.0",
        -                "value0.5;p=v"));
        +        assertThat(values, Matchers.contains(
        +            "value1.0",
        +            "value0.5;p=v"));
             }
        -    
        +
             @Test
             public void testBad()
             {
                 QuotedQualityCSV values = new QuotedQualityCSV();
         
        -        
                 // None of these should throw exceptions
                 values.addValue(null);
                 values.addValue("");
        @@ -223,13 +221,10 @@ public class QuotedQualityCSVTest
                 values.addValue("q=");
                 values.addValue("q=,");
                 values.addValue("q=;");
        -        
             }
         
        -    /* ------------------------------------------------------------ */
        -
        -    private static final String[] preferBrotli = {"br","gzip"};
        -    private static final String[] preferGzip = {"gzip","br"};
        +    private static final String[] preferBrotli = {"br", "gzip"};
        +    private static final String[] preferGzip = {"gzip", "br"};
             private static final String[] noFormats = {};
         
             @Test
        @@ -295,14 +290,13 @@ public class QuotedQualityCSVTest
                 values.addValue("gzip, *");
                 assertThat(values, contains("*", "gzip"));
             }
        -    
         
             @Test
             public void testSameQuality()
             {
                 QuotedQualityCSV values = new QuotedQualityCSV();
                 values.addValue("one;q=0.5,two;q=0.5,three;q=0.5");
        -        assertThat(values.getValues(),Matchers.contains("one","two","three"));
        +        assertThat(values.getValues(), Matchers.contains("one", "two", "three"));
             }
         
             @Test
        @@ -310,10 +304,9 @@ public class QuotedQualityCSVTest
             {
                 QuotedQualityCSV values = new QuotedQualityCSV();
                 values.addValue("one,two;,three;x=y");
        -        assertThat(values.getValues(),Matchers.contains("one","two","three;x=y"));
        +        assertThat(values.getValues(), Matchers.contains("one", "two", "three;x=y"));
             }
         
        -
             @Test
             public void testQuality()
             {
        @@ -339,19 +332,15 @@ public class QuotedQualityCSVTest
                     }
                 };
         
        -
                 // The provided string is not legal according to some RFCs ( not a token because of = and not a parameter because not preceded by ; )
                 // The string is legal according to RFC7239 which allows for just parameters (called forwarded-pairs)
                 values.addValue("p=0.5,q=0.5");
         
        -
                 // The QuotedCSV implementation is lenient and adopts the later interpretation and thus sees q=0.5 and p=0.5 both as parameters
        -        assertThat(results,contains("parsedValue: ", "parsedParam: p=0.5",
        -                                    "parsedValue: ", "parsedParam: q=0.5"));
        -
        +        assertThat(results, contains("parsedValue: ", "parsedParam: p=0.5",
        +            "parsedValue: ", "parsedParam: q=0.5"));
         
                 // However the QuotedQualityCSV only handles the q parameter and that is consumed from the parameter string.
        -        assertThat(values,contains("p=0.5", ""));
        -
        +        assertThat(values, contains("p=0.5", ""));
             }
         }
        diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/SyntaxTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/SyntaxTest.java
        index 173d3d1d548..019aa158214 100644
        --- a/jetty-http/src/test/java/org/eclipse/jetty/http/SyntaxTest.java
        +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/SyntaxTest.java
        @@ -1,6 +1,6 @@
         //
         //  ========================================================================
        -//  Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
        +//  Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
         //  ------------------------------------------------------------------------
         //  All rights reserved. This program and the accompanying materials
         //  are made available under the terms of the Eclipse Public License v1.0
        @@ -18,52 +18,52 @@
         
         package org.eclipse.jetty.http;
         
        -import static org.hamcrest.CoreMatchers.allOf;
        -import static org.hamcrest.CoreMatchers.containsString;
        -import static org.hamcrest.MatcherAssert.assertThat;
        -import static org.junit.jupiter.api.Assertions.fail;
        -
         import org.junit.jupiter.api.Test;
         
        +import static org.hamcrest.MatcherAssert.assertThat;
        +import static org.hamcrest.Matchers.allOf;
        +import static org.hamcrest.Matchers.containsString;
        +import static org.junit.jupiter.api.Assertions.fail;
        +
         public class SyntaxTest
         {
             @Test
             public void testRequireValidRFC2616Token_Good()
             {
        -        String tokens[] = {
        -                "name",
        -                "",
        -                null,
        -                "n.a.m.e",
        -                "na-me",
        -                "+name",
        -                "na*me",
        -                "na$me",
        -                "#name"
        +        String[] tokens = {
        +            "name",
        +            "",
        +            null,
        +            "n.a.m.e",
        +            "na-me",
        +            "+name",
        +            "na*me",
        +            "na$me",
        +            "#name"
                 };
        -        
        +
                 for (String token : tokens)
                 {
                     Syntax.requireValidRFC2616Token(token, "Test Based");
                     // No exception should occur here
                 }
             }
        -    
        +
             @Test
             public void testRequireValidRFC2616Token_Bad()
             {
        -        String tokens[] = {
        -                "\"name\"",
        -                "name\t",
        -                "na me",
        -                "name\u0082",
        -                "na\tme",
        -                "na;me",
        -                "{name}",
        -                "[name]",
        -                "\""
        +        String[] tokens = {
        +            "\"name\"",
        +            "name\t",
        +            "na me",
        +            "name\u0082",
        +            "na\tme",
        +            "na;me",
        +            "{name}",
        +            "[name]",
        +            "\""
                 };
        -        
        +
                 for (String token : tokens)
                 {
                     try
        @@ -74,50 +74,50 @@ public class SyntaxTest
                     catch (IllegalArgumentException e)
                     {
                         assertThat("Testing Bad RFC2616 Token [" + token + "]", e.getMessage(),
        -                        allOf(containsString("Test Based"),
        -                                containsString("RFC2616")));
        +                    allOf(containsString("Test Based"),
        +                        containsString("RFC2616")));
                     }
                 }
             }
        -    
        +
             @Test
             public void testRequireValidRFC6265CookieValue_Good()
             {
        -        String values[] = {
        -                "value",
        -                "",
        -                null,
        -                "val=ue",
        -                "val-ue",
        -                "\"value\"",
        -                "val/ue",
        -                "v.a.l.u.e"
        +        String[] values = {
        +            "value",
        +            "",
        +            null,
        +            "val=ue",
        +            "val-ue",
        +            "\"value\"",
        +            "val/ue",
        +            "v.a.l.u.e"
                 };
        -        
        +
                 for (String value : values)
                 {
                     Syntax.requireValidRFC6265CookieValue(value);
                     // No exception should occur here
                 }
             }
        -    
        +
             @Test
             public void testRequireValidRFC6265CookieValue_Bad()
             {
        -        String values[] = {
        -                "va\tlue",
        -                "\t",
        -                "value\u0000",
        -                "val\u0082ue",
        -                "va lue",
        -                "va;lue",
        -                "\"value",
        -                "value\"",
        -                "val\\ue",
        -                "val\"ue",
        -                "\""
        +        String[] values = {
        +            "va\tlue",
        +            "\t",
        +            "value\u0000",
        +            "val\u0082ue",
        +            "va lue",
        +            "va;lue",
        +            "\"value",
        +            "value\"",
        +            "val\\ue",
        +            "val\"ue",
        +            "\""
                 };
        -        
        +
                 for (String value : values)
                 {
                     try
        diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/matchers/HttpFieldsContainsHeaderKey.java b/jetty-http/src/test/java/org/eclipse/jetty/http/matchers/HttpFieldsContainsHeaderKey.java
        index b4ef5f11e39..1425bf1e5c8 100644
        --- a/jetty-http/src/test/java/org/eclipse/jetty/http/matchers/HttpFieldsContainsHeaderKey.java
        +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/matchers/HttpFieldsContainsHeaderKey.java
        @@ -1,6 +1,6 @@
         //
         //  ========================================================================
        -//  Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
        +//  Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
         //  ------------------------------------------------------------------------
         //  All rights reserved. This program and the accompanying materials
         //  are made available under the terms of the Eclipse Public License v1.0
        @@ -21,7 +21,6 @@ package org.eclipse.jetty.http.matchers;
         import org.eclipse.jetty.http.HttpFields;
         import org.eclipse.jetty.http.HttpHeader;
         import org.hamcrest.Description;
        -import org.hamcrest.Factory;
         import org.hamcrest.Matcher;
         import org.hamcrest.TypeSafeMatcher;
         
        @@ -51,8 +50,8 @@ public class HttpFieldsContainsHeaderKey extends TypeSafeMatcher
                 return fields.containsKey(this.keyName);
             }
         
        -    @Factory
        -    public static Matcher containsKey(String keyName) {
        +    public static Matcher containsKey(String keyName)
        +    {
                 return new HttpFieldsContainsHeaderKey(keyName);
             }
         }
        diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/matchers/HttpFieldsContainsHeaderValue.java b/jetty-http/src/test/java/org/eclipse/jetty/http/matchers/HttpFieldsContainsHeaderValue.java
        index 1e8389089f1..bf7f2536928 100644
        --- a/jetty-http/src/test/java/org/eclipse/jetty/http/matchers/HttpFieldsContainsHeaderValue.java
        +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/matchers/HttpFieldsContainsHeaderValue.java
        @@ -1,6 +1,6 @@
         //
         //  ========================================================================
        -//  Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
        +//  Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
         //  ------------------------------------------------------------------------
         //  All rights reserved. This program and the accompanying materials
         //  are made available under the terms of the Eclipse Public License v1.0
        @@ -60,7 +60,7 @@ public class HttpFieldsContainsHeaderValue extends TypeSafeMatcher
                     return true;
         
                 // Simple equals
        -        if(this.value == field.getValue())
        +        if (this.value == field.getValue())
                     return true;
         
                 // Try individual value logic
        diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/matchers/HttpFieldsMatchersTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/matchers/HttpFieldsMatchersTest.java
        index 895049a797f..16b0ae3c978 100644
        --- a/jetty-http/src/test/java/org/eclipse/jetty/http/matchers/HttpFieldsMatchersTest.java
        +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/matchers/HttpFieldsMatchersTest.java
        @@ -1,6 +1,6 @@
         //
         //  ========================================================================
        -//  Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
        +//  Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
         //  ------------------------------------------------------------------------
         //  All rights reserved. This program and the accompanying materials
         //  are made available under the terms of the Eclipse Public License v1.0
        @@ -18,6 +18,10 @@
         
         package org.eclipse.jetty.http.matchers;
         
        +import org.eclipse.jetty.http.HttpFields;
        +import org.eclipse.jetty.http.HttpHeader;
        +import org.junit.jupiter.api.Test;
        +
         import static org.eclipse.jetty.http.HttpFieldsMatchers.containsHeader;
         import static org.eclipse.jetty.http.HttpFieldsMatchers.containsHeaderValue;
         import static org.hamcrest.MatcherAssert.assertThat;
        @@ -25,10 +29,6 @@ import static org.hamcrest.Matchers.containsString;
         import static org.hamcrest.Matchers.not;
         import static org.junit.jupiter.api.Assertions.assertThrows;
         
        -import org.eclipse.jetty.http.HttpFields;
        -import org.eclipse.jetty.http.HttpHeader;
        -import org.junit.jupiter.api.Test;
        -
         public class HttpFieldsMatchersTest
         {
             @Test
        @@ -50,7 +50,8 @@ public class HttpFieldsMatchersTest
                 fields.put("b", "bar");
                 fields.put("c", "fizz");
         
        -        AssertionError x = assertThrows(AssertionError.class, ()-> {
        +        AssertionError x = assertThrows(AssertionError.class, () ->
        +        {
                     assertThat(fields, not(containsHeader("a")));
                 });
         
        @@ -65,7 +66,8 @@ public class HttpFieldsMatchersTest
                 fields.put("b", "bar");
                 fields.put("c", "fizz");
         
        -        AssertionError x = assertThrows(AssertionError.class, ()->{
        +        AssertionError x = assertThrows(AssertionError.class, () ->
        +        {
                     assertThat(fields, containsHeader("z"));
                 });
         
        @@ -80,7 +82,8 @@ public class HttpFieldsMatchersTest
                 fields.put("b", "bar");
                 fields.put("c", "fizz");
         
        -        AssertionError x = assertThrows(AssertionError.class, ()-> {
        +        AssertionError x = assertThrows(AssertionError.class, () ->
        +        {
                     assertThat(fields, containsHeaderValue("z", "floom"));
                 });
         
        @@ -95,7 +98,8 @@ public class HttpFieldsMatchersTest
                 fields.put("b", "bar");
                 fields.put("c", "fizz");
         
        -        AssertionError x = assertThrows(AssertionError.class, ()-> {
        +        AssertionError x = assertThrows(AssertionError.class, () ->
        +        {
                     assertThat(fields, containsHeaderValue("a", "floom"));
                 });
         
        diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/PathMappingsTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/PathMappingsTest.java
        index 6ca1022c6cf..018dc430f43 100644
        --- a/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/PathMappingsTest.java
        +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/PathMappingsTest.java
        @@ -1,6 +1,6 @@
         //
         //  ========================================================================
        -//  Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
        +//  Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
         //  ------------------------------------------------------------------------
         //  All rights reserved. This program and the accompanying materials
         //  are made available under the terms of the Eclipse Public License v1.0
        @@ -18,32 +18,32 @@
         
         package org.eclipse.jetty.http.pathmap;
         
        +import org.junit.jupiter.api.Test;
        +import org.junit.jupiter.params.ParameterizedTest;
        +import org.junit.jupiter.params.provider.ValueSource;
        +
         import static org.hamcrest.MatcherAssert.assertThat;
         import static org.hamcrest.Matchers.notNullValue;
         import static org.junit.jupiter.api.Assertions.assertEquals;
         import static org.junit.jupiter.api.Assertions.assertThrows;
         import static org.junit.jupiter.api.Assertions.assertTrue;
         
        -import org.junit.jupiter.api.Test;
        -import org.junit.jupiter.params.ParameterizedTest;
        -import org.junit.jupiter.params.provider.ValueSource;
        -
         public class PathMappingsTest
         {
             private void assertMatch(PathMappings pathmap, String path, String expectedValue)
             {
        -        String msg = String.format(".getMatch(\"%s\")",path);
        +        String msg = String.format(".getMatch(\"%s\")", path);
                 MappedResource match = pathmap.getMatch(path);
        -        assertThat(msg,match,notNullValue());
        +        assertThat(msg, match, notNullValue());
                 String actualMatch = match.getResource();
        -        assertEquals(expectedValue,actualMatch,msg);
        +        assertEquals(expectedValue, actualMatch, msg);
             }
         
             public void dumpMappings(PathMappings p)
             {
                 for (MappedResource res : p)
                 {
        -            System.out.printf("  %s%n",res);
        +            System.out.printf("  %s%n", res);
                 }
             }
         
        @@ -61,26 +61,26 @@ public class PathMappingsTest
             {
                 PathMappings p = new PathMappings<>();
         
        -        p.put(new ServletPathSpec("/"),"default");
        -        p.put(new ServletPathSpec("/animal/bird/*"),"birds");
        -        p.put(new ServletPathSpec("/animal/fish/*"),"fishes");
        -        p.put(new ServletPathSpec("/animal/*"),"animals");
        -        p.put(new RegexPathSpec("^/animal/.*/chat$"),"animalChat");
        -        p.put(new RegexPathSpec("^/animal/.*/cam$"),"animalCam");
        -        p.put(new RegexPathSpec("^/entrance/cam$"),"entranceCam");
        +        p.put(new ServletPathSpec("/"), "default");
        +        p.put(new ServletPathSpec("/animal/bird/*"), "birds");
        +        p.put(new ServletPathSpec("/animal/fish/*"), "fishes");
        +        p.put(new ServletPathSpec("/animal/*"), "animals");
        +        p.put(new RegexPathSpec("^/animal/.*/chat$"), "animalChat");
        +        p.put(new RegexPathSpec("^/animal/.*/cam$"), "animalCam");
        +        p.put(new RegexPathSpec("^/entrance/cam$"), "entranceCam");
         
                 // dumpMappings(p);
         
        -        assertMatch(p,"/animal/bird/eagle","birds");
        -        assertMatch(p,"/animal/fish/bass/sea","fishes");
        -        assertMatch(p,"/animal/peccary/javalina/evolution","animals");
        -        assertMatch(p,"/","default");
        -        assertMatch(p,"/animal/bird/eagle/chat","animalChat");
        -        assertMatch(p,"/animal/bird/penguin/chat","animalChat");
        -        assertMatch(p,"/animal/fish/trout/cam","animalCam");
        -        assertMatch(p,"/entrance/cam","entranceCam");
        +        assertMatch(p, "/animal/bird/eagle", "birds");
        +        assertMatch(p, "/animal/fish/bass/sea", "fishes");
        +        assertMatch(p, "/animal/peccary/javalina/evolution", "animals");
        +        assertMatch(p, "/", "default");
        +        assertMatch(p, "/animal/bird/eagle/chat", "animalChat");
        +        assertMatch(p, "/animal/bird/penguin/chat", "animalChat");
        +        assertMatch(p, "/animal/fish/trout/cam", "animalCam");
        +        assertMatch(p, "/entrance/cam", "entranceCam");
             }
        -    
        +
             /**
              * Test the match order rules imposed by the Servlet API (default vs any)
              */
        @@ -89,15 +89,15 @@ public class PathMappingsTest
             {
                 PathMappings p = new PathMappings<>();
         
        -        p.put(new ServletPathSpec("/"),"default");
        -        p.put(new ServletPathSpec("/*"),"any"); 
        +        p.put(new ServletPathSpec("/"), "default");
        +        p.put(new ServletPathSpec("/*"), "any");
         
        -        assertMatch(p,"/abs/path","any");
        -        assertMatch(p,"/abs/path/xxx","any");
        -        assertMatch(p,"/animal/bird/eagle/bald","any");
        -        assertMatch(p,"/","any");
        +        assertMatch(p, "/abs/path", "any");
        +        assertMatch(p, "/abs/path/xxx", "any");
        +        assertMatch(p, "/animal/bird/eagle/bald", "any");
        +        assertMatch(p, "/", "any");
             }
        -    
        +
             /**
              * Test the match order rules with a mixed Servlet and URI Template path specs
              * 

        @@ -112,24 +112,24 @@ public class PathMappingsTest { PathMappings p = new PathMappings<>(); - p.put(new ServletPathSpec("/"),"default"); - p.put(new ServletPathSpec("/animal/bird/*"),"birds"); - p.put(new ServletPathSpec("/animal/fish/*"),"fishes"); - p.put(new ServletPathSpec("/animal/*"),"animals"); - p.put(new UriTemplatePathSpec("/animal/{type}/{name}/chat"),"animalChat"); - p.put(new UriTemplatePathSpec("/animal/{type}/{name}/cam"),"animalCam"); - p.put(new UriTemplatePathSpec("/entrance/cam"),"entranceCam"); + p.put(new ServletPathSpec("/"), "default"); + p.put(new ServletPathSpec("/animal/bird/*"), "birds"); + p.put(new ServletPathSpec("/animal/fish/*"), "fishes"); + p.put(new ServletPathSpec("/animal/*"), "animals"); + p.put(new UriTemplatePathSpec("/animal/{type}/{name}/chat"), "animalChat"); + p.put(new UriTemplatePathSpec("/animal/{type}/{name}/cam"), "animalCam"); + p.put(new UriTemplatePathSpec("/entrance/cam"), "entranceCam"); // dumpMappings(p); - assertMatch(p,"/animal/bird/eagle","birds"); - assertMatch(p,"/animal/fish/bass/sea","fishes"); - assertMatch(p,"/animal/peccary/javalina/evolution","animals"); - assertMatch(p,"/","default"); - assertMatch(p,"/animal/bird/eagle/chat","animalChat"); - assertMatch(p,"/animal/bird/penguin/chat","animalChat"); - assertMatch(p,"/animal/fish/trout/cam","animalCam"); - assertMatch(p,"/entrance/cam","entranceCam"); + assertMatch(p, "/animal/bird/eagle", "birds"); + assertMatch(p, "/animal/fish/bass/sea", "fishes"); + assertMatch(p, "/animal/peccary/javalina/evolution", "animals"); + assertMatch(p, "/", "default"); + assertMatch(p, "/animal/bird/eagle/chat", "animalChat"); + assertMatch(p, "/animal/bird/penguin/chat", "animalChat"); + assertMatch(p, "/animal/fish/trout/cam", "animalCam"); + assertMatch(p, "/entrance/cam", "entranceCam"); } /** @@ -146,19 +146,19 @@ public class PathMappingsTest { PathMappings p = new PathMappings<>(); - p.put(new UriTemplatePathSpec("/a/{var}/c"),"endpointA"); - p.put(new UriTemplatePathSpec("/a/b/c"),"endpointB"); - p.put(new UriTemplatePathSpec("/a/{var1}/{var2}"),"endpointC"); - p.put(new UriTemplatePathSpec("/{var1}/d"),"endpointD"); - p.put(new UriTemplatePathSpec("/b/{var2}"),"endpointE"); + p.put(new UriTemplatePathSpec("/a/{var}/c"), "endpointA"); + p.put(new UriTemplatePathSpec("/a/b/c"), "endpointB"); + p.put(new UriTemplatePathSpec("/a/{var1}/{var2}"), "endpointC"); + p.put(new UriTemplatePathSpec("/{var1}/d"), "endpointD"); + p.put(new UriTemplatePathSpec("/b/{var2}"), "endpointE"); // dumpMappings(p); - assertMatch(p,"/a/b/c","endpointB"); - assertMatch(p,"/a/d/c","endpointA"); - assertMatch(p,"/a/x/y","endpointC"); + assertMatch(p, "/a/b/c", "endpointB"); + assertMatch(p, "/a/d/c", "endpointA"); + assertMatch(p, "/a/x/y", "endpointC"); - assertMatch(p,"/b/d","endpointE"); + assertMatch(p, "/b/d", "endpointE"); } @Test @@ -192,7 +192,7 @@ public class PathMappingsTest assertEquals(null, new ServletPathSpec("/Foo/*").getPathInfo("/Foo"), "pathInfo prefix"); assertEquals(null, new ServletPathSpec("*.ext").getPathInfo("/Foo/bar.ext"), "pathInfo suffix"); assertEquals(null, new ServletPathSpec("/").getPathInfo("/Foo/bar.ext"), "pathInfo default"); - + p.put(new ServletPathSpec("/*"), "0"); // assertEquals("1", p.get("/abs/path"), "Get absolute path"); @@ -233,12 +233,13 @@ public class PathMappingsTest assertTrue(!new ServletPathSpec("*.foo").matches("anything.bar"), "!match *.foo"); assertEquals("10", p.getMatch("/").getResource(), "match / with ''"); - - assertTrue(new ServletPathSpec("").matches("/"),"match \"\""); + + assertTrue(new ServletPathSpec("").matches("/"), "match \"\""); } /** * See JIRA issue: JETTY-88. + * * @throws Exception failed test */ @Test @@ -264,35 +265,36 @@ public class PathMappingsTest public void testPrecidenceVsOrdering() throws Exception { PathMappings p = new PathMappings<>(); - p.put(new ServletPathSpec("/dump/gzip/*"),"prefix"); - p.put(new ServletPathSpec("*.txt"),"suffix"); - - assertEquals(null,p.getMatch("/foo/bar")); - assertEquals("prefix",p.getMatch("/dump/gzip/something").getResource()); - assertEquals("suffix",p.getMatch("/foo/something.txt").getResource()); - assertEquals("prefix",p.getMatch("/dump/gzip/something.txt").getResource()); - + p.put(new ServletPathSpec("/dump/gzip/*"), "prefix"); + p.put(new ServletPathSpec("*.txt"), "suffix"); + + assertEquals(null, p.getMatch("/foo/bar")); + assertEquals("prefix", p.getMatch("/dump/gzip/something").getResource()); + assertEquals("suffix", p.getMatch("/foo/something.txt").getResource()); + assertEquals("prefix", p.getMatch("/dump/gzip/something.txt").getResource()); + p = new PathMappings<>(); - p.put(new ServletPathSpec("*.txt"),"suffix"); - p.put(new ServletPathSpec("/dump/gzip/*"),"prefix"); - - assertEquals(null,p.getMatch("/foo/bar")); - assertEquals("prefix",p.getMatch("/dump/gzip/something").getResource()); - assertEquals("suffix",p.getMatch("/foo/something.txt").getResource()); - assertEquals("prefix",p.getMatch("/dump/gzip/something.txt").getResource()); + p.put(new ServletPathSpec("*.txt"), "suffix"); + p.put(new ServletPathSpec("/dump/gzip/*"), "prefix"); + + assertEquals(null, p.getMatch("/foo/bar")); + assertEquals("prefix", p.getMatch("/dump/gzip/something").getResource()); + assertEquals("suffix", p.getMatch("/foo/something.txt").getResource()); + assertEquals("prefix", p.getMatch("/dump/gzip/something.txt").getResource()); } - + @ParameterizedTest @ValueSource(strings = { - "*", - "/foo/*/bar", - "/foo*", - "*/foo", - "*.foo/*" + "*", + "/foo/*/bar", + "/foo*", + "*/foo", + "*.foo/*" }) public void testBadPathSpecs(String str) { - assertThrows(IllegalArgumentException.class, ()->{ + assertThrows(IllegalArgumentException.class, () -> + { new ServletPathSpec(str); }); } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/PathSpecAssert.java b/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/PathSpecAssert.java index 1770db67923..086a72d9ee9 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/PathSpecAssert.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/PathSpecAssert.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,8 +18,8 @@ package org.eclipse.jetty.http.pathmap; -import static org.hamcrest.Matchers.is; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; public class PathSpecAssert { diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/RegexPathSpecTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/RegexPathSpecTest.java index 6771a27f300..de09d9429cf 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/RegexPathSpecTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/RegexPathSpecTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,24 +18,24 @@ package org.eclipse.jetty.http.pathmap; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.hamcrest.MatcherAssert.assertThat; - -import org.junit.jupiter.api.Test; public class RegexPathSpecTest { public static void assertMatches(PathSpec spec, String path) { - String msg = String.format("Spec(\"%s\").matches(\"%s\")",spec.getDeclaration(),path); - assertThat(msg,spec.matches(path),is(true)); + String msg = String.format("Spec(\"%s\").matches(\"%s\")", spec.getDeclaration(), path); + assertThat(msg, spec.matches(path), is(true)); } public static void assertNotMatches(PathSpec spec, String path) { - String msg = String.format("!Spec(\"%s\").matches(\"%s\")",spec.getDeclaration(),path); - assertThat(msg,spec.matches(path),is(false)); + String msg = String.format("!Spec(\"%s\").matches(\"%s\")", spec.getDeclaration(), path); + assertThat(msg, spec.matches(path), is(false)); } @Test @@ -47,10 +47,10 @@ public class RegexPathSpecTest assertEquals(1, spec.getPathDepth(), "Spec.pathDepth"); assertEquals(PathSpecGroup.EXACT, spec.group, "Spec.group"); - assertMatches(spec,"/a"); + assertMatches(spec, "/a"); - assertNotMatches(spec,"/aa"); - assertNotMatches(spec,"/a/"); + assertNotMatches(spec, "/aa"); + assertNotMatches(spec, "/a/"); } @Test @@ -62,16 +62,16 @@ public class RegexPathSpecTest assertEquals(3, spec.getPathDepth(), "Spec.pathDepth"); assertEquals(PathSpecGroup.MIDDLE_GLOB, spec.group, "Spec.group"); - assertMatches(spec,"/rest/api/list"); - assertMatches(spec,"/rest/1.0/list"); - assertMatches(spec,"/rest/2.0/list"); - assertMatches(spec,"/rest/accounts/list"); + assertMatches(spec, "/rest/api/list"); + assertMatches(spec, "/rest/1.0/list"); + assertMatches(spec, "/rest/2.0/list"); + assertMatches(spec, "/rest/accounts/list"); - assertNotMatches(spec,"/a"); - assertNotMatches(spec,"/aa"); - assertNotMatches(spec,"/aa/bb"); - assertNotMatches(spec,"/rest/admin/delete"); - assertNotMatches(spec,"/rest/list"); + assertNotMatches(spec, "/a"); + assertNotMatches(spec, "/aa"); + assertNotMatches(spec, "/aa/bb"); + assertNotMatches(spec, "/rest/admin/delete"); + assertNotMatches(spec, "/rest/list"); } @Test @@ -83,16 +83,16 @@ public class RegexPathSpecTest assertEquals(3, spec.getPathDepth(), "Spec.pathDepth"); assertEquals(PathSpecGroup.MIDDLE_GLOB, spec.group, "Spec.group"); - assertMatches(spec,"/rest/api/list"); - assertMatches(spec,"/rest/1.0/list"); - assertMatches(spec,"/rest/2.0/list"); - assertMatches(spec,"/rest/accounts/list"); + assertMatches(spec, "/rest/api/list"); + assertMatches(spec, "/rest/1.0/list"); + assertMatches(spec, "/rest/2.0/list"); + assertMatches(spec, "/rest/accounts/list"); - assertNotMatches(spec,"/a"); - assertNotMatches(spec,"/aa"); - assertNotMatches(spec,"/aa/bb"); - assertNotMatches(spec,"/rest/admin/delete"); - assertNotMatches(spec,"/rest/list"); + assertNotMatches(spec, "/a"); + assertNotMatches(spec, "/aa"); + assertNotMatches(spec, "/aa/bb"); + assertNotMatches(spec, "/rest/admin/delete"); + assertNotMatches(spec, "/rest/list"); } @Test @@ -104,13 +104,13 @@ public class RegexPathSpecTest assertEquals(2, spec.getPathDepth(), "Spec.pathDepth"); assertEquals(PathSpecGroup.PREFIX_GLOB, spec.group, "Spec.group"); - assertMatches(spec,"/a/"); - assertMatches(spec,"/a/b"); - assertMatches(spec,"/a/b/c/d/e"); + assertMatches(spec, "/a/"); + assertMatches(spec, "/a/b"); + assertMatches(spec, "/a/b/c/d/e"); - assertNotMatches(spec,"/a"); - assertNotMatches(spec,"/aa"); - assertNotMatches(spec,"/aa/bb"); + assertNotMatches(spec, "/a"); + assertNotMatches(spec, "/aa"); + assertNotMatches(spec, "/aa/bb"); } @Test @@ -122,14 +122,14 @@ public class RegexPathSpecTest assertEquals(0, spec.getPathDepth(), "Spec.pathDepth"); assertEquals(PathSpecGroup.SUFFIX_GLOB, spec.group, "Spec.group"); - assertMatches(spec,"/a.do"); - assertMatches(spec,"/a/b/c.do"); - assertMatches(spec,"/abcde.do"); - assertMatches(spec,"/abc/efg.do"); + assertMatches(spec, "/a.do"); + assertMatches(spec, "/a/b/c.do"); + assertMatches(spec, "/abcde.do"); + assertMatches(spec, "/abc/efg.do"); - assertNotMatches(spec,"/a"); - assertNotMatches(spec,"/aa"); - assertNotMatches(spec,"/aa/bb"); - assertNotMatches(spec,"/aa/bb.do/more"); + assertNotMatches(spec, "/a"); + assertNotMatches(spec, "/aa"); + assertNotMatches(spec, "/aa/bb"); + assertNotMatches(spec, "/aa/bb.do/more"); } } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/ServletPathSpecMatchListTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/ServletPathSpecMatchListTest.java index 36079878b2c..88c637b489b 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/ServletPathSpecMatchListTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/ServletPathSpecMatchListTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,9 +18,6 @@ package org.eclipse.jetty.http.pathmap; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; - import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; @@ -29,6 +26,9 @@ 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.is; + /** * Tests of {@link PathMappings#getMatches(String)} */ @@ -40,34 +40,35 @@ public class ServletPathSpecMatchListTest ArrayList data = new ArrayList<>(); // From old PathMapTest - data.add(Arguments.of( "All matches", "/animal/bird/path.tar.gz", "[/animal/bird/*=birds, /animal/*=animals, *.tar.gz=tarball, *.gz=gzipped, /=default]")); - data.add(Arguments.of( "Dir matches", "/animal/fish/", "[/animal/fish/*=fishes, /animal/*=animals, /=default]")); - data.add(Arguments.of( "Dir matches", "/animal/fish", "[/animal/fish/*=fishes, /animal/*=animals, /=default]")); - data.add(Arguments.of( "Root matches", "/", "[=root, /=default]")); - data.add(Arguments.of( "Dir matches", "", "[/=default]")); + data.add(Arguments.of("All matches", "/animal/bird/path.tar.gz", "[/animal/bird/*=birds, /animal/*=animals, *.tar.gz=tarball, *.gz=gzipped, /=default]")); + data.add(Arguments.of("Dir matches", "/animal/fish/", "[/animal/fish/*=fishes, /animal/*=animals, /=default]")); + data.add(Arguments.of("Dir matches", "/animal/fish", "[/animal/fish/*=fishes, /animal/*=animals, /=default]")); + data.add(Arguments.of("Root matches", "/", "[=root, /=default]")); + data.add(Arguments.of("Dir matches", "", "[/=default]")); return data.stream(); } private static PathMappings mappings; - - static { + + static + { mappings = new PathMappings<>(); // From old PathMapTest - mappings.put(new ServletPathSpec("/abs/path"),"abspath"); // 1 - mappings.put(new ServletPathSpec("/abs/path/longer"),"longpath"); // 2 - mappings.put(new ServletPathSpec("/animal/bird/*"),"birds"); // 3 - mappings.put(new ServletPathSpec("/animal/fish/*"),"fishes"); // 4 - mappings.put(new ServletPathSpec("/animal/*"),"animals"); // 5 - mappings.put(new ServletPathSpec("*.tar.gz"),"tarball"); // 6 - mappings.put(new ServletPathSpec("*.gz"),"gzipped"); // 7 - mappings.put(new ServletPathSpec("/"),"default"); // 8 + mappings.put(new ServletPathSpec("/abs/path"), "abspath"); // 1 + mappings.put(new ServletPathSpec("/abs/path/longer"), "longpath"); // 2 + mappings.put(new ServletPathSpec("/animal/bird/*"), "birds"); // 3 + mappings.put(new ServletPathSpec("/animal/fish/*"), "fishes"); // 4 + mappings.put(new ServletPathSpec("/animal/*"), "animals"); // 5 + mappings.put(new ServletPathSpec("*.tar.gz"), "tarball"); // 6 + mappings.put(new ServletPathSpec("*.gz"), "gzipped"); // 7 + mappings.put(new ServletPathSpec("/"), "default"); // 8 // 9 was the old Jetty ":" spec delimited case (no longer valid) - mappings.put(new ServletPathSpec(""),"root"); // 10 - mappings.put(new ServletPathSpec("/\u20ACuro/*"),"money"); // 11 + mappings.put(new ServletPathSpec(""), "root"); // 10 + mappings.put(new ServletPathSpec("/\u20ACuro/*"), "money"); // 11 } - + @ParameterizedTest @MethodSource("data") public void testGetMatches(String message, String inputPath, String expectedListing) @@ -86,6 +87,6 @@ public class ServletPathSpecMatchListTest } actual.append(']'); - assertThat(message + " on [" + inputPath + "]",actual.toString(),is(expectedListing)); + assertThat(message + " on [" + inputPath + "]", actual.toString(), is(expectedListing)); } } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/ServletPathSpecOrderTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/ServletPathSpecOrderTest.java index a1a4a370457..2859dcd0a1f 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/ServletPathSpecOrderTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/ServletPathSpecOrderTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,9 +18,6 @@ package org.eclipse.jetty.http.pathmap; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; - import java.util.ArrayList; import java.util.stream.Stream; @@ -28,6 +25,9 @@ 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.is; + /** * Tests of {@link PathMappings#getMatch(String)}, with a focus on correct mapping selection order */ @@ -39,57 +39,58 @@ public class ServletPathSpecOrderTest ArrayList data = new ArrayList<>(); // From old PathMapTest - data.add(Arguments.of("/abs/path","abspath")); - data.add(Arguments.of("/abs/path/xxx","default")); - data.add(Arguments.of("/abs/pith","default")); - data.add(Arguments.of("/abs/path/longer","longpath")); - data.add(Arguments.of("/abs/path/","default")); - data.add(Arguments.of("/abs/path/foo","default")); - data.add(Arguments.of("/animal/bird/eagle/bald","birds")); - data.add(Arguments.of("/animal/fish/shark/hammerhead","fishes")); - data.add(Arguments.of("/animal/insect/ladybug","animals")); - data.add(Arguments.of("/animal","animals")); - data.add(Arguments.of("/animal/","animals")); - data.add(Arguments.of("/animal/other","animals")); - data.add(Arguments.of("/animal/*","animals")); - data.add(Arguments.of("/downloads/distribution.tar.gz","tarball")); - data.add(Arguments.of("/downloads/script.gz","gzipped")); - data.add(Arguments.of("/animal/arhive.gz","animals")); - data.add(Arguments.of("/Other/path","default")); - data.add(Arguments.of("/\u20ACuro/path","money")); - data.add(Arguments.of("/","root")); + data.add(Arguments.of("/abs/path", "abspath")); + data.add(Arguments.of("/abs/path/xxx", "default")); + data.add(Arguments.of("/abs/pith", "default")); + data.add(Arguments.of("/abs/path/longer", "longpath")); + data.add(Arguments.of("/abs/path/", "default")); + data.add(Arguments.of("/abs/path/foo", "default")); + data.add(Arguments.of("/animal/bird/eagle/bald", "birds")); + data.add(Arguments.of("/animal/fish/shark/hammerhead", "fishes")); + data.add(Arguments.of("/animal/insect/ladybug", "animals")); + data.add(Arguments.of("/animal", "animals")); + data.add(Arguments.of("/animal/", "animals")); + data.add(Arguments.of("/animal/other", "animals")); + data.add(Arguments.of("/animal/*", "animals")); + data.add(Arguments.of("/downloads/distribution.tar.gz", "tarball")); + data.add(Arguments.of("/downloads/script.gz", "gzipped")); + data.add(Arguments.of("/animal/arhive.gz", "animals")); + data.add(Arguments.of("/Other/path", "default")); + data.add(Arguments.of("/\u20ACuro/path", "money")); + data.add(Arguments.of("/", "root")); // Extra tests - data.add(Arguments.of("/downloads/readme.txt","default")); - data.add(Arguments.of("/downloads/logs.tgz","default")); - data.add(Arguments.of("/main.css","default")); + data.add(Arguments.of("/downloads/readme.txt", "default")); + data.add(Arguments.of("/downloads/logs.tgz", "default")); + data.add(Arguments.of("/main.css", "default")); return data.stream(); } private static PathMappings mappings; - - static { + + static + { mappings = new PathMappings<>(); // From old PathMapTest - mappings.put(new ServletPathSpec("/abs/path"),"abspath"); // 1 - mappings.put(new ServletPathSpec("/abs/path/longer"),"longpath"); // 2 - mappings.put(new ServletPathSpec("/animal/bird/*"),"birds"); // 3 - mappings.put(new ServletPathSpec("/animal/fish/*"),"fishes"); // 4 - mappings.put(new ServletPathSpec("/animal/*"),"animals"); // 5 - mappings.put(new ServletPathSpec("*.tar.gz"),"tarball"); // 6 - mappings.put(new ServletPathSpec("*.gz"),"gzipped"); // 7 - mappings.put(new ServletPathSpec("/"),"default"); // 8 + mappings.put(new ServletPathSpec("/abs/path"), "abspath"); // 1 + mappings.put(new ServletPathSpec("/abs/path/longer"), "longpath"); // 2 + mappings.put(new ServletPathSpec("/animal/bird/*"), "birds"); // 3 + mappings.put(new ServletPathSpec("/animal/fish/*"), "fishes"); // 4 + mappings.put(new ServletPathSpec("/animal/*"), "animals"); // 5 + mappings.put(new ServletPathSpec("*.tar.gz"), "tarball"); // 6 + mappings.put(new ServletPathSpec("*.gz"), "gzipped"); // 7 + mappings.put(new ServletPathSpec("/"), "default"); // 8 // 9 was the old Jetty ":" spec delimited case (no longer valid) - mappings.put(new ServletPathSpec(""),"root"); // 10 - mappings.put(new ServletPathSpec("/\u20ACuro/*"),"money"); // 11 + mappings.put(new ServletPathSpec(""), "root"); // 10 + mappings.put(new ServletPathSpec("/\u20ACuro/*"), "money"); // 11 } - + @ParameterizedTest @MethodSource("data") public void testMatch(String inputPath, String expectedResource) { - assertThat("Match on ["+ inputPath+ "]", mappings.getMatch(inputPath).getResource(), is(expectedResource)); + assertThat("Match on [" + inputPath + "]", mappings.getMatch(inputPath).getResource(), is(expectedResource)); } } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/ServletPathSpecTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/ServletPathSpecTest.java index b0154e6b52c..51d1c74509b 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/ServletPathSpecTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/ServletPathSpecTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,13 +18,13 @@ package org.eclipse.jetty.http.pathmap; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.fail; -import org.junit.jupiter.api.Test; - public class ServletPathSpecTest { private void assertBadServletPathSpec(String pathSpec) @@ -43,14 +43,14 @@ public class ServletPathSpecTest private void assertMatches(ServletPathSpec spec, String path) { - String msg = String.format("Spec(\"%s\").matches(\"%s\")",spec.getDeclaration(),path); - assertThat(msg,spec.matches(path),is(true)); + String msg = String.format("Spec(\"%s\").matches(\"%s\")", spec.getDeclaration(), path); + assertThat(msg, spec.matches(path), is(true)); } private void assertNotMatches(ServletPathSpec spec, String path) { - String msg = String.format("!Spec(\"%s\").matches(\"%s\")",spec.getDeclaration(),path); - assertThat(msg,spec.matches(path),is(false)); + String msg = String.format("!Spec(\"%s\").matches(\"%s\")", spec.getDeclaration(), path); + assertThat(msg, spec.matches(path), is(false)); } @Test @@ -98,13 +98,13 @@ public class ServletPathSpecTest assertEquals("/abs/path", spec.getDeclaration(), "Spec.pathSpec"); assertEquals(2, spec.getPathDepth(), "Spec.pathDepth"); - assertMatches(spec,"/abs/path"); - - assertNotMatches(spec,"/abs/path/"); - assertNotMatches(spec,"/abs/path/more"); - assertNotMatches(spec,"/foo"); - assertNotMatches(spec,"/foo/abs/path"); - assertNotMatches(spec,"/foo/abs/path/"); + assertMatches(spec, "/abs/path"); + + assertNotMatches(spec, "/abs/path/"); + assertNotMatches(spec, "/abs/path/more"); + assertNotMatches(spec, "/foo"); + assertNotMatches(spec, "/foo/abs/path"); + assertNotMatches(spec, "/foo/abs/path/"); } @Test @@ -128,7 +128,7 @@ public class ServletPathSpecTest assertEquals("", spec.getDeclaration(), "Spec.pathSpec"); assertEquals(-1, spec.getPathDepth(), "Spec.pathDepth"); } - + @Test public void testRootPathSpec() { @@ -157,12 +157,12 @@ public class ServletPathSpecTest assertEquals("/downloads/*", spec.getDeclaration(), "Spec.pathSpec"); assertEquals(2, spec.getPathDepth(), "Spec.pathDepth"); - assertMatches(spec,"/downloads/logo.jpg"); - assertMatches(spec,"/downloads/distribution.tar.gz"); - assertMatches(spec,"/downloads/distribution.tgz"); - assertMatches(spec,"/downloads/distribution.zip"); + assertMatches(spec, "/downloads/logo.jpg"); + assertMatches(spec, "/downloads/distribution.tar.gz"); + assertMatches(spec, "/downloads/distribution.tgz"); + assertMatches(spec, "/downloads/distribution.zip"); - assertMatches(spec,"/downloads"); + assertMatches(spec, "/downloads"); assertEquals("/", spec.getPathInfo("/downloads/"), "Spec.pathInfo"); assertEquals("/distribution.zip", spec.getPathInfo("/downloads/distribution.zip"), "Spec.pathInfo"); @@ -176,12 +176,12 @@ public class ServletPathSpecTest assertEquals("*.gz", spec.getDeclaration(), "Spec.pathSpec"); assertEquals(0, spec.getPathDepth(), "Spec.pathDepth"); - assertMatches(spec,"/downloads/distribution.tar.gz"); - assertMatches(spec,"/downloads/jetty.log.gz"); + assertMatches(spec, "/downloads/distribution.tar.gz"); + assertMatches(spec, "/downloads/jetty.log.gz"); - assertNotMatches(spec,"/downloads/distribution.zip"); - assertNotMatches(spec,"/downloads/distribution.tgz"); - assertNotMatches(spec,"/abs/path"); + assertNotMatches(spec, "/downloads/distribution.zip"); + assertNotMatches(spec, "/downloads/distribution.tgz"); + assertNotMatches(spec, "/abs/path"); assertEquals(null, spec.getPathInfo("/downloads/distribution.tar.gz"), "Spec.pathInfo"); } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/UriTemplatePathSpecBadSpecsTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/UriTemplatePathSpecBadSpecsTest.java index 9cdb498a06c..13d52dcd615 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/UriTemplatePathSpecBadSpecsTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/UriTemplatePathSpecBadSpecsTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,14 +18,14 @@ package org.eclipse.jetty.http.pathmap; -import static org.junit.jupiter.api.Assertions.assertThrows; - import java.util.stream.Stream; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertThrows; + /** * Tests for bad path specs on ServerEndpoint Path Param / URI Template */ @@ -33,7 +33,7 @@ public class UriTemplatePathSpecBadSpecsTest { public static Stream data() { - String badSpecs[] = new String[]{ + String[] badSpecs = new String[]{ "/a/b{var}", // bad syntax - variable does not encompass whole path segment "a/{var}", // bad syntax - no start slash "/a/{var/b}", // path segment separator in variable name @@ -54,10 +54,10 @@ public class UriTemplatePathSpecBadSpecsTest return Stream.of(badSpecs).map(Arguments::of); } - @ParameterizedTest(name="[{index}] {0}") + @ParameterizedTest(name = "[{index}] {0}") @MethodSource("data") public void testBadPathSpec(String pathSpec) { - assertThrows(IllegalArgumentException.class, ()-> new UriTemplatePathSpec(pathSpec)); + assertThrows(IllegalArgumentException.class, () -> new UriTemplatePathSpec(pathSpec)); } -} \ No newline at end of file +} diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/UriTemplatePathSpecTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/UriTemplatePathSpecTest.java index edac6c3eb7a..afc20b78301 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/UriTemplatePathSpecTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/UriTemplatePathSpecTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,15 +18,15 @@ package org.eclipse.jetty.http.pathmap; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.hamcrest.MatcherAssert.assertThat; - import java.util.Map; import org.junit.jupiter.api.Test; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.jupiter.api.Assertions.assertEquals; + /** * Tests for URI Template Path Specs */ @@ -34,25 +34,25 @@ public class UriTemplatePathSpecTest { private void assertDetectedVars(UriTemplatePathSpec spec, String... expectedVars) { - String prefix = String.format("Spec(\"%s\")",spec.getDeclaration()); + String prefix = String.format("Spec(\"%s\")", spec.getDeclaration()); assertEquals(expectedVars.length, spec.getVariableCount(), prefix + ".variableCount"); assertEquals(expectedVars.length, spec.getVariables().length, prefix + ".variable.length"); for (int i = 0; i < expectedVars.length; i++) { - assertThat(String.format("%s.variable[%d]",prefix,i),spec.getVariables()[i],is(expectedVars[i])); + assertThat(String.format("%s.variable[%d]", prefix, i), spec.getVariables()[i], is(expectedVars[i])); } } private void assertMatches(PathSpec spec, String path) { - String msg = String.format("Spec(\"%s\").matches(\"%s\")",spec.getDeclaration(),path); - assertThat(msg,spec.matches(path),is(true)); + String msg = String.format("Spec(\"%s\").matches(\"%s\")", spec.getDeclaration(), path); + assertThat(msg, spec.matches(path), is(true)); } private void assertNotMatches(PathSpec spec, String path) { - String msg = String.format("!Spec(\"%s\").matches(\"%s\")",spec.getDeclaration(),path); - assertThat(msg,spec.matches(path),is(false)); + String msg = String.format("!Spec(\"%s\").matches(\"%s\")", spec.getDeclaration(), path); + assertThat(msg, spec.matches(path), is(false)); } @Test @@ -76,16 +76,16 @@ public class UriTemplatePathSpecTest assertEquals("^/a$", spec.getPattern().pattern(), "Spec.pattern"); assertEquals(1, spec.getPathDepth(), "Spec.pathDepth"); assertEquals(PathSpecGroup.EXACT, spec.getGroup(), "Spec.group"); - - assertMatches(spec,"/a"); - assertMatches(spec,"/a?type=other"); - assertNotMatches(spec,"/a/b"); - assertNotMatches(spec,"/a/"); + + assertMatches(spec, "/a"); + assertMatches(spec, "/a?type=other"); + assertNotMatches(spec, "/a/b"); + assertNotMatches(spec, "/a/"); assertEquals(0, spec.getVariableCount(), "Spec.variableCount"); assertEquals(0, spec.getVariables().length, "Spec.variable.length"); } - + @Test public void testExactPathSpec_TestWebapp() { @@ -94,14 +94,14 @@ public class UriTemplatePathSpecTest assertEquals("^/deep\\.thought/$", spec.getPattern().pattern(), "Spec.pattern"); assertEquals(1, spec.getPathDepth(), "Spec.pathDepth"); assertEquals(PathSpecGroup.EXACT, spec.getGroup(), "Spec.group"); - - assertMatches(spec,"/deep.thought/"); - assertNotMatches(spec,"/deep.thought"); + + assertMatches(spec, "/deep.thought/"); + assertNotMatches(spec, "/deep.thought"); assertEquals(0, spec.getVariableCount(), "Spec.variableCount"); assertEquals(0, spec.getVariables().length, "Spec.variable.length"); } - + @Test public void testExactTwoPathSpec() { @@ -114,11 +114,11 @@ public class UriTemplatePathSpecTest assertEquals(0, spec.getVariableCount(), "Spec.variableCount"); assertEquals(0, spec.getVariables().length, "Spec.variable.length"); - assertMatches(spec,"/a/b"); + assertMatches(spec, "/a/b"); - assertNotMatches(spec,"/a/b/"); - assertNotMatches(spec,"/a/"); - assertNotMatches(spec,"/a/bb"); + assertNotMatches(spec, "/a/b/"); + assertNotMatches(spec, "/a/"); + assertNotMatches(spec, "/a/bb"); } @Test @@ -130,18 +130,18 @@ public class UriTemplatePathSpecTest assertEquals(3, spec.getPathDepth(), "Spec.pathDepth"); assertEquals(PathSpecGroup.MIDDLE_GLOB, spec.getGroup(), "Spec.group"); - assertDetectedVars(spec,"var"); + assertDetectedVars(spec, "var"); - assertMatches(spec,"/a/b/c"); - assertMatches(spec,"/a/zz/c"); - assertMatches(spec,"/a/hello+world/c"); - assertNotMatches(spec,"/a/bc"); - assertNotMatches(spec,"/a/b/"); - assertNotMatches(spec,"/a/b"); + assertMatches(spec, "/a/b/c"); + assertMatches(spec, "/a/zz/c"); + assertMatches(spec, "/a/hello+world/c"); + assertNotMatches(spec, "/a/bc"); + assertNotMatches(spec, "/a/b/"); + assertNotMatches(spec, "/a/b"); Map mapped = spec.getPathParams("/a/b/c"); - assertThat("Spec.pathParams",mapped,notNullValue()); - assertThat("Spec.pathParams.size",mapped.size(),is(1)); + assertThat("Spec.pathParams", mapped, notNullValue()); + assertThat("Spec.pathParams.size", mapped.size(), is(1)); assertEquals("b", mapped.get("var"), "Spec.pathParams[var]"); } @@ -154,15 +154,15 @@ public class UriTemplatePathSpecTest assertEquals(2, spec.getPathDepth(), "Spec.pathDepth"); assertEquals(PathSpecGroup.PREFIX_GLOB, spec.getGroup(), "Spec.group"); - assertDetectedVars(spec,"foo"); + assertDetectedVars(spec, "foo"); - assertMatches(spec,"/a/b"); - assertNotMatches(spec,"/a/"); - assertNotMatches(spec,"/a"); + assertMatches(spec, "/a/b"); + assertNotMatches(spec, "/a/"); + assertNotMatches(spec, "/a"); Map mapped = spec.getPathParams("/a/b"); - assertThat("Spec.pathParams",mapped,notNullValue()); - assertThat("Spec.pathParams.size",mapped.size(),is(1)); + assertThat("Spec.pathParams", mapped, notNullValue()); + assertThat("Spec.pathParams.size", mapped.size(), is(1)); assertEquals("b", mapped.get("foo"), "Spec.pathParams[foo]"); } @@ -175,18 +175,18 @@ public class UriTemplatePathSpecTest assertEquals(3, spec.getPathDepth(), "Spec.pathDepth"); assertEquals(PathSpecGroup.SUFFIX_GLOB, spec.getGroup(), "Spec.group"); - assertDetectedVars(spec,"var"); + assertDetectedVars(spec, "var"); - assertMatches(spec,"/a/b/c"); - assertMatches(spec,"/az/b/c"); - assertMatches(spec,"/hello+world/b/c"); - assertNotMatches(spec,"/a/bc"); - assertNotMatches(spec,"/a/b/"); - assertNotMatches(spec,"/a/b"); + assertMatches(spec, "/a/b/c"); + assertMatches(spec, "/az/b/c"); + assertMatches(spec, "/hello+world/b/c"); + assertNotMatches(spec, "/a/bc"); + assertNotMatches(spec, "/a/b/"); + assertNotMatches(spec, "/a/b"); Map mapped = spec.getPathParams("/a/b/c"); - assertThat("Spec.pathParams",mapped,notNullValue()); - assertThat("Spec.pathParams.size",mapped.size(),is(1)); + assertThat("Spec.pathParams", mapped, notNullValue()); + assertThat("Spec.pathParams.size", mapped.size(), is(1)); assertEquals("a", mapped.get("var"), "Spec.pathParams[var]"); } @@ -199,16 +199,16 @@ public class UriTemplatePathSpecTest assertEquals(5, spec.getPathDepth(), "Spec.pathDepth"); assertEquals(PathSpecGroup.MIDDLE_GLOB, spec.getGroup(), "Spec.group"); - assertDetectedVars(spec,"var1","var2"); + assertDetectedVars(spec, "var1", "var2"); - assertMatches(spec,"/a/b/c/d/e"); - assertNotMatches(spec,"/a/bc/d/e"); - assertNotMatches(spec,"/a/b/d/e"); - assertNotMatches(spec,"/a/b//d/e"); + assertMatches(spec, "/a/b/c/d/e"); + assertNotMatches(spec, "/a/bc/d/e"); + assertNotMatches(spec, "/a/b/d/e"); + assertNotMatches(spec, "/a/b//d/e"); Map mapped = spec.getPathParams("/a/b/c/d/e"); - assertThat("Spec.pathParams",mapped,notNullValue()); - assertThat("Spec.pathParams.size",mapped.size(),is(2)); + assertThat("Spec.pathParams", mapped, notNullValue()); + assertThat("Spec.pathParams.size", mapped.size(), is(2)); assertEquals("b", mapped.get("var1"), "Spec.pathParams[var1]"); assertEquals("d", mapped.get("var2"), "Spec.pathParams[var2]"); } @@ -222,16 +222,16 @@ public class UriTemplatePathSpecTest assertEquals(4, spec.getPathDepth(), "Spec.pathDepth"); assertEquals(PathSpecGroup.MIDDLE_GLOB, spec.getGroup(), "Spec.group"); - assertDetectedVars(spec,"var1","var2","var3"); + assertDetectedVars(spec, "var1", "var2", "var3"); - assertMatches(spec,"/a/b/c/d"); - assertNotMatches(spec,"/a/bc/d/e"); - assertNotMatches(spec,"/a/c/d/e"); - assertNotMatches(spec,"/a//d/e"); + assertMatches(spec, "/a/b/c/d"); + assertNotMatches(spec, "/a/bc/d/e"); + assertNotMatches(spec, "/a/c/d/e"); + assertNotMatches(spec, "/a//d/e"); Map mapped = spec.getPathParams("/a/b/c/d"); - assertThat("Spec.pathParams",mapped,notNullValue()); - assertThat("Spec.pathParams.size",mapped.size(),is(3)); + assertThat("Spec.pathParams", mapped, notNullValue()); + assertThat("Spec.pathParams.size", mapped.size(), is(3)); assertEquals("a", mapped.get("var1"), "Spec.pathParams[var1]"); assertEquals("c", mapped.get("var2"), "Spec.pathParams[var2]"); assertEquals("d", mapped.get("var3"), "Spec.pathParams[var3]"); @@ -246,16 +246,16 @@ public class UriTemplatePathSpecTest assertEquals(3, spec.getPathDepth(), "Spec.pathDepth"); assertEquals(PathSpecGroup.PREFIX_GLOB, spec.getGroup(), "Spec.group"); - assertDetectedVars(spec,"var1","var2"); + assertDetectedVars(spec, "var1", "var2"); - assertMatches(spec,"/a/b/c"); - assertNotMatches(spec,"/a/bc"); - assertNotMatches(spec,"/a/b/"); - assertNotMatches(spec,"/a/b"); + assertMatches(spec, "/a/b/c"); + assertNotMatches(spec, "/a/bc"); + assertNotMatches(spec, "/a/b/"); + assertNotMatches(spec, "/a/b"); Map mapped = spec.getPathParams("/a/b/c"); - assertThat("Spec.pathParams",mapped,notNullValue()); - assertThat("Spec.pathParams.size",mapped.size(),is(2)); + assertThat("Spec.pathParams", mapped, notNullValue()); + assertThat("Spec.pathParams.size", mapped.size(), is(2)); assertEquals("b", mapped.get("var1"), "Spec.pathParams[var1]"); assertEquals("c", mapped.get("var2"), "Spec.pathParams[var2]"); } @@ -269,16 +269,16 @@ public class UriTemplatePathSpecTest assertEquals(1, spec.getPathDepth(), "Spec.pathDepth"); assertEquals(PathSpecGroup.PREFIX_GLOB, spec.getGroup(), "Spec.group"); - assertDetectedVars(spec,"var1"); + assertDetectedVars(spec, "var1"); - assertMatches(spec,"/a"); - assertNotMatches(spec,"/"); - assertNotMatches(spec,"/a/b"); - assertNotMatches(spec,"/a/b/c"); + assertMatches(spec, "/a"); + assertNotMatches(spec, "/"); + assertNotMatches(spec, "/a/b"); + assertNotMatches(spec, "/a/b/c"); Map mapped = spec.getPathParams("/a"); - assertThat("Spec.pathParams",mapped,notNullValue()); - assertThat("Spec.pathParams.size",mapped.size(),is(1)); + assertThat("Spec.pathParams", mapped, notNullValue()); + assertThat("Spec.pathParams.size", mapped.size(), is(1)); assertEquals("a", mapped.get("var1"), "Spec.pathParams[var1]"); } } diff --git a/jetty-http2/http2-alpn-tests/pom.xml b/jetty-http2/http2-alpn-tests/pom.xml index 6eff280901f..f0f25deeb9e 100644 --- a/jetty-http2/http2-alpn-tests/pom.xml +++ b/jetty-http2/http2-alpn-tests/pom.xml @@ -1,106 +1,101 @@ - - org.eclipse.jetty.http2 - http2-parent - 9.4.13-SNAPSHOT - + + org.eclipse.jetty.http2 + http2-parent + 9.4.21-SNAPSHOT + - 4.0.0 - http2-alpn-tests - Jetty :: HTTP2 :: ALPN Tests + 4.0.0 + http2-alpn-tests + Jetty :: HTTP2 :: ALPN Tests - - ${project.groupId}.alpn.tests - + + ${project.groupId}.alpn.tests + - - - - maven-dependency-plugin - - - copy - generate-resources - - copy - - - - - org.mortbay.jetty.alpn - alpn-boot - ${alpn.version} - jar - false - ${project.build.directory}/alpn - - - - - - - - maven-surefire-plugin - - -Xbootclasspath/p:${project.build.directory}/alpn/alpn-boot-${alpn.version}.jar - - - - + + + + maven-dependency-plugin + + + copy + generate-resources + + copy + + + + + org.mortbay.jetty.alpn + alpn-boot + ${alpn.version} + jar + false + ${project.build.directory}/alpn + + + + + + + + maven-surefire-plugin + + -Xbootclasspath/p:${project.build.directory}/alpn/alpn-boot-${alpn.version}.jar + + + + - - - org.eclipse.jetty.alpn - alpn-api - ${alpn.api.version} - provided - + + + org.eclipse.jetty.alpn + alpn-api + ${alpn.api.version} + provided + + + org.eclipse.jetty + jetty-alpn-openjdk8-server + ${project.version} + test + + + org.eclipse.jetty + jetty-server + ${project.version} + test + + + org.eclipse.jetty.http2 + http2-server + ${project.version} + test + + + org.eclipse.jetty.toolchain + jetty-test-helper + test + + + + + + jdk9 + + [1.9,) + + + - org.eclipse.jetty - jetty-alpn-openjdk8-server - ${project.version} - test + org.eclipse.jetty + jetty-alpn-java-server + ${project.version} + test - - org.eclipse.jetty - jetty-server - ${project.version} - test - - - org.eclipse.jetty.http2 - http2-server - ${project.version} - test - - - org.eclipse.jetty.toolchain - jetty-test-helper - test - - - junit - junit - test - - - - - - jdk9 - - [1.9,) - - - - - org.eclipse.jetty - jetty-alpn-java-server - ${project.version} - test - - - - + + + diff --git a/jetty-http2/http2-alpn-tests/src/test/java/org/eclipse/jetty/http2/alpn/tests/ALPNNegotiationTest.java b/jetty-http2/http2-alpn-tests/src/test/java/org/eclipse/jetty/http2/alpn/tests/ALPNNegotiationTest.java index 60c859bf5ff..c49ed66f48c 100644 --- a/jetty-http2/http2-alpn-tests/src/test/java/org/eclipse/jetty/http2/alpn/tests/ALPNNegotiationTest.java +++ b/jetty-http2/http2-alpn-tests/src/test/java/org/eclipse/jetty/http2/alpn/tests/ALPNNegotiationTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,11 +18,6 @@ package org.eclipse.jetty.http2.alpn.tests; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; @@ -33,7 +28,6 @@ import java.nio.channels.SocketChannel; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.List; - import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLSocket; @@ -43,13 +37,18 @@ import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.junit.jupiter.api.Test; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class ALPNNegotiationTest extends AbstractALPNTest { @Test public void testGentleCloseDuringHandshake() throws Exception { InetSocketAddress address = prepare(); - SslContextFactory sslContextFactory = newSslContextFactory(); + SslContextFactory sslContextFactory = newClientSslContextFactory(); sslContextFactory.start(); SSLEngine sslEngine = sslContextFactory.newSSLEngine(address); sslEngine.setUseClientMode(true); @@ -113,7 +112,7 @@ public class ALPNNegotiationTest extends AbstractALPNTest public void testAbruptCloseDuringHandshake() throws Exception { InetSocketAddress address = prepare(); - SslContextFactory sslContextFactory = newSslContextFactory(); + SslContextFactory sslContextFactory = newClientSslContextFactory(); sslContextFactory.start(); SSLEngine sslEngine = sslContextFactory.newSSLEngine(address); sslEngine.setUseClientMode(true); @@ -175,7 +174,7 @@ public class ALPNNegotiationTest extends AbstractALPNTest { InetSocketAddress address = prepare(); - SslContextFactory sslContextFactory = newSslContextFactory(); + SslContextFactory sslContextFactory = newClientSslContextFactory(); sslContextFactory.start(); SSLContext sslContext = sslContextFactory.getSslContext(); @@ -209,8 +208,8 @@ public class ALPNNegotiationTest extends AbstractALPNTest // Verify that the server really speaks http/1.1 OutputStream output = client.getOutputStream(); - output.write(("" + - "GET / HTTP/1.1\r\n" + + output.write(( + "GET / HTTP/1.1\r\n" + "Host: localhost:" + address.getPort() + "\r\n" + "\r\n" + "").getBytes(StandardCharsets.UTF_8)); @@ -228,7 +227,7 @@ public class ALPNNegotiationTest extends AbstractALPNTest { InetSocketAddress address = prepare(); - SslContextFactory sslContextFactory = newSslContextFactory(); + SslContextFactory sslContextFactory = newClientSslContextFactory(); sslContextFactory.start(); SSLContext sslContext = sslContextFactory.getSslContext(); try (SSLSocket client = (SSLSocket)sslContext.getSocketFactory().createSocket(address.getAddress(), address.getPort())) @@ -261,8 +260,8 @@ public class ALPNNegotiationTest extends AbstractALPNTest // Verify that the server really speaks http/1.1 OutputStream output = client.getOutputStream(); - output.write(("" + - "GET / HTTP/1.1\r\n" + + output.write(( + "GET / HTTP/1.1\r\n" + "Host: localhost:" + address.getPort() + "\r\n" + "\r\n" + "").getBytes(StandardCharsets.UTF_8)); @@ -280,7 +279,7 @@ public class ALPNNegotiationTest extends AbstractALPNTest { InetSocketAddress address = prepare(); - SslContextFactory sslContextFactory = newSslContextFactory(); + SslContextFactory sslContextFactory = newClientSslContextFactory(); sslContextFactory.start(); SSLContext sslContext = sslContextFactory.getSslContext(); try (SSLSocket client = (SSLSocket)sslContext.getSocketFactory().createSocket(address.getAddress(), address.getPort())) @@ -312,8 +311,8 @@ public class ALPNNegotiationTest extends AbstractALPNTest // Verify that the server really speaks http/1.1 OutputStream output = client.getOutputStream(); - output.write(("" + - "GET / HTTP/1.1\r\n" + + output.write(( + "GET / HTTP/1.1\r\n" + "Host: localhost:" + address.getPort() + "\r\n" + "\r\n" + "").getBytes(StandardCharsets.UTF_8)); diff --git a/jetty-http2/http2-alpn-tests/src/test/java/org/eclipse/jetty/http2/alpn/tests/AbstractALPNTest.java b/jetty-http2/http2-alpn-tests/src/test/java/org/eclipse/jetty/http2/alpn/tests/AbstractALPNTest.java index 59ad2d7e3c1..692755fb12d 100644 --- a/jetty-http2/http2-alpn-tests/src/test/java/org/eclipse/jetty/http2/alpn/tests/AbstractALPNTest.java +++ b/jetty-http2/http2-alpn-tests/src/test/java/org/eclipse/jetty/http2/alpn/tests/AbstractALPNTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -48,8 +48,8 @@ public class AbstractALPNTest HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(httpConfiguration); ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory(); alpn.setDefaultProtocol(h1.getProtocol()); - - connector = new ServerConnector(server, newSslContextFactory(), alpn, h1, h2); + + connector = new ServerConnector(server, newServerSslContextFactory(), alpn, h1, h2); connector.setPort(0); connector.setIdleTimeout(30000); server.addConnector(connector); @@ -60,9 +60,22 @@ public class AbstractALPNTest return new InetSocketAddress("localhost", connector.getLocalPort()); } - protected SslContextFactory newSslContextFactory() + protected SslContextFactory.Server newServerSslContextFactory() + { + SslContextFactory.Server result = new SslContextFactory.Server(); + configureSslContextFactory(result); + return result; + } + + protected SslContextFactory.Client newClientSslContextFactory() + { + SslContextFactory.Client result = new SslContextFactory.Client(); + configureSslContextFactory(result); + return result; + } + + private void configureSslContextFactory(SslContextFactory sslContextFactory) { - SslContextFactory sslContextFactory = new SslContextFactory(); sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks"); sslContextFactory.setKeyStorePassword("storepwd"); sslContextFactory.setTrustStorePath("src/test/resources/truststore.jks"); @@ -70,7 +83,6 @@ public class AbstractALPNTest sslContextFactory.setIncludeProtocols("TLSv1.2"); // The mandatory HTTP/2 cipher. sslContextFactory.setIncludeCipherSuites("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"); - return sslContextFactory; } @AfterEach diff --git a/jetty-http2/http2-client/pom.xml b/jetty-http2/http2-client/pom.xml index 5d2bd3a3d3d..67c035c495e 100644 --- a/jetty-http2/http2-client/pom.xml +++ b/jetty-http2/http2-client/pom.xml @@ -3,67 +3,66 @@ org.eclipse.jetty.http2 http2-parent - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 http2-client Jetty :: HTTP2 :: Client - + ${project.groupId}.client - - + - - - org.eclipse.jetty.http2 - http2-common - ${project.version} - - - org.eclipse.jetty - jetty-alpn-client - ${project.version} - + + + org.eclipse.jetty.http2 + http2-common + ${project.version} + + + org.eclipse.jetty + jetty-alpn-client + ${project.version} + - - org.eclipse.jetty.toolchain - jetty-test-helper - test - - - org.eclipse.jetty - jetty-server - ${project.version} - test - - - org.eclipse.jetty - jetty-servlet - ${project.version} - test - - - org.eclipse.jetty - jetty-servlets - ${project.version} - test - - - org.eclipse.jetty - jetty-proxy - ${project.version} - test - - - org.eclipse.jetty.http2 - http2-server - ${project.version} - test - - + + org.eclipse.jetty.toolchain + jetty-test-helper + test + + + org.eclipse.jetty + jetty-server + ${project.version} + test + + + org.eclipse.jetty + jetty-servlet + ${project.version} + test + + + org.eclipse.jetty + jetty-servlets + ${project.version} + test + + + org.eclipse.jetty + jetty-proxy + ${project.version} + test + + + org.eclipse.jetty.http2 + http2-server + ${project.version} + test + + diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java index 03bd0d3d006..3b969874d63 100644 --- a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java +++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java index 803d95b586a..c44f4dcdfb9 100644 --- a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java +++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -72,7 +72,7 @@ public class HTTP2ClientConnectionFactory implements ClientConnectionFactory parser.setMaxSettingsKeys(client.getMaxSettingsKeys()); HTTP2ClientConnection connection = new HTTP2ClientConnection(client, byteBufferPool, executor, endPoint, - parser, session, client.getInputBufferSize(), promise, listener); + parser, session, client.getInputBufferSize(), promise, listener); connection.addListener(connectionListener); return customize(connection, context); } diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java index 3be563d093c..660ae6c205f 100644 --- a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java +++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -29,6 +29,7 @@ import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.PushPromiseFrame; +import org.eclipse.jetty.http2.frames.ResetFrame; import org.eclipse.jetty.http2.generator.Generator; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.util.Callback; @@ -117,6 +118,17 @@ public class HTTP2ClientSession extends HTTP2Session } } + @Override + protected void onResetForUnknownStream(ResetFrame frame) + { + int streamId = frame.getStreamId(); + boolean closed = isClientStream(streamId) ? isLocalStreamClosed(streamId) : isRemoteStreamClosed(streamId); + if (closed) + notifyReset(this, frame); + else + onConnectionFailure(ErrorCode.PROTOCOL_ERROR.code, "unexpected_rst_stream_frame"); + } + @Override public void onPushPromise(PushPromiseFrame frame) { diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java index 9d55e94971f..0d620a0ecee 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,7 +20,6 @@ package org.eclipse.jetty.http2.client; import java.net.InetSocketAddress; import java.util.concurrent.TimeUnit; - import javax.servlet.http.HttpServlet; import org.eclipse.jetty.http.HostPortHttpField; diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AsyncIOTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AsyncIOTest.java index 46a15a43b12..a1e3050ce97 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AsyncIOTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AsyncIOTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,16 +18,12 @@ package org.eclipse.jetty.http2.client; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.IOException; import java.io.InterruptedIOException; import java.nio.ByteBuffer; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; - import javax.servlet.AsyncContext; import javax.servlet.ReadListener; import javax.servlet.ServletException; @@ -44,9 +40,11 @@ import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.FuturePromise; - import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class AsyncIOTest extends AbstractTest { @Test diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AsyncServletTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AsyncServletTest.java index 2ea9eb80f9d..df1fe1bf9ee 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AsyncServletTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AsyncServletTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,18 +18,12 @@ package org.eclipse.jetty.http2.client; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Random; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; - import javax.servlet.AsyncContext; import javax.servlet.AsyncEvent; import javax.servlet.AsyncListener; @@ -60,9 +54,13 @@ import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.FuturePromise; import org.eclipse.jetty.util.Promise; - import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class AsyncServletTest extends AbstractTest { @Test @@ -137,25 +135,28 @@ public class AsyncServletTest extends AbstractTest MetaData.Request metaData = newRequest("GET", fields); HeadersFrame frame = new HeadersFrame(metaData, null, true); FuturePromise promise = new FuturePromise<>(); - CountDownLatch clientLatch = new CountDownLatch(1); + CountDownLatch responseLatch = new CountDownLatch(1); + CountDownLatch resetLatch = new CountDownLatch(1); session.newStream(frame, promise, new Stream.Listener.Adapter() { @Override public void onHeaders(Stream stream, HeadersFrame frame) { - MetaData.Response response = (MetaData.Response)frame.getMetaData(); - if (response.getStatus() == HttpStatus.INTERNAL_SERVER_ERROR_500 && frame.isEndStream()) - clientLatch.countDown(); + responseLatch.countDown(); + } + + @Override + public void onReset(Stream stream, ResetFrame frame) + { + resetLatch.countDown(); } }); Stream stream = promise.get(5, TimeUnit.SECONDS); stream.setIdleTimeout(10 * idleTimeout); - // When the client closes, the server receives the - // corresponding frame and acts by notifying the failure, - // which sends back to the client the error response. assertTrue(serverLatch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); - assertTrue(clientLatch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); + assertFalse(responseLatch.await(idleTimeout + 1000, TimeUnit.MILLISECONDS)); + assertTrue(resetLatch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); } @Test @@ -237,11 +238,12 @@ public class AsyncServletTest extends AbstractTest ServletOutputStream output = response.getOutputStream(); assertThrows(IOException.class, - () -> { - // Large writes or explicit flush() must - // fail because the stream has been reset. - output.flush(); - }); + () -> + { + // Large writes or explicit flush() must + // fail because the stream has been reset. + output.flush(); + }); } @Test diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/BufferingFlowControlStrategyTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/BufferingFlowControlStrategyTest.java index 1dc3391bad9..45fd917f240 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/BufferingFlowControlStrategyTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/BufferingFlowControlStrategyTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/Client.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/Client.java index 657e19d1558..b352cd336a6 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/Client.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/Client.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -43,7 +43,7 @@ public class Client public static void main(String[] args) throws Exception { HTTP2Client client = new HTTP2Client(); - SslContextFactory sslContextFactory = new SslContextFactory(); + SslContextFactory sslContextFactory = new SslContextFactory.Client(); client.addBean(sslContextFactory); client.start(); diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/ConnectTimeoutTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/ConnectTimeoutTest.java index c6bd653a9eb..9b8c6a3daa3 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/ConnectTimeoutTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/ConnectTimeoutTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,10 +18,6 @@ package org.eclipse.jetty.http2.client; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.instanceOf; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.IOException; import java.net.InetSocketAddress; import java.net.Socket; @@ -35,6 +31,10 @@ import org.eclipse.jetty.util.Promise; import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.instanceOf; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class ConnectTimeoutTest extends AbstractTest { @Test @@ -66,7 +66,7 @@ public class ConnectTimeoutTest extends AbstractTest private void assumeConnectTimeout(String host, int port, int connectTimeout) throws IOException { boolean socketTimeout = false; - + try (Socket socket = new Socket()) { // Try to connect to a private address in the 10.x.y.z range. @@ -86,7 +86,7 @@ public class ConnectTimeoutTest extends AbstractTest // Useful when debugging x.printStackTrace(System.err); } - + // Abort the test if we can connect. Assumptions.assumeTrue(socketTimeout, "Should have seen connect timeout"); } diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/EmptyHttpServlet.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/EmptyHttpServlet.java index efff08e2ddc..630110034d3 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/EmptyHttpServlet.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/EmptyHttpServlet.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,7 +19,6 @@ package org.eclipse.jetty.http2.client; import java.io.IOException; - import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlStalledTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlStalledTest.java index 2a71d1ecc9b..cf8608d6748 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlStalledTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlStalledTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,9 +18,6 @@ package org.eclipse.jetty.http2.client; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.util.ArrayDeque; @@ -56,9 +53,11 @@ import org.eclipse.jetty.util.FuturePromise; import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.junit.jupiter.api.AfterEach; - import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class FlowControlStalledTest { protected ServerConnector connector; diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlStrategyTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlStrategyTest.java index 08b60cd0388..9fe509df5f2 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlStrategyTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlStrategyTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,13 +18,6 @@ package org.eclipse.jetty.http2.client; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.util.ArrayList; @@ -74,10 +67,15 @@ import org.eclipse.jetty.util.FuturePromise; import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.junit.jupiter.api.AfterEach; - -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + public abstract class FlowControlStrategyTest { protected ServerConnector connector; @@ -505,7 +503,7 @@ public abstract class FlowControlStrategyTest private void checkThatWeAreFlowControlStalled(Exchanger exchanger) throws Exception { assertThrows(TimeoutException.class, - () -> exchanger.exchange(null, 1, TimeUnit.SECONDS)); + () -> exchanger.exchange(null, 1, TimeUnit.SECONDS)); } @Test @@ -605,7 +603,9 @@ public abstract class FlowControlStrategyTest // Consume the data of the first response. // This will open up the session window, allowing the fourth stream to send data. for (Callback callback : callbacks1) + { callback.succeeded(); + } assertTrue(latch.await(5, TimeUnit.SECONDS)); } diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlWindowsTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlWindowsTest.java index ecf9e8d1331..2b2bb275cd6 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlWindowsTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlWindowsTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,9 +18,6 @@ package org.eclipse.jetty.http2.client; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.net.InetSocketAddress; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -48,6 +45,9 @@ import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class FlowControlWindowsTest { private Server server; diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java index 33ef5e818a0..b5be288a82b 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,10 +18,6 @@ package org.eclipse.jetty.http2.client; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.WritePendingException; @@ -31,8 +27,6 @@ import java.util.Map; import java.util.Random; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; - -import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -51,6 +45,7 @@ import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.GoAwayFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.SettingsFrame; +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; @@ -61,9 +56,12 @@ import org.eclipse.jetty.util.FuturePromise; import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.Jetty; import org.eclipse.jetty.util.Promise; - 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 HTTP2Test extends AbstractTest { @Test @@ -154,7 +152,7 @@ public class HTTP2Test extends AbstractTest start(new HttpServlet() { @Override - protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException + protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException { resp.getOutputStream().write(content); } @@ -202,7 +200,7 @@ public class HTTP2Test extends AbstractTest start(new EmptyHttpServlet() { @Override - protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException { IO.copy(request.getInputStream(), response.getOutputStream()); } @@ -246,7 +244,7 @@ public class HTTP2Test extends AbstractTest start(new HttpServlet() { @Override - protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException { int download = request.getIntHeader(downloadBytes); byte[] content = new byte[download]; @@ -289,7 +287,7 @@ public class HTTP2Test extends AbstractTest start(new HttpServlet() { @Override - protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + protected void service(HttpServletRequest request, HttpServletResponse response) { response.setStatus(status); } @@ -324,7 +322,7 @@ public class HTTP2Test extends AbstractTest start(new HttpServlet() { @Override - protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + protected void service(HttpServletRequest request, HttpServletResponse response) { assertEquals(host, request.getServerName()); assertEquals(port, request.getServerPort()); @@ -749,7 +747,7 @@ public class HTTP2Test extends AbstractTest RawHTTP2ServerConnectionFactory connectionFactory = new RawHTTP2ServerConnectionFactory(new HttpConfiguration(), serverListener) { @Override - protected ServerParser newServerParser(Connector connector, ServerParser.Listener listener) + protected ServerParser newServerParser(Connector connector, ServerParser.Listener listener, RateControl rateControl) { return super.newServerParser(connector, new ServerParser.Listener.Wrapper(listener) { @@ -759,7 +757,7 @@ public class HTTP2Test extends AbstractTest super.onGoAway(frame); goAwayLatch.countDown(); } - }); + }, rateControl); } }; prepareServer(connectionFactory); diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/IdleTimeoutTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/IdleTimeoutTest.java index 297b93fd91f..aaf8a7af2b0 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/IdleTimeoutTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/IdleTimeoutTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,22 +16,14 @@ // ======================================================================== // - package org.eclipse.jetty.http2.client; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - import java.io.IOException; import java.nio.ByteBuffer; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicReference; - import javax.servlet.ServletException; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServlet; @@ -63,9 +55,14 @@ import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.hamcrest.Matchers; - import org.junit.jupiter.api.Test; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + public class IdleTimeoutTest extends AbstractTest { private final int idleTimeout = 1000; diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/InterleavingTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/InterleavingTest.java index a194c01b27f..306278c822a 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/InterleavingTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/InterleavingTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,12 +18,6 @@ package org.eclipse.jetty.http2.client; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.lessThanOrEqualTo; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; import java.util.ArrayList; @@ -55,6 +49,12 @@ import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.junit.jupiter.api.Test; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.lessThanOrEqualTo; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + public class InterleavingTest extends AbstractTest { @Test @@ -195,7 +195,9 @@ public class InterleavingTest extends AbstractTest { logger.debug("stream {} interleaved lengths = {}", stream, lengths); for (Integer length : lengths) + { assertThat(length, lessThanOrEqualTo(maxFrameSize)); + } }); } diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/InvalidServerTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/InvalidServerTest.java index 750f0aca457..6aeca90b8bd 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/InvalidServerTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/InvalidServerTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,9 +18,6 @@ package org.eclipse.jetty.http2.client; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.InputStream; import java.io.OutputStream; import java.net.InetSocketAddress; @@ -34,6 +31,9 @@ import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.util.Promise; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class InvalidServerTest extends AbstractTest { @Test diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/MaxPushedStreamsTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/MaxPushedStreamsTest.java index c2eb22730fd..1890fd36458 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/MaxPushedStreamsTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/MaxPushedStreamsTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -65,49 +65,57 @@ public class MaxPushedStreamsTest extends AbstractTest // Trick the server into thinking it can push unlimited streams. ((HTTP2Session)stream.getSession()).setMaxLocalStreams(-1); - BiFunction, Stream, List> add = (l, s) -> { l.add(s); return l; }; - BinaryOperator> addAll = (l1, l2) -> { l1.addAll(l2); return l1; }; + BiFunction, Stream, List> add = (l, s) -> + { + l.add(s); + return l; + }; + BinaryOperator> addAll = (l1, l2) -> + { + l1.addAll(l2); + return l1; + }; CompletableFuture> result = CompletableFuture.completedFuture(new ArrayList<>()); // Push maxPushed resources... IntStream.range(0, maxPushed) - .mapToObj(i -> new PushPromiseFrame(stream.getId(), 0, newRequest("GET", "/push_" + i, new HttpFields()))) - .map(pushFrame -> + .mapToObj(i -> new PushPromiseFrame(stream.getId(), 0, newRequest("GET", "/push_" + i, new HttpFields()))) + .map(pushFrame -> + { + Promise.Completable promise = new Promise.Completable<>(); + stream.push(pushFrame, promise, new Stream.Listener.Adapter()); + return promise; + }) + // ... wait for the pushed streams... + .reduce(result, (cfList, cfStream) -> cfList.thenCombine(cfStream, add), + (cfList1, cfList2) -> cfList1.thenCombine(cfList2, addAll)) + // ... then push one extra stream, the client must reject it... + .thenApply(streams -> + { + PushPromiseFrame extraPushFrame = new PushPromiseFrame(stream.getId(), 0, newRequest("GET", "/push_extra", new HttpFields())); + FuturePromise extraPromise = new FuturePromise<>(); + stream.push(extraPushFrame, extraPromise, new Stream.Listener.Adapter() { - Promise.Completable promise = new Promise.Completable<>(); - stream.push(pushFrame, promise, new Stream.Listener.Adapter()); - return promise; - }) - // ... wait for the pushed streams... - .reduce(result, (cfList, cfStream) -> cfList.thenCombine(cfStream, add), - (cfList1, cfList2) -> cfList1.thenCombine(cfList2, addAll)) - // ... then push one extra stream, the client must reject it... - .thenApply(streams -> - { - PushPromiseFrame extraPushFrame = new PushPromiseFrame(stream.getId(), 0, newRequest("GET", "/push_extra", new HttpFields())); - FuturePromise extraPromise = new FuturePromise<>(); - stream.push(extraPushFrame, extraPromise, new Stream.Listener.Adapter() + @Override + public void onReset(Stream stream, ResetFrame frame) { - @Override - public void onReset(Stream stream, ResetFrame frame) - { - assertEquals(ErrorCode.REFUSED_STREAM_ERROR.code, frame.getError()); - resetLatch.countDown(); - } - }); - return streams; - }) - // ... then send the data for the valid pushed streams... - .thenAccept(streams -> streams.forEach(pushedStream -> - { - DataFrame data = new DataFrame(pushedStream.getId(), BufferUtil.EMPTY_BUFFER, true); - pushedStream.data(data, Callback.NOOP); - })) - // ... then send the response. - .thenRun(() -> - { - MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields()); - stream.headers(new HeadersFrame(stream.getId(), response, null, true), Callback.NOOP); + assertEquals(ErrorCode.REFUSED_STREAM_ERROR.code, frame.getError()); + resetLatch.countDown(); + } }); + return streams; + }) + // ... then send the data for the valid pushed streams... + .thenAccept(streams -> streams.forEach(pushedStream -> + { + DataFrame data = new DataFrame(pushedStream.getId(), BufferUtil.EMPTY_BUFFER, true); + pushedStream.data(data, Callback.NOOP); + })) + // ... then send the response. + .thenRun(() -> + { + MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields()); + stream.headers(new HeadersFrame(stream.getId(), response, null, true), Callback.NOOP); + }); return null; } }); diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PingTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PingTest.java index 7c8c8bb0569..61e4ef15a79 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PingTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PingTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,9 +18,6 @@ package org.eclipse.jetty.http2.client; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.util.Random; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -29,9 +26,11 @@ import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.api.server.ServerSessionListener; import org.eclipse.jetty.http2.frames.PingFrame; import org.eclipse.jetty.util.Callback; - import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class PingTest extends AbstractTest { @Test diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PrefaceTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PrefaceTest.java index 835db222aac..6177fd68b95 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PrefaceTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PrefaceTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,12 +18,6 @@ package org.eclipse.jetty.http2.client; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.greaterThanOrEqualTo; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; @@ -65,6 +59,12 @@ import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Promise; import org.junit.jupiter.api.Test; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +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 PrefaceTest extends AbstractTest { @Test @@ -238,8 +238,8 @@ public class PrefaceTest extends AbstractTest { socket.connect(new InetSocketAddress("localhost", connector.getLocalPort())); - String upgradeRequest = "" + - "GET /one HTTP/1.1\r\n" + + String upgradeRequest = + "GET /one HTTP/1.1\r\n" + "Host: localhost\r\n" + "Connection: Upgrade, HTTP2-Settings\r\n" + "Upgrade: h2c\r\n" + @@ -254,7 +254,8 @@ public class PrefaceTest extends AbstractTest // The 101 response is the reply to the client preface SETTINGS frame. ByteBuffer buffer = byteBufferPool.acquire(1024, true); - http1: while (true) + http1: + while (true) { BufferUtil.clearToFill(buffer); int read = socket.read(buffer); diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PriorityTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PriorityTest.java index 0832264bd07..25a80e45f54 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PriorityTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PriorityTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,10 +18,6 @@ package org.eclipse.jetty.http2.client; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -36,9 +32,12 @@ import org.eclipse.jetty.http2.frames.PriorityFrame; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.FuturePromise; import org.eclipse.jetty.util.Promise; - import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class PriorityTest extends AbstractTest { @Test diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/ProxyProtocolTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/ProxyProtocolTest.java index dffd55f185f..e5557b1ae91 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/ProxyProtocolTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/ProxyProtocolTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,13 +18,6 @@ package org.eclipse.jetty.http2.client; -import static org.hamcrest.CoreMatchers.instanceOf; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import static org.hamcrest.MatcherAssert.assertThat; - import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; @@ -32,7 +25,6 @@ import java.nio.channels.SocketChannel; import java.nio.charset.StandardCharsets; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -56,11 +48,17 @@ import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.util.FuturePromise; import org.eclipse.jetty.util.Promise; +import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.TypeUtil; import org.junit.jupiter.api.AfterEach; - import org.junit.jupiter.api.Test; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.instanceOf; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class ProxyProtocolTest { private Server server; @@ -98,12 +96,12 @@ public class ProxyProtocolTest { try { - assertEquals("1.2.3.4",request.getRemoteAddr()); - assertEquals(1111,request.getRemotePort()); - assertEquals("5.6.7.8",request.getLocalAddr()); - assertEquals(2222,request.getLocalPort()); + assertEquals("1.2.3.4", request.getRemoteAddr()); + assertEquals(1111, request.getRemotePort()); + assertEquals("5.6.7.8", request.getLocalAddr()); + assertEquals(2222, request.getLocalPort()); } - catch(Throwable th) + catch (Throwable th) { th.printStackTrace(); response.setStatus(500); @@ -139,7 +137,7 @@ public class ProxyProtocolTest }); assertTrue(latch.await(5, TimeUnit.SECONDS)); } - + @Test public void test_PROXY_GET_v2() throws Exception { @@ -150,16 +148,16 @@ public class ProxyProtocolTest { try { - assertEquals("10.0.0.4",request.getRemoteAddr()); - assertEquals(33824,request.getRemotePort()); - assertEquals("10.0.0.5",request.getLocalAddr()); - assertEquals(8888,request.getLocalPort()); + assertEquals("10.0.0.4", request.getRemoteAddr()); + assertEquals(33824, request.getRemotePort()); + assertEquals("10.0.0.5", request.getLocalAddr()); + assertEquals(8888, request.getLocalPort()); EndPoint endPoint = baseRequest.getHttpChannel().getEndPoint(); assertThat(endPoint, instanceOf(ProxyConnectionFactory.ProxyEndPoint.class)); ProxyConnectionFactory.ProxyEndPoint proxyEndPoint = (ProxyConnectionFactory.ProxyEndPoint)endPoint; assertNotNull(proxyEndPoint.getAttribute(ProxyConnectionFactory.TLS_VERSION)); } - catch(Throwable th) + catch (Throwable th) { th.printStackTrace(); response.setStatus(500); @@ -170,7 +168,7 @@ public class ProxyProtocolTest // String is: "MAGIC VER|CMD FAM|PROT LEN SRC_ADDR DST_ADDR SRC_PORT DST_PORT PP2_TYPE_SSL LEN CLIENT VERIFY PP2_SUBTYPE_SSL_VERSION LEN 1.2" String request1 = "0D0A0D0A000D0A515549540A 21 11 001A 0A000004 0A000005 8420 22B8 20 000B 01 00000000 21 0003 312E32"; - request1 = request1.replace(" ", ""); + request1 = StringUtil.strip(request1, " "); SocketChannel channel = SocketChannel.open(); channel.connect(new InetSocketAddress("localhost", connector.getLocalPort())); channel.write(ByteBuffer.wrap(TypeUtil.fromHexString(request1))); diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/ProxyTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/ProxyTest.java index c5eec2e1155..1790ce2c1bd 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/ProxyTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/ProxyTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,15 +18,12 @@ package org.eclipse.jetty.http2.client; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.IOException; import java.net.InetSocketAddress; import java.util.HashMap; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; - import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -56,6 +53,8 @@ import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class ProxyTest { private HTTP2Client client; diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PushCacheFilterTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PushCacheFilterTest.java index a8bb32169eb..86141934dd6 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PushCacheFilterTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PushCacheFilterTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,10 +18,6 @@ package org.eclipse.jetty.http2.client; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.EnumSet; @@ -29,7 +25,6 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; - import javax.servlet.DispatcherType; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; @@ -56,9 +51,12 @@ import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlets.PushCacheFilter; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Promise; - 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 PushCacheFilterTest extends AbstractTest { private String contextPath = "/push"; @@ -744,7 +742,7 @@ public class PushCacheFilterTest extends AbstractTest { String name = "foo"; String value = "bar"; - final String primaryResource = "/primary.html?"+name + "=" +value; + final String primaryResource = "/primary.html?" + name + "=" + value; final String secondaryResource = "/secondary.html?" + name + "=" + value; start(new HttpServlet() { diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/RawHTTP2ProxyTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/RawHTTP2ProxyTest.java index 5b9f3ad3f3c..2f5f47c6ecd 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/RawHTTP2ProxyTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/RawHTTP2ProxyTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,9 +18,6 @@ package org.eclipse.jetty.http2.client; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.util.ArrayDeque; @@ -60,9 +57,11 @@ import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.junit.jupiter.api.AfterEach; - import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class RawHTTP2ProxyTest { private static final Logger LOGGER = Log.getLogger(RawHTTP2ProxyTest.class); @@ -110,7 +109,6 @@ public class RawHTTP2ProxyTest } } - @Test public void testRawHTTP2Proxy() throws Exception { @@ -569,7 +567,7 @@ public class RawHTTP2ProxyTest if (frameInfo != null) { serverToProxyStream = entry.getKey(); - proxyToClientStream = streams.get(serverToProxyStream); + proxyToClientStream = streams.get(serverToProxyStream); break; } } diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/SessionFailureTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/SessionFailureTest.java index f4787700a21..e0ea4b8b880 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/SessionFailureTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/SessionFailureTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,10 +18,6 @@ package org.eclipse.jetty.http2.client; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.lessThanOrEqualTo; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; @@ -38,6 +34,10 @@ import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Promise; import org.junit.jupiter.api.Test; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.lessThanOrEqualTo; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class SessionFailureTest extends AbstractTest { @Test @@ -125,7 +125,7 @@ public class SessionFailureTest extends AbstractTest long now = System.nanoTime(); while (((HTTP2Session)session).getEndPoint().isOpen()) { - assertThat(TimeUnit.NANOSECONDS.toSeconds(now-start), lessThanOrEqualTo(5L)); + assertThat(TimeUnit.NANOSECONDS.toSeconds(now - start), lessThanOrEqualTo(5L)); Thread.sleep(10); now = System.nanoTime(); diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/SimpleFlowControlStrategyTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/SimpleFlowControlStrategyTest.java index 4e4f84b315e..ba85d9148be 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/SimpleFlowControlStrategyTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/SimpleFlowControlStrategyTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/SmallThreadPoolLoadTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/SmallThreadPoolLoadTest.java index e67928f5e4d..e6a682af0c8 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/SmallThreadPoolLoadTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/SmallThreadPoolLoadTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,9 +18,6 @@ package org.eclipse.jetty.http2.client; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.IOException; import java.nio.ByteBuffer; import java.util.Locale; @@ -30,7 +27,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import java.util.stream.IntStream; - import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -55,10 +51,12 @@ import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.eclipse.jetty.util.thread.Scheduler; import org.hamcrest.Matchers; - import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertTrue; + @Disabled public class SmallThreadPoolLoadTest extends AbstractTest { @@ -88,10 +86,10 @@ public class SmallThreadPoolLoadTest extends AbstractTest int runs = 10; int iterations = 512; boolean result = IntStream.range(0, 16).parallel() - .mapToObj(i -> IntStream.range(0, runs) - .mapToObj(j -> run(session, iterations)) - .reduce(true, (acc, res) -> acc && res)) - .reduce(true, (acc, res) -> acc && res); + .mapToObj(i -> IntStream.range(0, runs) + .mapToObj(j -> run(session, iterations)) + .reduce(true, (acc, res) -> acc && res)) + .reduce(true, (acc, res) -> acc && res); assertTrue(result); } @@ -108,8 +106,8 @@ public class SmallThreadPoolLoadTest extends AbstractTest Scheduler.Task task = client.getScheduler().schedule(() -> { logger.warn("Interrupting test, it is taking too long{}Server:{}{}{}Client:{}{}", - System.lineSeparator(), System.lineSeparator(), server.dump(), - System.lineSeparator(), System.lineSeparator(), client.dump()); + System.lineSeparator(), System.lineSeparator(), server.dump(), + System.lineSeparator(), System.lineSeparator(), client.dump()); testThread.interrupt(); }, iterations * factor, TimeUnit.MILLISECONDS); @@ -128,9 +126,9 @@ public class SmallThreadPoolLoadTest extends AbstractTest task.cancel(); long elapsed = TimeUnit.NANOSECONDS.toMillis(end - begin); logger.info("{} requests in {} ms, {}/{} success/failure, {} req/s", - iterations, elapsed, - successes, iterations - successes, - elapsed > 0 ? iterations * 1000 / elapsed : -1); + iterations, elapsed, + successes, iterations - successes, + elapsed > 0 ? iterations * 1000 / elapsed : -1); return true; } catch (Exception x) @@ -193,8 +191,8 @@ public class SmallThreadPoolLoadTest extends AbstractTest latch.countDown(); else logger.warn("Request {} took too long{}Server:{}{}{}Client:{}{}", requestId, - System.lineSeparator(), System.lineSeparator(), server.dump(), - System.lineSeparator(), System.lineSeparator(), client.dump()); + System.lineSeparator(), System.lineSeparator(), server.dump(), + System.lineSeparator(), System.lineSeparator(), client.dump()); return !reset.get(); } @@ -215,10 +213,10 @@ public class SmallThreadPoolLoadTest extends AbstractTest } case "POST": { - int content_length=request.getContentLength(); - ByteArrayOutputStream2 bout = new ByteArrayOutputStream2(content_length>0?content_length:16*1024); + int content_length = request.getContentLength(); + ByteArrayOutputStream2 bout = new ByteArrayOutputStream2(content_length > 0 ? content_length : 16 * 1024); IO.copy(request.getInputStream(), bout); - response.getOutputStream().write(bout.getBuf(),0,bout.getCount()); + response.getOutputStream().write(bout.getBuf(), 0, bout.getCount()); break; } } diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamCloseTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamCloseTest.java index 4a20cb85540..bb2c05fee59 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamCloseTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamCloseTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,10 +18,6 @@ package org.eclipse.jetty.http2.client; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; @@ -45,9 +41,12 @@ import org.eclipse.jetty.http2.frames.ResetFrame; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.FuturePromise; import org.eclipse.jetty.util.Promise; - 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 StreamCloseTest extends AbstractTest { @Test @@ -355,6 +354,8 @@ public class StreamCloseTest extends AbstractTest assertEquals(0, serverSession.getStreams().size()); for (Stream stream : streams) + { assertTrue(stream.isClosed()); + } } } diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamCountTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamCountTest.java index 9a5d22f94c0..5227219e067 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamCountTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamCountTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,9 +18,6 @@ package org.eclipse.jetty.http2.client; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.util.HashMap; import java.util.Map; import java.util.concurrent.CountDownLatch; @@ -41,9 +38,11 @@ import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.FuturePromise; - import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class StreamCountTest extends AbstractTest { @Test @@ -115,7 +114,7 @@ public class StreamCountTest extends AbstractTest session.newStream(frame2, streamPromise2, new Stream.Listener.Adapter()); assertThrows(ExecutionException.class, - () -> streamPromise2.get(5, TimeUnit.SECONDS)); + () -> streamPromise2.get(5, TimeUnit.SECONDS)); stream1.data(new DataFrame(stream1.getId(), BufferUtil.EMPTY_BUFFER, true), Callback.NOOP); assertTrue(responseLatch.await(5, TimeUnit.SECONDS)); diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamResetTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamResetTest.java index bae4c00c3ad..8bc64030bbf 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamResetTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamResetTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,27 +18,26 @@ package org.eclipse.jetty.http2.client; -import static org.hamcrest.MatcherAssert.assertThat; -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.assertTrue; - import java.io.IOException; import java.io.InterruptedIOException; +import java.net.InetSocketAddress; import java.nio.ByteBuffer; +import java.nio.channels.SocketChannel; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Exchanger; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; - import javax.servlet.AsyncContext; import javax.servlet.ServletOutputStream; import javax.servlet.WriteListener; @@ -47,7 +46,9 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.ErrorCode; @@ -61,12 +62,20 @@ import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.api.server.ServerSessionListener; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.http2.frames.PrefaceFrame; import org.eclipse.jetty.http2.frames.ResetFrame; +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.server.AbstractHTTP2ServerConnectionFactory; import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory; +import org.eclipse.jetty.io.AbstractEndPoint; +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.io.WriteFlusher; import org.eclipse.jetty.server.HttpChannel; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpOutput; +import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.servlet.ServletContextHandler; @@ -79,9 +88,14 @@ import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.log.StacklessLogging; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.hamcrest.Matchers; - import org.junit.jupiter.api.Test; +import static org.hamcrest.MatcherAssert.assertThat; +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.assertTrue; + public class StreamResetTest extends AbstractTest { @Test @@ -167,14 +181,14 @@ public class StreamResetTest extends AbstractTest { callback.succeeded(); completable.thenRun(() -> - stream.data(new DataFrame(stream.getId(), ByteBuffer.allocate(16), true), new Callback() + stream.data(new DataFrame(stream.getId(), ByteBuffer.allocate(16), true), new Callback() + { + @Override + public void succeeded() { - @Override - public void succeeded() - { - serverDataLatch.countDown(); - } - })); + serverDataLatch.countDown(); + } + })); } @Override @@ -570,7 +584,7 @@ public class StreamResetTest extends AbstractTest }); Session client = newClient(new Session.Listener.Adapter()); - + MetaData.Request request = newRequest("GET", new HttpFields()); HeadersFrame frame = new HeadersFrame(request, null, false); FuturePromise promise = new FuturePromise<>(); @@ -835,4 +849,210 @@ public class StreamResetTest extends AbstractTest // Read on server should fail. assertTrue(failureLatch.await(5, TimeUnit.SECONDS)); } + + @Test + public void testResetAfterTCPCongestedWrite() throws Exception + { + AtomicReference flusherRef = new AtomicReference<>(); + CountDownLatch flusherLatch = new CountDownLatch(1); + CountDownLatch writeLatch1 = new CountDownLatch(1); + CountDownLatch writeLatch2 = new CountDownLatch(1); + start(new EmptyHttpServlet() + { + @Override + protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException + { + Request jettyRequest = (Request)request; + flusherRef.set(((AbstractEndPoint)jettyRequest.getHttpChannel().getEndPoint()).getWriteFlusher()); + flusherLatch.countDown(); + + ServletOutputStream output = response.getOutputStream(); + try + { + // Large write, it blocks due to TCP congestion. + byte[] data = new byte[128 * 1024 * 1024]; + output.write(data); + } + catch (IOException x) + { + writeLatch1.countDown(); + try + { + // Try to write again, must fail immediately. + output.write(0xFF); + } + catch (IOException e) + { + writeLatch2.countDown(); + } + } + } + }); + + ByteBufferPool byteBufferPool = client.getByteBufferPool(); + try (SocketChannel socket = SocketChannel.open()) + { + String host = "localhost"; + int port = connector.getLocalPort(); + socket.connect(new InetSocketAddress(host, port)); + + Generator generator = new Generator(byteBufferPool); + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.control(lease, new PrefaceFrame()); + Map clientSettings = new HashMap<>(); + // Max stream HTTP/2 flow control window. + clientSettings.put(SettingsFrame.INITIAL_WINDOW_SIZE, Integer.MAX_VALUE); + generator.control(lease, new SettingsFrame(clientSettings, false)); + // Max session HTTP/2 flow control window. + generator.control(lease, new WindowUpdateFrame(0, Integer.MAX_VALUE - FlowControlStrategy.DEFAULT_WINDOW_SIZE)); + + HttpURI uri = new HttpURI("http", host, port, servletPath); + MetaData.Request request = new MetaData.Request(HttpMethod.GET.asString(), uri, HttpVersion.HTTP_2, new HttpFields()); + int streamId = 3; + HeadersFrame headersFrame = new HeadersFrame(streamId, request, null, true); + generator.control(lease, headersFrame); + + List buffers = lease.getByteBuffers(); + socket.write(buffers.toArray(new ByteBuffer[0])); + + // Wait until the server is TCP congested. + assertTrue(flusherLatch.await(5, TimeUnit.SECONDS)); + WriteFlusher flusher = flusherRef.get(); + waitUntilTCPCongested(flusher); + + lease.recycle(); + generator.control(lease, new ResetFrame(streamId, ErrorCode.CANCEL_STREAM_ERROR.code)); + buffers = lease.getByteBuffers(); + socket.write(buffers.toArray(new ByteBuffer[0])); + + assertTrue(writeLatch1.await(5, TimeUnit.SECONDS)); + assertTrue(writeLatch2.await(5, TimeUnit.SECONDS)); + } + } + + @Test + public void testResetSecondRequestAfterTCPCongestedWriteBeforeWrite() throws Exception + { + Exchanger exchanger = new Exchanger<>(); + CountDownLatch requestLatch1 = new CountDownLatch(1); + CountDownLatch requestLatch2 = new CountDownLatch(1); + CountDownLatch writeLatch1 = new CountDownLatch(1); + start(new EmptyHttpServlet() + { + @Override + protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException + { + if (request.getPathInfo().equals("/1")) + service1(request, response); + else if (request.getPathInfo().equals("/2")) + service2(request, response); + else + throw new IllegalArgumentException(); + } + + private void service1(HttpServletRequest request, HttpServletResponse response) throws IOException + { + try + { + Request jettyRequest = (Request)request; + exchanger.exchange(((AbstractEndPoint)jettyRequest.getHttpChannel().getEndPoint()).getWriteFlusher()); + + ServletOutputStream output = response.getOutputStream(); + // Large write, it blocks due to TCP congestion. + output.write(new byte[128 * 1024 * 1024]); + } + catch (InterruptedException x) + { + throw new InterruptedIOException(); + } + } + + private void service2(HttpServletRequest request, HttpServletResponse response) throws IOException + { + try + { + requestLatch1.countDown(); + requestLatch2.await(); + ServletOutputStream output = response.getOutputStream(); + int length = 512 * 1024; + AbstractHTTP2ServerConnectionFactory h2 = connector.getConnectionFactory(AbstractHTTP2ServerConnectionFactory.class); + if (h2 != null) + length = h2.getHttpConfiguration().getOutputAggregationSize(); + // Medium write so we don't aggregate it, must not block. + output.write(new byte[length * 2]); + } + catch (IOException x) + { + writeLatch1.countDown(); + } + catch (InterruptedException x) + { + throw new InterruptedIOException(); + } + } + }); + + ByteBufferPool byteBufferPool = client.getByteBufferPool(); + try (SocketChannel socket = SocketChannel.open()) + { + String host = "localhost"; + int port = connector.getLocalPort(); + socket.connect(new InetSocketAddress(host, port)); + + Generator generator = new Generator(byteBufferPool); + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.control(lease, new PrefaceFrame()); + Map clientSettings = new HashMap<>(); + // Max stream HTTP/2 flow control window. + clientSettings.put(SettingsFrame.INITIAL_WINDOW_SIZE, Integer.MAX_VALUE); + generator.control(lease, new SettingsFrame(clientSettings, false)); + // Max session HTTP/2 flow control window. + generator.control(lease, new WindowUpdateFrame(0, Integer.MAX_VALUE - FlowControlStrategy.DEFAULT_WINDOW_SIZE)); + + HttpURI uri = new HttpURI("http", host, port, servletPath + "/1"); + MetaData.Request request = new MetaData.Request(HttpMethod.GET.asString(), uri, HttpVersion.HTTP_2, new HttpFields()); + HeadersFrame headersFrame = new HeadersFrame(3, request, null, true); + generator.control(lease, headersFrame); + + List buffers = lease.getByteBuffers(); + socket.write(buffers.toArray(new ByteBuffer[0])); + + waitUntilTCPCongested(exchanger.exchange(null)); + + // Send a second request. + uri = new HttpURI("http", host, port, servletPath + "/2"); + request = new MetaData.Request(HttpMethod.GET.asString(), uri, HttpVersion.HTTP_2, new HttpFields()); + int streamId = 5; + headersFrame = new HeadersFrame(streamId, request, null, true); + generator.control(lease, headersFrame); + buffers = lease.getByteBuffers(); + socket.write(buffers.toArray(new ByteBuffer[0])); + assertTrue(requestLatch1.await(5, TimeUnit.SECONDS)); + + // Now reset the second request, which has not started writing yet. + lease.recycle(); + generator.control(lease, new ResetFrame(streamId, ErrorCode.CANCEL_STREAM_ERROR.code)); + buffers = lease.getByteBuffers(); + socket.write(buffers.toArray(new ByteBuffer[0])); + // Wait to be sure that the server processed the reset. + Thread.sleep(1000); + // Let the request write, it should not block. + requestLatch2.countDown(); + assertTrue(writeLatch1.await(5, TimeUnit.SECONDS)); + } + } + + private void waitUntilTCPCongested(WriteFlusher flusher) throws TimeoutException, InterruptedException + { + long start = System.nanoTime(); + while (!flusher.isPending()) + { + long elapsed = System.nanoTime() - start; + if (TimeUnit.NANOSECONDS.toSeconds(elapsed) > 15) + throw new TimeoutException(); + Thread.sleep(100); + } + // Wait for the selector to update the SelectionKey to OP_WRITE. + Thread.sleep(1000); + } } diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/TrailersTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/TrailersTest.java index b2007ec6efe..1751968b9da 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/TrailersTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/TrailersTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,16 +18,6 @@ package org.eclipse.jetty.http2.client; -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.assertTrue; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; - import java.io.IOException; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; @@ -35,7 +25,6 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; - import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -58,10 +47,14 @@ import org.eclipse.jetty.server.Response; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.FuturePromise; import org.eclipse.jetty.util.Promise; - import org.eclipse.jetty.util.StringUtil; 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.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; public class TrailersTest extends AbstractTest { @@ -289,7 +282,7 @@ public class TrailersTest extends AbstractTest assertTrue(latch.await(5, TimeUnit.SECONDS)); - assertTrue( frames.size()==3, frames.toString()); + assertEquals(3, frames.size(), frames.toString()); HeadersFrame headers = (HeadersFrame)frames.get(0); DataFrame data = (DataFrame)frames.get(1); @@ -298,7 +291,7 @@ public class TrailersTest extends AbstractTest assertFalse(headers.isEndStream()); assertFalse(data.isEndStream()); assertTrue(trailers.isEndStream()); - assertTrue(trailers.getMetaData().getFields().get(trailerName).equals(trailerValue)); + assertEquals(trailers.getMetaData().getFields().get(trailerName), trailerValue); } @Test @@ -343,7 +336,7 @@ public class TrailersTest extends AbstractTest } }); Stream stream = promise.get(5, TimeUnit.SECONDS); - ByteBuffer data = ByteBuffer.wrap( StringUtil.getUtf8Bytes( "hello")); + ByteBuffer data = ByteBuffer.wrap(StringUtil.getUtf8Bytes("hello")); Callback.Completable completable = new Callback.Completable(); stream.data(new DataFrame(stream.getId(), data, false), completable); completable.thenRun(() -> @@ -358,6 +351,5 @@ public class TrailersTest extends AbstractTest assertTrue(serverLatch.await(5, TimeUnit.SECONDS)); assertTrue(clientLatch.await(5, TimeUnit.SECONDS)); - } } diff --git a/jetty-http2/http2-common/pom.xml b/jetty-http2/http2-common/pom.xml index d9bcdda6058..cf959c3a5d8 100644 --- a/jetty-http2/http2-common/pom.xml +++ b/jetty-http2/http2-common/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.http2 http2-parent - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/AbstractFlowControlStrategy.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/AbstractFlowControlStrategy.java index 16a0068a8e6..80c66c2af0b 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/AbstractFlowControlStrategy.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/AbstractFlowControlStrategy.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -29,7 +29,6 @@ import org.eclipse.jetty.http2.frames.WindowUpdateFrame; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.annotation.ManagedOperation; -import org.eclipse.jetty.util.component.ContainerLifeCycle; import org.eclipse.jetty.util.component.Dumpable; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -243,7 +242,7 @@ public abstract class AbstractFlowControlStrategy implements FlowControlStrategy @Override public String dump() { - return ContainerLifeCycle.dump(this); + return Dumpable.dump(this); } @Override diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/BufferingFlowControlStrategy.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/BufferingFlowControlStrategy.java index cfff9b01b84..7eff31981e2 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/BufferingFlowControlStrategy.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/BufferingFlowControlStrategy.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -170,7 +170,7 @@ public class BufferingFlowControlStrategy extends AbstractFlowControlStrategy // and here we keep track of its max value. // Updating the max session recv window is done here - // so that if a peer decides to send an unilateral + // so that if a peer decides to send a unilateral // window update to enlarge the session window, // without the corresponding data consumption, here // we can track it. @@ -201,11 +201,11 @@ public class BufferingFlowControlStrategy extends AbstractFlowControlStrategy public String toString() { return String.format("%s@%x[ratio=%.2f,sessionLevel=%s,sessionStallTime=%dms,streamsStallTime=%dms]", - getClass().getSimpleName(), - hashCode(), - bufferRatio, - sessionLevel, - getSessionStallTime(), - getStreamsStallTime()); + getClass().getSimpleName(), + hashCode(), + bufferRatio, + sessionLevel, + getSessionStallTime(), + getStreamsStallTime()); } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/CloseState.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/CloseState.java index 5ee85cbec56..6b90b89165f 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/CloseState.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/CloseState.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ErrorCode.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ErrorCode.java index aae6c082ccd..4269bc67d1f 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ErrorCode.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ErrorCode.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -40,7 +40,7 @@ public enum ErrorCode */ INTERNAL_ERROR(2), /** - * Indicates a HTTP/2 flow control violation. + * Indicates an HTTP/2 flow control violation. */ FLOW_CONTROL_ERROR(3), /** @@ -68,7 +68,7 @@ public enum ErrorCode */ COMPRESSION_ERROR(9), /** - * Indicates that the connection established by a HTTP CONNECT was abnormally closed. + * Indicates that the connection established by an HTTP CONNECT was abnormally closed. */ HTTP_CONNECT_ERROR(10), /** @@ -86,7 +86,7 @@ public enum ErrorCode public final int code; - private ErrorCode(int code) + ErrorCode(int code) { this.code = code; Codes.codes.put(code, this); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/Flags.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/Flags.java index f4ee05a3c1b..be6ab297d1c 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/Flags.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/Flags.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,10 +20,10 @@ package org.eclipse.jetty.http2; public interface Flags { - public static final int NONE = 0x00; - public static final int END_STREAM = 0x01; - public static final int ACK = 0x01; - public static final int END_HEADERS = 0x04; - public static final int PADDING = 0x08; - public static final int PRIORITY = 0x20; + int NONE = 0x00; + int END_STREAM = 0x01; + int ACK = 0x01; + int END_HEADERS = 0x04; + int PADDING = 0x08; + int PRIORITY = 0x20; } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/FlowControlStrategy.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/FlowControlStrategy.java index 7b536d729f0..5062d7b7c37 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/FlowControlStrategy.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/FlowControlStrategy.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -22,28 +22,28 @@ import org.eclipse.jetty.http2.frames.WindowUpdateFrame; public interface FlowControlStrategy { - public static int DEFAULT_WINDOW_SIZE = 65535; + int DEFAULT_WINDOW_SIZE = 65535; - public void onStreamCreated(IStream stream); + void onStreamCreated(IStream stream); - public void onStreamDestroyed(IStream stream); + void onStreamDestroyed(IStream stream); - public void updateInitialStreamWindow(ISession session, int initialStreamWindow, boolean local); + void updateInitialStreamWindow(ISession session, int initialStreamWindow, boolean local); - public void onWindowUpdate(ISession session, IStream stream, WindowUpdateFrame frame); + void onWindowUpdate(ISession session, IStream stream, WindowUpdateFrame frame); - public void onDataReceived(ISession session, IStream stream, int length); + void onDataReceived(ISession session, IStream stream, int length); - public void onDataConsumed(ISession session, IStream stream, int length); + void onDataConsumed(ISession session, IStream stream, int length); - public void windowUpdate(ISession session, IStream stream, WindowUpdateFrame frame); + void windowUpdate(ISession session, IStream stream, WindowUpdateFrame frame); - public void onDataSending(IStream stream, int length); + void onDataSending(IStream stream, int length); - public void onDataSent(IStream stream, int length); + void onDataSent(IStream stream, int length); - public interface Factory + interface Factory { - public FlowControlStrategy newFlowControlStrategy(); + FlowControlStrategy newFlowControlStrategy(); } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Cipher.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Cipher.java index 9f3145201a5..e2135e2e68f 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Cipher.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Cipher.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -27,300 +27,300 @@ public class HTTP2Cipher { public static final Comparator COMPARATOR = new CipherComparator(); - private final static Trie __blackProtocols = new ArrayTrie<>(6*5); - private final static Trie __blackCiphers = new ArrayTrie<>(275*40); + private static final Trie __blackProtocols = new ArrayTrie<>(6 * 5); + private static final Trie __blackCiphers = new ArrayTrie<>(275 * 40); static { for (String p : new String[] + { + "TLSv1.2", "TLSv1.1", "TLSv1", "SSL", "SSLv2", "SSLv3" + }) { - "TLSv1.2","TLSv1.1", "TLSv1", "SSL", "SSLv2", "SSLv3" - }) - { - __blackProtocols.put(p,Boolean.TRUE); + __blackProtocols.put(p, Boolean.TRUE); } for (String c : new String[] + { + "TLS_NULL_WITH_NULL_NULL", + "TLS_RSA_WITH_NULL_MD5", + "TLS_RSA_WITH_NULL_SHA", + "TLS_RSA_EXPORT_WITH_RC4_40_MD5", + "TLS_RSA_WITH_RC4_128_MD5", + "TLS_RSA_WITH_RC4_128_SHA", + "TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5", + "TLS_RSA_WITH_IDEA_CBC_SHA", + "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA", + "TLS_RSA_WITH_DES_CBC_SHA", + "TLS_RSA_WITH_3DES_EDE_CBC_SHA", + "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA", + "TLS_DH_DSS_WITH_DES_CBC_SHA", + "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA", + "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA", + "TLS_DH_RSA_WITH_DES_CBC_SHA", + "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA", + "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", + "TLS_DHE_DSS_WITH_DES_CBC_SHA", + "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA", + "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", + "TLS_DHE_RSA_WITH_DES_CBC_SHA", + "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA", + "TLS_DH_anon_EXPORT_WITH_RC4_40_MD5", + "TLS_DH_anon_WITH_RC4_128_MD5", + "TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA", + "TLS_DH_anon_WITH_DES_CBC_SHA", + "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA", + "TLS_KRB5_WITH_DES_CBC_SHA", + "TLS_KRB5_WITH_3DES_EDE_CBC_SHA", + "TLS_KRB5_WITH_RC4_128_SHA", + "TLS_KRB5_WITH_IDEA_CBC_SHA", + "TLS_KRB5_WITH_DES_CBC_MD5", + "TLS_KRB5_WITH_3DES_EDE_CBC_MD5", + "TLS_KRB5_WITH_RC4_128_MD5", + "TLS_KRB5_WITH_IDEA_CBC_MD5", + "TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA", + "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA", + "TLS_KRB5_EXPORT_WITH_RC4_40_SHA", + "TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5", + "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5", + "TLS_KRB5_EXPORT_WITH_RC4_40_MD5", + "TLS_PSK_WITH_NULL_SHA", + "TLS_DHE_PSK_WITH_NULL_SHA", + "TLS_RSA_PSK_WITH_NULL_SHA", + "TLS_RSA_WITH_AES_128_CBC_SHA", + "TLS_DH_DSS_WITH_AES_128_CBC_SHA", + "TLS_DH_RSA_WITH_AES_128_CBC_SHA", + "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", + "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", + "TLS_DH_anon_WITH_AES_128_CBC_SHA", + "TLS_RSA_WITH_AES_256_CBC_SHA", + "TLS_DH_DSS_WITH_AES_256_CBC_SHA", + "TLS_DH_RSA_WITH_AES_256_CBC_SHA", + "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", + "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", + "TLS_DH_anon_WITH_AES_256_CBC_SHA", + "TLS_RSA_WITH_NULL_SHA256", + "TLS_RSA_WITH_AES_128_CBC_SHA256", + "TLS_RSA_WITH_AES_256_CBC_SHA256", + "TLS_DH_DSS_WITH_AES_128_CBC_SHA256", + "TLS_DH_RSA_WITH_AES_128_CBC_SHA256", + "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", + "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA", + "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA", + "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA", + "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA", + "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA", + "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA", + "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", + "TLS_DH_DSS_WITH_AES_256_CBC_SHA256", + "TLS_DH_RSA_WITH_AES_256_CBC_SHA256", + "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", + "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", + "TLS_DH_anon_WITH_AES_128_CBC_SHA256", + "TLS_DH_anon_WITH_AES_256_CBC_SHA256", + "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA", + "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA", + "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA", + "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA", + "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA", + "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA", + "TLS_PSK_WITH_RC4_128_SHA", + "TLS_PSK_WITH_3DES_EDE_CBC_SHA", + "TLS_PSK_WITH_AES_128_CBC_SHA", + "TLS_PSK_WITH_AES_256_CBC_SHA", + "TLS_DHE_PSK_WITH_RC4_128_SHA", + "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA", + "TLS_DHE_PSK_WITH_AES_128_CBC_SHA", + "TLS_DHE_PSK_WITH_AES_256_CBC_SHA", + "TLS_RSA_PSK_WITH_RC4_128_SHA", + "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA", + "TLS_RSA_PSK_WITH_AES_128_CBC_SHA", + "TLS_RSA_PSK_WITH_AES_256_CBC_SHA", + "TLS_RSA_WITH_SEED_CBC_SHA", + "TLS_DH_DSS_WITH_SEED_CBC_SHA", + "TLS_DH_RSA_WITH_SEED_CBC_SHA", + "TLS_DHE_DSS_WITH_SEED_CBC_SHA", + "TLS_DHE_RSA_WITH_SEED_CBC_SHA", + "TLS_DH_anon_WITH_SEED_CBC_SHA", + "TLS_RSA_WITH_AES_128_GCM_SHA256", + "TLS_RSA_WITH_AES_256_GCM_SHA384", + "TLS_DH_RSA_WITH_AES_128_GCM_SHA256", + "TLS_DH_RSA_WITH_AES_256_GCM_SHA384", + "TLS_DH_DSS_WITH_AES_128_GCM_SHA256", + "TLS_DH_DSS_WITH_AES_256_GCM_SHA384", + "TLS_DH_anon_WITH_AES_128_GCM_SHA256", + "TLS_DH_anon_WITH_AES_256_GCM_SHA384", + "TLS_PSK_WITH_AES_128_GCM_SHA256", + "TLS_PSK_WITH_AES_256_GCM_SHA384", + "TLS_RSA_PSK_WITH_AES_128_GCM_SHA256", + "TLS_RSA_PSK_WITH_AES_256_GCM_SHA384", + "TLS_PSK_WITH_AES_128_CBC_SHA256", + "TLS_PSK_WITH_AES_256_CBC_SHA384", + "TLS_PSK_WITH_NULL_SHA256", + "TLS_PSK_WITH_NULL_SHA384", + "TLS_DHE_PSK_WITH_AES_128_CBC_SHA256", + "TLS_DHE_PSK_WITH_AES_256_CBC_SHA384", + "TLS_DHE_PSK_WITH_NULL_SHA256", + "TLS_DHE_PSK_WITH_NULL_SHA384", + "TLS_RSA_PSK_WITH_AES_128_CBC_SHA256", + "TLS_RSA_PSK_WITH_AES_256_CBC_SHA384", + "TLS_RSA_PSK_WITH_NULL_SHA256", + "TLS_RSA_PSK_WITH_NULL_SHA384", + "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256", + "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256", + "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256", + "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256", + "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", + "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256", + "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256", + "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256", + "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256", + "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256", + "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256", + "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256", + "TLS_EMPTY_RENEGOTIATION_INFO_SCSV", + "TLS_ECDH_ECDSA_WITH_NULL_SHA", + "TLS_ECDH_ECDSA_WITH_RC4_128_SHA", + "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", + "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", + "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_NULL_SHA", + "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", + "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", + "TLS_ECDH_RSA_WITH_NULL_SHA", + "TLS_ECDH_RSA_WITH_RC4_128_SHA", + "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", + "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", + "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_RSA_WITH_NULL_SHA", + "TLS_ECDHE_RSA_WITH_RC4_128_SHA", + "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", + "TLS_ECDH_anon_WITH_NULL_SHA", + "TLS_ECDH_anon_WITH_RC4_128_SHA", + "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA", + "TLS_ECDH_anon_WITH_AES_128_CBC_SHA", + "TLS_ECDH_anon_WITH_AES_256_CBC_SHA", + "TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA", + "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA", + "TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA", + "TLS_SRP_SHA_WITH_AES_128_CBC_SHA", + "TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA", + "TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA", + "TLS_SRP_SHA_WITH_AES_256_CBC_SHA", + "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA", + "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", + "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256", + "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384", + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", + "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256", + "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384", + "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_PSK_WITH_RC4_128_SHA", + "TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA", + "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256", + "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384", + "TLS_ECDHE_PSK_WITH_NULL_SHA", + "TLS_ECDHE_PSK_WITH_NULL_SHA256", + "TLS_ECDHE_PSK_WITH_NULL_SHA384", + "TLS_RSA_WITH_ARIA_128_CBC_SHA256", + "TLS_RSA_WITH_ARIA_256_CBC_SHA384", + "TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256", + "TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384", + "TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256", + "TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384", + "TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256", + "TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384", + "TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256", + "TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384", + "TLS_DH_anon_WITH_ARIA_128_CBC_SHA256", + "TLS_DH_anon_WITH_ARIA_256_CBC_SHA384", + "TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256", + "TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384", + "TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256", + "TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384", + "TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256", + "TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384", + "TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256", + "TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384", + "TLS_RSA_WITH_ARIA_128_GCM_SHA256", + "TLS_RSA_WITH_ARIA_256_GCM_SHA384", + "TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256", + "TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384", + "TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256", + "TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384", + "TLS_DH_anon_WITH_ARIA_128_GCM_SHA256", + "TLS_DH_anon_WITH_ARIA_256_GCM_SHA384", + "TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256", + "TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384", + "TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256", + "TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384", + "TLS_PSK_WITH_ARIA_128_CBC_SHA256", + "TLS_PSK_WITH_ARIA_256_CBC_SHA384", + "TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256", + "TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384", + "TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256", + "TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384", + "TLS_PSK_WITH_ARIA_128_GCM_SHA256", + "TLS_PSK_WITH_ARIA_256_GCM_SHA384", + "TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256", + "TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384", + "TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256", + "TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384", + "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", + "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", + "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", + "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", + "TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", + "TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384", + "TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256", + "TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384", + "TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256", + "TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384", + "TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256", + "TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384", + "TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256", + "TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384", + "TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256", + "TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384", + "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256", + "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384", + "TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256", + "TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384", + "TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256", + "TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384", + "TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256", + "TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384", + "TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256", + "TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384", + "TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", + "TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", + "TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256", + "TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384", + "TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", + "TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", + "TLS_RSA_WITH_AES_128_CCM", + "TLS_RSA_WITH_AES_256_CCM", + "TLS_RSA_WITH_AES_128_CCM_8", + "TLS_RSA_WITH_AES_256_CCM_8", + "TLS_PSK_WITH_AES_128_CCM", + "TLS_PSK_WITH_AES_256_CCM", + "TLS_PSK_WITH_AES_128_CCM_8", + "TLS_PSK_WITH_AES_256_CCM_8" + }) { - "TLS_NULL_WITH_NULL_NULL", - "TLS_RSA_WITH_NULL_MD5", - "TLS_RSA_WITH_NULL_SHA", - "TLS_RSA_EXPORT_WITH_RC4_40_MD5", - "TLS_RSA_WITH_RC4_128_MD5", - "TLS_RSA_WITH_RC4_128_SHA", - "TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5", - "TLS_RSA_WITH_IDEA_CBC_SHA", - "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA", - "TLS_RSA_WITH_DES_CBC_SHA", - "TLS_RSA_WITH_3DES_EDE_CBC_SHA", - "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA", - "TLS_DH_DSS_WITH_DES_CBC_SHA", - "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA", - "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA", - "TLS_DH_RSA_WITH_DES_CBC_SHA", - "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA", - "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", - "TLS_DHE_DSS_WITH_DES_CBC_SHA", - "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA", - "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", - "TLS_DHE_RSA_WITH_DES_CBC_SHA", - "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA", - "TLS_DH_anon_EXPORT_WITH_RC4_40_MD5", - "TLS_DH_anon_WITH_RC4_128_MD5", - "TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA", - "TLS_DH_anon_WITH_DES_CBC_SHA", - "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA", - "TLS_KRB5_WITH_DES_CBC_SHA", - "TLS_KRB5_WITH_3DES_EDE_CBC_SHA", - "TLS_KRB5_WITH_RC4_128_SHA", - "TLS_KRB5_WITH_IDEA_CBC_SHA", - "TLS_KRB5_WITH_DES_CBC_MD5", - "TLS_KRB5_WITH_3DES_EDE_CBC_MD5", - "TLS_KRB5_WITH_RC4_128_MD5", - "TLS_KRB5_WITH_IDEA_CBC_MD5", - "TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA", - "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA", - "TLS_KRB5_EXPORT_WITH_RC4_40_SHA", - "TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5", - "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5", - "TLS_KRB5_EXPORT_WITH_RC4_40_MD5", - "TLS_PSK_WITH_NULL_SHA", - "TLS_DHE_PSK_WITH_NULL_SHA", - "TLS_RSA_PSK_WITH_NULL_SHA", - "TLS_RSA_WITH_AES_128_CBC_SHA", - "TLS_DH_DSS_WITH_AES_128_CBC_SHA", - "TLS_DH_RSA_WITH_AES_128_CBC_SHA", - "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", - "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", - "TLS_DH_anon_WITH_AES_128_CBC_SHA", - "TLS_RSA_WITH_AES_256_CBC_SHA", - "TLS_DH_DSS_WITH_AES_256_CBC_SHA", - "TLS_DH_RSA_WITH_AES_256_CBC_SHA", - "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", - "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", - "TLS_DH_anon_WITH_AES_256_CBC_SHA", - "TLS_RSA_WITH_NULL_SHA256", - "TLS_RSA_WITH_AES_128_CBC_SHA256", - "TLS_RSA_WITH_AES_256_CBC_SHA256", - "TLS_DH_DSS_WITH_AES_128_CBC_SHA256", - "TLS_DH_RSA_WITH_AES_128_CBC_SHA256", - "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", - "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA", - "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA", - "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA", - "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA", - "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA", - "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA", - "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", - "TLS_DH_DSS_WITH_AES_256_CBC_SHA256", - "TLS_DH_RSA_WITH_AES_256_CBC_SHA256", - "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", - "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", - "TLS_DH_anon_WITH_AES_128_CBC_SHA256", - "TLS_DH_anon_WITH_AES_256_CBC_SHA256", - "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA", - "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA", - "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA", - "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA", - "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA", - "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA", - "TLS_PSK_WITH_RC4_128_SHA", - "TLS_PSK_WITH_3DES_EDE_CBC_SHA", - "TLS_PSK_WITH_AES_128_CBC_SHA", - "TLS_PSK_WITH_AES_256_CBC_SHA", - "TLS_DHE_PSK_WITH_RC4_128_SHA", - "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA", - "TLS_DHE_PSK_WITH_AES_128_CBC_SHA", - "TLS_DHE_PSK_WITH_AES_256_CBC_SHA", - "TLS_RSA_PSK_WITH_RC4_128_SHA", - "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA", - "TLS_RSA_PSK_WITH_AES_128_CBC_SHA", - "TLS_RSA_PSK_WITH_AES_256_CBC_SHA", - "TLS_RSA_WITH_SEED_CBC_SHA", - "TLS_DH_DSS_WITH_SEED_CBC_SHA", - "TLS_DH_RSA_WITH_SEED_CBC_SHA", - "TLS_DHE_DSS_WITH_SEED_CBC_SHA", - "TLS_DHE_RSA_WITH_SEED_CBC_SHA", - "TLS_DH_anon_WITH_SEED_CBC_SHA", - "TLS_RSA_WITH_AES_128_GCM_SHA256", - "TLS_RSA_WITH_AES_256_GCM_SHA384", - "TLS_DH_RSA_WITH_AES_128_GCM_SHA256", - "TLS_DH_RSA_WITH_AES_256_GCM_SHA384", - "TLS_DH_DSS_WITH_AES_128_GCM_SHA256", - "TLS_DH_DSS_WITH_AES_256_GCM_SHA384", - "TLS_DH_anon_WITH_AES_128_GCM_SHA256", - "TLS_DH_anon_WITH_AES_256_GCM_SHA384", - "TLS_PSK_WITH_AES_128_GCM_SHA256", - "TLS_PSK_WITH_AES_256_GCM_SHA384", - "TLS_RSA_PSK_WITH_AES_128_GCM_SHA256", - "TLS_RSA_PSK_WITH_AES_256_GCM_SHA384", - "TLS_PSK_WITH_AES_128_CBC_SHA256", - "TLS_PSK_WITH_AES_256_CBC_SHA384", - "TLS_PSK_WITH_NULL_SHA256", - "TLS_PSK_WITH_NULL_SHA384", - "TLS_DHE_PSK_WITH_AES_128_CBC_SHA256", - "TLS_DHE_PSK_WITH_AES_256_CBC_SHA384", - "TLS_DHE_PSK_WITH_NULL_SHA256", - "TLS_DHE_PSK_WITH_NULL_SHA384", - "TLS_RSA_PSK_WITH_AES_128_CBC_SHA256", - "TLS_RSA_PSK_WITH_AES_256_CBC_SHA384", - "TLS_RSA_PSK_WITH_NULL_SHA256", - "TLS_RSA_PSK_WITH_NULL_SHA384", - "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256", - "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256", - "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256", - "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256", - "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", - "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256", - "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256", - "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256", - "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256", - "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256", - "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256", - "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256", - "TLS_EMPTY_RENEGOTIATION_INFO_SCSV", - "TLS_ECDH_ECDSA_WITH_NULL_SHA", - "TLS_ECDH_ECDSA_WITH_RC4_128_SHA", - "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", - "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", - "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", - "TLS_ECDHE_ECDSA_WITH_NULL_SHA", - "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", - "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", - "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", - "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", - "TLS_ECDH_RSA_WITH_NULL_SHA", - "TLS_ECDH_RSA_WITH_RC4_128_SHA", - "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", - "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", - "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA", - "TLS_ECDHE_RSA_WITH_NULL_SHA", - "TLS_ECDHE_RSA_WITH_RC4_128_SHA", - "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", - "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", - "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", - "TLS_ECDH_anon_WITH_NULL_SHA", - "TLS_ECDH_anon_WITH_RC4_128_SHA", - "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA", - "TLS_ECDH_anon_WITH_AES_128_CBC_SHA", - "TLS_ECDH_anon_WITH_AES_256_CBC_SHA", - "TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA", - "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA", - "TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA", - "TLS_SRP_SHA_WITH_AES_128_CBC_SHA", - "TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA", - "TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA", - "TLS_SRP_SHA_WITH_AES_256_CBC_SHA", - "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA", - "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA", - "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", - "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", - "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256", - "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384", - "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", - "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", - "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256", - "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384", - "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", - "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", - "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", - "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", - "TLS_ECDHE_PSK_WITH_RC4_128_SHA", - "TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA", - "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA", - "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA", - "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256", - "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384", - "TLS_ECDHE_PSK_WITH_NULL_SHA", - "TLS_ECDHE_PSK_WITH_NULL_SHA256", - "TLS_ECDHE_PSK_WITH_NULL_SHA384", - "TLS_RSA_WITH_ARIA_128_CBC_SHA256", - "TLS_RSA_WITH_ARIA_256_CBC_SHA384", - "TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256", - "TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384", - "TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256", - "TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384", - "TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256", - "TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384", - "TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256", - "TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384", - "TLS_DH_anon_WITH_ARIA_128_CBC_SHA256", - "TLS_DH_anon_WITH_ARIA_256_CBC_SHA384", - "TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256", - "TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384", - "TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256", - "TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384", - "TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256", - "TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384", - "TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256", - "TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384", - "TLS_RSA_WITH_ARIA_128_GCM_SHA256", - "TLS_RSA_WITH_ARIA_256_GCM_SHA384", - "TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256", - "TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384", - "TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256", - "TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384", - "TLS_DH_anon_WITH_ARIA_128_GCM_SHA256", - "TLS_DH_anon_WITH_ARIA_256_GCM_SHA384", - "TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256", - "TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384", - "TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256", - "TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384", - "TLS_PSK_WITH_ARIA_128_CBC_SHA256", - "TLS_PSK_WITH_ARIA_256_CBC_SHA384", - "TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256", - "TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384", - "TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256", - "TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384", - "TLS_PSK_WITH_ARIA_128_GCM_SHA256", - "TLS_PSK_WITH_ARIA_256_GCM_SHA384", - "TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256", - "TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384", - "TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256", - "TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384", - "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", - "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", - "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", - "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", - "TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", - "TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384", - "TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256", - "TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384", - "TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256", - "TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384", - "TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256", - "TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384", - "TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256", - "TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384", - "TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256", - "TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384", - "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256", - "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384", - "TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256", - "TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384", - "TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256", - "TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384", - "TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256", - "TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384", - "TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256", - "TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384", - "TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", - "TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", - "TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256", - "TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384", - "TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", - "TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", - "TLS_RSA_WITH_AES_128_CCM", - "TLS_RSA_WITH_AES_256_CCM", - "TLS_RSA_WITH_AES_128_CCM_8", - "TLS_RSA_WITH_AES_256_CCM_8", - "TLS_PSK_WITH_AES_128_CCM", - "TLS_PSK_WITH_AES_256_CCM", - "TLS_PSK_WITH_AES_128_CCM_8", - "TLS_PSK_WITH_AES_256_CCM_8" - }) - { - __blackCiphers.put(c,Boolean.TRUE); + __blackCiphers.put(c, Boolean.TRUE); } } @@ -344,9 +344,9 @@ public class HTTP2Cipher @Override public int compare(String c1, String c2) { - boolean b1=isBlackListCipher(c1); - boolean b2=isBlackListCipher(c2); - if (b1==b2) + boolean b1 = isBlackListCipher(c1); + boolean b2 = isBlackListCipher(c2); + if (b1 == b2) return 0; if (b1) return 1; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java index c3739f7bd7d..ffcbb193280 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -23,7 +23,6 @@ import java.nio.ByteBuffer; import java.util.ArrayDeque; import java.util.Queue; import java.util.concurrent.Executor; -import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import org.eclipse.jetty.http2.frames.DataFrame; @@ -31,10 +30,10 @@ import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.AbstractConnection; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.io.RetainableByteBuffer; import org.eclipse.jetty.io.WriteFlusher; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.Retainable; import org.eclipse.jetty.util.component.LifeCycle; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -45,10 +44,10 @@ import org.eclipse.jetty.util.thread.strategy.EatWhatYouKill; public class HTTP2Connection extends AbstractConnection implements WriteFlusher.Listener { protected static final Logger LOG = Log.getLogger(HTTP2Connection.class); - + // TODO remove this once we are sure EWYK is OK for http2 private static final boolean PEC_MODE = Boolean.getBoolean("org.eclipse.jetty.http2.PEC_MODE"); - + private final Queue tasks = new ArrayDeque<>(); private final HTTP2Producer producer = new HTTP2Producer(); private final AtomicLong bytesIn = new AtomicLong(); @@ -217,8 +216,8 @@ public class HTTP2Connection extends AbstractConnection implements WriteFlusher. private void setInputBuffer(ByteBuffer byteBuffer) { - if (networkBuffer == null) - networkBuffer = acquireNetworkBuffer(); + acquireNetworkBuffer(); + // TODO handle buffer overflow? networkBuffer.put(byteBuffer); } @@ -234,93 +233,104 @@ public class HTTP2Connection extends AbstractConnection implements WriteFlusher. if (isFillInterested() || shutdown || failed) return null; - if (networkBuffer == null) - networkBuffer = acquireNetworkBuffer(); - - boolean parse = networkBuffer.hasRemaining(); - - while (true) + boolean interested = false; + acquireNetworkBuffer(); + try { - if (parse) + boolean parse = networkBuffer.hasRemaining(); + + while (true) { - boolean released; - networkBuffer.retain(); - try + if (parse) { while (networkBuffer.hasRemaining()) { - parser.parse(networkBuffer.buffer); + parser.parse(networkBuffer.getBuffer()); if (failed) return null; } - } - finally - { - released = networkBuffer.release(); - if (failed && released) - releaseNetworkBuffer(); + + task = pollTask(); + if (LOG.isDebugEnabled()) + LOG.debug("Dequeued new task {}", task); + if (task != null) + return task; + + // If more references than 1 (ie not just us), don't refill into buffer and risk compaction. + if (networkBuffer.getReferences() > 1) + reacquireNetworkBuffer(); } - task = pollTask(); + // Here we know that this.networkBuffer is not retained by + // application code: either it has been released, or it's a new one. + int filled = fill(getEndPoint(), networkBuffer.getBuffer()); if (LOG.isDebugEnabled()) - LOG.debug("Dequeued new task {}", task); - if (task != null) + LOG.debug("Filled {} bytes in {}", filled, networkBuffer); + + if (filled > 0) { - if (released) - releaseNetworkBuffer(); - else - networkBuffer = null; - return task; + bytesIn.addAndGet(filled); + parse = true; + } + else if (filled == 0) + { + interested = true; + return null; } else { - if (!released) - networkBuffer = acquireNetworkBuffer(); + shutdown = true; + session.onShutdown(); + return null; } } - - // Here we know that this.buffer is not retained: - // either it has been released, or it's a new one. - - int filled = fill(getEndPoint(), networkBuffer.buffer); - if (LOG.isDebugEnabled()) - LOG.debug("Filled {} bytes in {}", filled, networkBuffer); - - if (filled > 0) - { - bytesIn.addAndGet(filled); - parse = true; - } - else if (filled == 0) - { - releaseNetworkBuffer(); + } + finally + { + releaseNetworkBuffer(); + if (interested) getEndPoint().fillInterested(fillableCallback); - return null; - } - else - { - releaseNetworkBuffer(); - shutdown = true; - session.onShutdown(); - return null; - } } } - private NetworkBuffer acquireNetworkBuffer() + private void acquireNetworkBuffer() { - NetworkBuffer networkBuffer = new NetworkBuffer(); + if (networkBuffer == null) + { + networkBuffer = new NetworkBuffer(); + if (LOG.isDebugEnabled()) + LOG.debug("Acquired {}", networkBuffer); + } + } + + private void reacquireNetworkBuffer() + { + NetworkBuffer currentBuffer = networkBuffer; + if (currentBuffer == null) + throw new IllegalStateException(); + + if (currentBuffer.getBuffer().hasRemaining()) + throw new IllegalStateException(); + + currentBuffer.release(); + networkBuffer = new NetworkBuffer(); if (LOG.isDebugEnabled()) - LOG.debug("Acquired {}", networkBuffer); - return networkBuffer; + LOG.debug("Reacquired {}<-{}", currentBuffer, networkBuffer); } private void releaseNetworkBuffer() { - if (LOG.isDebugEnabled()) - LOG.debug("Released {}", networkBuffer); - networkBuffer.recycle(); + NetworkBuffer currentBuffer = networkBuffer; + if (currentBuffer == null) + throw new IllegalStateException(); + + if (currentBuffer.hasRemaining() && !shutdown && !failed) + throw new IllegalStateException(); + + currentBuffer.release(); networkBuffer = null; + if (LOG.isDebugEnabled()) + LOG.debug("Released {}", currentBuffer); } @Override @@ -375,56 +385,36 @@ public class HTTP2Connection extends AbstractConnection implements WriteFlusher. } } - private class NetworkBuffer implements Callback, Retainable + private class NetworkBuffer extends RetainableByteBuffer implements Callback { - private final AtomicInteger refCount = new AtomicInteger(); - private final ByteBuffer buffer; - private NetworkBuffer() { - buffer = byteBufferPool.acquire(bufferSize, false); // TODO: make directness customizable + super(byteBufferPool, bufferSize, false); } private void put(ByteBuffer source) { - BufferUtil.append(buffer, source); - } - - private boolean hasRemaining() - { - return buffer.hasRemaining(); - } - - @Override - public void retain() - { - refCount.incrementAndGet(); - } - - private boolean release() - { - return refCount.decrementAndGet() == 0; + BufferUtil.append(getBuffer(), source); } @Override public void succeeded() { - if (release()) - { - if (LOG.isDebugEnabled()) - LOG.debug("Released retained {}", this); - recycle(); - } + completed(null); } @Override public void failed(Throwable failure) { - if (release()) + completed(failure); + } + + private void completed(Throwable failure) + { + if (release() == 0) { if (LOG.isDebugEnabled()) LOG.debug("Released retained " + this, failure); - recycle(); } } @@ -433,16 +423,5 @@ public class HTTP2Connection extends AbstractConnection implements WriteFlusher. { return InvocationType.NON_BLOCKING; } - - private void recycle() - { - byteBufferPool.release(buffer); - } - - @Override - public String toString() - { - return String.format("%s@%x[%s]", getClass().getSimpleName(), hashCode(), buffer); - } } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Flusher.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Flusher.java index 61b9c69acad..350751ead3c 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Flusher.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Flusher.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -34,7 +34,6 @@ import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.EofException; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.IteratingCallback; -import org.eclipse.jetty.util.component.ContainerLifeCycle; import org.eclipse.jetty.util.component.Dumpable; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -140,11 +139,15 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable WindowEntry windowEntry; while ((windowEntry = windows.poll()) != null) + { windowEntry.perform(); + } Entry entry; while ((entry = entries.poll()) != null) + { pendingEntries.offer(entry); + } } if (pendingEntries.isEmpty()) @@ -238,12 +241,12 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable if (LOG.isDebugEnabled()) LOG.debug("Writing {} buffers ({} bytes) - entries processed/pending {}/{}: {}/{}", - byteBuffers.size(), - lease.getTotalLength(), - processedEntries.size(), - pendingEntries.size(), - processedEntries, - pendingEntries); + byteBuffers.size(), + lease.getTotalLength(), + processedEntries.size(), + pendingEntries.size(), + processedEntries, + pendingEntries); session.getEndPoint().write(this, byteBuffers.toArray(EMPTY_BYTE_BUFFERS)); return Action.SCHEDULED; @@ -253,7 +256,9 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable { // A single EndPoint write may be flushed multiple times (for example with SSL). for (Entry entry : processedEntries) + { bytes = entry.onFlushed(bytes); + } } @Override @@ -261,11 +266,11 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable { if (LOG.isDebugEnabled()) LOG.debug("Written {} buffers - entries processed/pending {}/{}: {}/{}", - lease.getByteBuffers().size(), - processedEntries.size(), - pendingEntries.size(), - processedEntries, - pendingEntries); + lease.getByteBuffers().size(), + processedEntries.size(), + pendingEntries.size(), + processedEntries, + pendingEntries); finish(); super.succeeded(); } @@ -311,10 +316,10 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable terminated = x; if (LOG.isDebugEnabled()) LOG.debug(String.format("%s, entries processed/pending/queued=%d/%d/%d", - closed != null ? "Closing" : "Failing", - processedEntries.size(), - pendingEntries.size(), - entries.size()), x); + closed != null ? "Closing" : "Failing", + processedEntries.size(), + pendingEntries.size(), + entries.size()), x); allEntries = new HashSet<>(entries); entries.clear(); } @@ -353,7 +358,7 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable @Override public String dump() { - return ContainerLifeCycle.dump(this); + return Dumpable.dump(this); } @Override @@ -366,14 +371,14 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable public String toString() { return String.format("%s[window_queue=%d,frame_queue=%d,processed/pending=%d/%d]", - super.toString(), - getWindowQueueSize(), - getFrameQueueSize(), - processedEntries.size(), - pendingEntries.size()); + super.toString(), + getWindowQueueSize(), + getFrameQueueSize(), + processedEntries.size(), + pendingEntries.size()); } - public static abstract class Entry extends Callback.Nested + public abstract static class Entry extends Callback.Nested { protected final Frame frame; protected final IStream stream; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index 04279864c5d..a8fb651121a 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -57,6 +57,7 @@ import org.eclipse.jetty.util.AtomicBiInteger; import org.eclipse.jetty.util.Atomics; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.CountingCallback; +import org.eclipse.jetty.util.MathUtils; import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.Retainable; import org.eclipse.jetty.util.annotation.ManagedAttribute; @@ -295,13 +296,12 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio } else { - if (isRemoteStreamClosed(streamId)) - notifyReset(this, frame); - else - onConnectionFailure(ErrorCode.PROTOCOL_ERROR.code, "unexpected_rst_stream_frame"); + onResetForUnknownStream(frame); } } + protected abstract void onResetForUnknownStream(ResetFrame frame); + @Override public void onSettings(SettingsFrame frame) { @@ -333,15 +333,16 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio } case SettingsFrame.ENABLE_PUSH: { + boolean enabled = value == 1; if (LOG.isDebugEnabled()) - LOG.debug("{} push for {}", pushEnabled ? "Enabling" : "Disabling", this); - pushEnabled = value == 1; + LOG.debug("{} push for {}", enabled ? "Enabling" : "Disabling", this); + pushEnabled = enabled; break; } case SettingsFrame.MAX_CONCURRENT_STREAMS: { if (LOG.isDebugEnabled()) - LOG.debug("Updating max local concurrent streams to {} for {}", maxLocalStreams, this); + LOG.debug("Updating max local concurrent streams to {} for {}", value, this); maxLocalStreams = value; break; } @@ -460,47 +461,33 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio int windowDelta = frame.getWindowDelta(); if (streamId > 0) { - if (windowDelta == 0) + IStream stream = getStream(streamId); + if (stream != null) { - reset(new ResetFrame(streamId, ErrorCode.PROTOCOL_ERROR.code), Callback.NOOP); - } - else - { - IStream stream = getStream(streamId); - if (stream != null) + int streamSendWindow = stream.updateSendWindow(0); + if (MathUtils.sumOverflows(streamSendWindow, windowDelta)) { - int streamSendWindow = stream.updateSendWindow(0); - if (sumOverflows(streamSendWindow, windowDelta)) - { - reset(new ResetFrame(streamId, ErrorCode.FLOW_CONTROL_ERROR.code), Callback.NOOP); - } - else - { - stream.process(frame, Callback.NOOP); - onWindowUpdate(stream, frame); - } + reset(new ResetFrame(streamId, ErrorCode.FLOW_CONTROL_ERROR.code), Callback.NOOP); } else { - if (!isRemoteStreamClosed(streamId)) - onConnectionFailure(ErrorCode.PROTOCOL_ERROR.code, "unexpected_window_update_frame"); + stream.process(frame, Callback.NOOP); + onWindowUpdate(stream, frame); } } + else + { + if (!isRemoteStreamClosed(streamId)) + onConnectionFailure(ErrorCode.PROTOCOL_ERROR.code, "unexpected_window_update_frame"); + } } else { - if (windowDelta == 0) - { - onConnectionFailure(ErrorCode.PROTOCOL_ERROR.code, "invalid_window_update_frame"); - } + int sessionSendWindow = updateSendWindow(0); + if (MathUtils.sumOverflows(sessionSendWindow, windowDelta)) + onConnectionFailure(ErrorCode.FLOW_CONTROL_ERROR.code, "invalid_flow_control_window"); else - { - int sessionSendWindow = updateSendWindow(0); - if (sumOverflows(sessionSendWindow, windowDelta)) - onConnectionFailure(ErrorCode.FLOW_CONTROL_ERROR.code, "invalid_flow_control_window"); - else - onWindowUpdate(null, frame); - } + onWindowUpdate(null, frame); } } @@ -515,19 +502,6 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio callback.succeeded(); } - private boolean sumOverflows(int a, int b) - { - try - { - Math.addExact(a, b); - return false; - } - catch (ArithmeticException x) - { - return true; - } - } - @Override public void onConnectionFailure(int error, String reason) { @@ -555,13 +529,13 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio streamId = localStreamIds.getAndAdd(2); PriorityFrame priority = frame.getPriority(); priority = priority == null ? null : new PriorityFrame(streamId, priority.getParentStreamId(), - priority.getWeight(), priority.isExclusive()); + priority.getWeight(), priority.isExclusive()); frame = new HeadersFrame(streamId, frame.getMetaData(), priority, frame.isEndStream()); } IStream stream = createLocalStream(streamId); stream.setListener(listener); - ControlEntry entry = new ControlEntry(frame, stream, new PromiseCallback<>(promise, stream)); + ControlEntry entry = new ControlEntry(frame, stream, new StreamPromiseCallback(promise, stream)); queued = flusher.append(entry); } // Iterate outside the synchronized block. @@ -583,7 +557,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio { streamId = localStreamIds.getAndAdd(2); frame = new PriorityFrame(streamId, frame.getParentStreamId(), - frame.getWeight(), frame.isExclusive()); + frame.getWeight(), frame.isExclusive()); } control(stream, callback, frame); return streamId; @@ -605,7 +579,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio IStream pushStream = createLocalStream(streamId); pushStream.setListener(listener); - ControlEntry entry = new ControlEntry(frame, pushStream, new PromiseCallback<>(promise, pushStream)); + ControlEntry entry = new ControlEntry(frame, pushStream, new StreamPromiseCallback(promise, pushStream)); queued = flusher.append(entry); } // Iterate outside the synchronized block. @@ -654,8 +628,8 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio * performing their actions. * * - * @param error the error code - * @param reason the reason + * @param error the error code + * @param reason the reason * @param callback the callback to invoke when the operation is complete * @see #onGoAway(GoAwayFrame) * @see #onShutdown() @@ -731,7 +705,9 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio callback = new CountingCallback(callback, 1 + length); frame(new ControlEntry(frame, stream, callback), false); for (int i = 1; i <= length; ++i) + { frame(new ControlEntry(frames[i - 1], stream, callback), i == length); + } } } @@ -763,7 +739,8 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio int localCount = localStreamCount.get(); int maxCount = getMaxLocalStreams(); if (maxCount >= 0 && localCount >= maxCount) - throw new IllegalStateException("Max local stream count " + maxCount + " exceeded"); + // TODO: remove the dump() in the exception message. + throw new IllegalStateException("Max local stream count " + maxCount + " exceeded" + System.lineSeparator() + dump()); if (localStreamCount.compareAndSet(localCount, localCount + 1)) break; } @@ -779,6 +756,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio } else { + localStreamCount.decrementAndGet(); throw new IllegalStateException("Duplicate stream " + streamId); } } @@ -815,6 +793,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio } else { + remoteStreamCount.addAndGetHi(-1); onConnectionFailure(ErrorCode.PROTOCOL_ERROR.code, "duplicate_stream"); return null; } @@ -1059,7 +1038,9 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio { flusher.terminate(cause); for (IStream stream : streams.values()) + { stream.close(); + } streams.clear(); disconnect(); return; @@ -1204,23 +1185,22 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio @Override public void dump(Appendable out, String indent) throws IOException { - super.dump(out, indent); - dump(out, indent, Collections.singleton(new DumpableCollection("streams", streams.values()))); + dumpObjects(out, indent, new DumpableCollection("streams", streams.values())); } @Override public String toString() { return String.format("%s@%x{l:%s <-> r:%s,sendWindow=%s,recvWindow=%s,streams=%d,%s,%s}", - getClass().getSimpleName(), - hashCode(), - getEndPoint().getLocalAddress(), - getEndPoint().getRemoteAddress(), - sendWindow, - recvWindow, - streams.size(), - closed, - closeFrame); + getClass().getSimpleName(), + hashCode(), + getEndPoint().getLocalAddress(), + getEndPoint().getRemoteAddress(), + sendWindow, + recvWindow, + streams.size(), + closed, + closeFrame); } private class ControlEntry extends HTTP2Flusher.Entry @@ -1461,21 +1441,21 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio } } - private static class PromiseCallback implements Callback + private static class StreamPromiseCallback implements Callback { - private final Promise promise; - private final C value; + private final Promise promise; + private final IStream stream; - private PromiseCallback(Promise promise, C value) + private StreamPromiseCallback(Promise promise, IStream stream) { this.promise = promise; - this.value = value; + this.stream = stream; } @Override public void succeeded() { - promise.succeeded(value); + promise.succeeded(stream); } @Override diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java index b9609ad4903..4da6aaa8d1f 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -42,7 +42,6 @@ import org.eclipse.jetty.http2.frames.WindowUpdateFrame; import org.eclipse.jetty.io.IdleTimeout; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Promise; -import org.eclipse.jetty.util.component.ContainerLifeCycle; import org.eclipse.jetty.util.component.Dumpable; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -139,6 +138,7 @@ public class HTTP2Stream extends IdleTimeout implements IStream, Callback, Dumpa { if (writing.compareAndSet(null, callback)) return true; + close(); callback.failed(new WritePendingException()); return false; } @@ -176,7 +176,8 @@ public class HTTP2Stream extends IdleTimeout implements IStream, Callback, Dumpa @Override public boolean isRemotelyClosed() { - return closeState.get() == CloseState.REMOTELY_CLOSED; + CloseState state = closeState.get(); + return state == CloseState.REMOTELY_CLOSED || state == CloseState.CLOSING; } public boolean isLocallyClosed() @@ -275,8 +276,6 @@ public class HTTP2Stream extends IdleTimeout implements IStream, Callback, Dumpa private void onHeaders(HeadersFrame frame, Callback callback) { - if (updateClose(frame.isEndStream(), CloseState.Event.RECEIVED)) - session.removeStream(this); MetaData metaData = frame.getMetaData(); if (metaData.isRequest() || metaData.isResponse()) { @@ -286,6 +285,10 @@ public class HTTP2Stream extends IdleTimeout implements IStream, Callback, Dumpa length = fields.getLongField(HttpHeader.CONTENT_LENGTH.asString()); dataLength = length >= 0 ? length : Long.MIN_VALUE; } + + if (updateClose(frame.isEndStream(), CloseState.Event.RECEIVED)) + session.removeStream(this); + callback.succeeded(); } @@ -507,6 +510,13 @@ public class HTTP2Stream extends IdleTimeout implements IStream, Callback, Dumpa } } + @Override + public void onClose() + { + super.onClose(); + notifyClosed(this); + } + private void updateStreamCount(int deltaStream, int deltaClosing) { ((HTTP2Session)session).updateStreamCount(isLocal(), deltaStream, deltaClosing); @@ -612,10 +622,25 @@ public class HTTP2Stream extends IdleTimeout implements IStream, Callback, Dumpa } } + private void notifyClosed(Stream stream) + { + Listener listener = this.listener; + if (listener == null) + return; + try + { + listener.onClosed(stream); + } + catch (Throwable x) + { + LOG.info("Failure while notifying listener " + listener, x); + } + } + @Override public String dump() { - return ContainerLifeCycle.dump(this); + return Dumpable.dump(this); } @Override @@ -627,15 +652,16 @@ public class HTTP2Stream extends IdleTimeout implements IStream, Callback, Dumpa @Override public String toString() { - return String.format("%s@%x#%d{sendWindow=%s,recvWindow=%s,reset=%b,%s,age=%d,attachment=%s}", - getClass().getSimpleName(), - hashCode(), - getId(), - sendWindow, - recvWindow, - isReset(), - closeState, - TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - timeStamp), - attachment); + return String.format("%s@%x#%d{sendWindow=%s,recvWindow=%s,reset=%b/%b,%s,age=%d,attachment=%s}", + getClass().getSimpleName(), + hashCode(), + getId(), + sendWindow, + recvWindow, + localReset, + remoteReset, + closeState, + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - timeStamp), + attachment); } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java index 3d74301e125..3df57d39b29 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -30,52 +30,52 @@ import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Promise; /** - *

        The SPI interface for implementing a HTTP/2 session.

        + *

        The SPI interface for implementing an HTTP/2 session.

        *

        This class extends {@link Session} by adding the methods required to * implement the HTTP/2 session functionalities.

        */ public interface ISession extends Session { @Override - public IStream getStream(int streamId); + IStream getStream(int streamId); /** *

        Removes the given {@code stream}.

        * * @param stream the stream to remove */ - public void removeStream(IStream stream); + void removeStream(IStream stream); /** *

        Enqueues the given frames to be written to the connection.

        * - * @param stream the stream the frames belong to + * @param stream the stream the frames belong to * @param callback the callback that gets notified when the frames have been sent - * @param frame the first frame to enqueue - * @param frames additional frames to enqueue + * @param frame the first frame to enqueue + * @param frames additional frames to enqueue */ - public void frames(IStream stream, Callback callback, Frame frame, Frame... frames); + void frames(IStream stream, Callback callback, Frame frame, Frame... frames); /** *

        Enqueues the given PUSH_PROMISE frame to be written to the connection.

        *

        Differently from {@link #frames(IStream, Callback, Frame, Frame...)}, this method * generates atomically the stream id for the pushed stream.

        * - * @param stream the stream associated to the pushed stream - * @param promise the promise that gets notified of the pushed stream creation - * @param frame the PUSH_PROMISE frame to enqueue + * @param stream the stream associated to the pushed stream + * @param promise the promise that gets notified of the pushed stream creation + * @param frame the PUSH_PROMISE frame to enqueue * @param listener the listener that gets notified of pushed stream events */ - public void push(IStream stream, Promise promise, PushPromiseFrame frame, Stream.Listener listener); + void push(IStream stream, Promise promise, PushPromiseFrame frame, Stream.Listener listener); /** *

        Enqueues the given DATA frame to be written to the connection.

        * - * @param stream the stream the data frame belongs to + * @param stream the stream the data frame belongs to * @param callback the callback that gets notified when the frame has been sent - * @param frame the DATA frame to send + * @param frame the DATA frame to send */ - public void data(IStream stream, Callback callback, DataFrame frame); + void data(IStream stream, Callback callback, DataFrame frame); /** *

        Updates the session send window by the given {@code delta}.

        @@ -83,7 +83,7 @@ public interface ISession extends Session * @param delta the delta value (positive or negative) to add to the session send window * @return the previous value of the session send window */ - public int updateSendWindow(int delta); + int updateSendWindow(int delta); /** *

        Updates the session receive window by the given {@code delta}.

        @@ -91,20 +91,20 @@ public interface ISession extends Session * @param delta the delta value (positive or negative) to add to the session receive window * @return the previous value of the session receive window */ - public int updateRecvWindow(int delta); + int updateRecvWindow(int delta); /** *

        Callback method invoked when a WINDOW_UPDATE frame has been received.

        * * @param stream the stream the window update belongs to, or null if the window update belongs to the session - * @param frame the WINDOW_UPDATE frame received + * @param frame the WINDOW_UPDATE frame received */ - public void onWindowUpdate(IStream stream, WindowUpdateFrame frame); + void onWindowUpdate(IStream stream, WindowUpdateFrame frame); /** * @return whether the push functionality is enabled */ - public boolean isPushEnabled(); + boolean isPushEnabled(); /** *

        Callback invoked when the connection reads -1.

        @@ -112,16 +112,16 @@ public interface ISession extends Session * @see #onIdleTimeout() * @see #close(int, String, Callback) */ - public void onShutdown(); + void onShutdown(); /** *

        Callback invoked when the idle timeout expires.

        * + * @return {@code true} if the session has expired * @see #onShutdown() * @see #close(int, String, Callback) - * @return {@code true} if the session has expired */ - public boolean onIdleTimeout(); + boolean onIdleTimeout(); /** *

        Callback method invoked during an HTTP/1.1 to HTTP/2 upgrade requests @@ -129,7 +129,7 @@ public interface ISession extends Session * * @param frame the synthetic frame to process */ - public void onFrame(Frame frame); + void onFrame(Frame frame); /** *

        Callback method invoked when bytes are flushed to the network.

        @@ -137,12 +137,12 @@ public interface ISession extends Session * @param bytes the number of bytes flushed to the network * @throws IOException if the flush should fail */ - public void onFlushed(long bytes) throws IOException; + void onFlushed(long bytes) throws IOException; /** * @return the number of bytes written by this session */ - public long getBytesWritten(); + long getBytesWritten(); /** *

        Callback method invoked when a DATA frame is received.

        @@ -150,5 +150,5 @@ public interface ISession extends Session * @param frame the DATA frame received * @param callback the callback to notify when the frame has been processed */ - public void onData(DataFrame frame, Callback callback); + void onData(DataFrame frame, Callback callback); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java index 95dc4f4fb87..144ed9190c6 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -25,7 +25,7 @@ import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.util.Callback; /** - *

        The SPI interface for implementing a HTTP/2 stream.

        + *

        The SPI interface for implementing an HTTP/2 stream.

        *

        This class extends {@link Stream} by adding the methods required to * implement the HTTP/2 stream functionalities.

        */ @@ -35,34 +35,34 @@ public interface IStream extends Stream, Closeable * @return the object attached to this stream * @see #setAttachment(Object) */ - public Object getAttachment(); + Object getAttachment(); /** * Attaches the given object to this stream for later retrieval. * * @param attachment the object to attach to this stream */ - public void setAttachment(Object attachment); + void setAttachment(Object attachment); /** * @return whether this stream is local or remote */ - public boolean isLocal(); + boolean isLocal(); @Override - public ISession getSession(); + ISession getSession(); /** * @return the {@link org.eclipse.jetty.http2.api.Stream.Listener} associated with this stream * @see #setListener(Stream.Listener) */ - public Listener getListener(); + Listener getListener(); /** * @param listener the {@link org.eclipse.jetty.http2.api.Stream.Listener} associated with this stream * @see #getListener() */ - public void setListener(Listener listener); + void setListener(Listener listener); /** *

        Processes the given {@code frame}, belonging to this stream.

        @@ -70,22 +70,22 @@ public interface IStream extends Stream, Closeable * @param frame the frame to process * @param callback the callback to complete when frame has been processed */ - public void process(Frame frame, Callback callback); + void process(Frame frame, Callback callback); /** *

        Updates the close state of this stream.

        * * @param update whether to update the close state - * @param event the event that caused the close state update + * @param event the event that caused the close state update * @return whether the stream has been fully closed by this invocation */ - public boolean updateClose(boolean update, CloseState.Event event); + boolean updateClose(boolean update, CloseState.Event event); /** *

        Forcibly closes this stream.

        */ @Override - public void close(); + void close(); /** *

        Updates the stream send window by the given {@code delta}.

        @@ -93,7 +93,7 @@ public interface IStream extends Stream, Closeable * @param delta the delta value (positive or negative) to add to the stream send window * @return the previous value of the stream send window */ - public int updateSendWindow(int delta); + int updateSendWindow(int delta); /** *

        Updates the stream receive window by the given {@code delta}.

        @@ -101,13 +101,13 @@ public interface IStream extends Stream, Closeable * @param delta the delta value (positive or negative) to add to the stream receive window * @return the previous value of the stream receive window */ - public int updateRecvWindow(int delta); + int updateRecvWindow(int delta); /** *

        Marks this stream as not idle so that the * {@link #getIdleTimeout() idle timeout} is postponed.

        */ - public void notIdle(); + void notIdle(); /** * @return whether the stream is closed remotely. diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/SimpleFlowControlStrategy.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/SimpleFlowControlStrategy.java index 9ad7a15a7b8..e8ba053ef63 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/SimpleFlowControlStrategy.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/SimpleFlowControlStrategy.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java index e1c99ac2ae5..2ba0b3d78ed 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -32,7 +32,7 @@ import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Promise; /** - *

        A {@link Session} represents the client-side endpoint of a HTTP/2 connection to a single origin server.

        + *

        A {@link Session} represents the client-side endpoint of an HTTP/2 connection to a single origin server.

        *

        Once a {@link Session} has been obtained, it can be used to open HTTP/2 streams:

        *
          * Session session = ...;
        @@ -57,11 +57,11 @@ public interface Session
             /**
              * 

        Sends the given HEADERS {@code frame} to create a new {@link Stream}.

        * - * @param frame the HEADERS frame containing the HTTP headers - * @param promise the promise that gets notified of the stream creation + * @param frame the HEADERS frame containing the HTTP headers + * @param promise the promise that gets notified of the stream creation * @param listener the listener that gets notified of stream events */ - public void newStream(HeadersFrame frame, Promise promise, Stream.Listener listener); + void newStream(HeadersFrame frame, Promise promise, Stream.Listener listener); /** *

        Sends the given PRIORITY {@code frame}.

        @@ -69,30 +69,30 @@ public interface Session * (for example {@code 0}), then a new {@code streamId} will be allocated, to * support unused anchor streams that act as parent for other streams.

        * - * @param frame the PRIORITY frame to send + * @param frame the PRIORITY frame to send * @param callback the callback that gets notified when the frame has been sent - * @return the new stream id generated by the PRIORITY frame, or the stream id - * that it is already referencing + * @return the new stream id generated by the PRIORITY frame, or the stream id + * that it is already referencing */ - public int priority(PriorityFrame frame, Callback callback); + int priority(PriorityFrame frame, Callback callback); /** *

        Sends the given SETTINGS {@code frame} to configure the session.

        * - * @param frame the SETTINGS frame to send + * @param frame the SETTINGS frame to send * @param callback the callback that gets notified when the frame has been sent */ - public void settings(SettingsFrame frame, Callback callback); + void settings(SettingsFrame frame, Callback callback); /** *

        Sends the given PING {@code frame}.

        *

        PING frames may be used to test the connection integrity and to measure * round-trip time.

        * - * @param frame the PING frame to send + * @param frame the PING frame to send * @param callback the callback that gets notified when the frame has been sent */ - public void ping(PingFrame frame, Callback callback); + void ping(PingFrame frame, Callback callback); /** *

        Closes the session by sending a GOAWAY frame with the given error code @@ -100,22 +100,22 @@ public interface Session *

        The GOAWAY frame is sent only once; subsequent or concurrent attempts to * close the session will have no effect.

        * - * @param error the error code - * @param payload an optional payload (may be null) + * @param error the error code + * @param payload an optional payload (may be null) * @param callback the callback that gets notified when the frame has been sent * @return true if the frame is being sent, false if the session was already closed */ - public boolean close(int error, String payload, Callback callback); + boolean close(int error, String payload, Callback callback); /** * @return whether the session is not open */ - public boolean isClosed(); + boolean isClosed(); /** * @return a snapshot of all the streams currently belonging to this session */ - public Collection getStreams(); + Collection getStreams(); /** *

        Retrieves the stream with the given {@code streamId}.

        @@ -123,37 +123,37 @@ public interface Session * @param streamId the stream id of the stream looked for * @return the stream with the given id, or null if no such stream exist */ - public Stream getStream(int streamId); + Stream getStream(int streamId); /** *

        A {@link Listener} is the passive counterpart of a {@link Session} and - * receives events happening on a HTTP/2 connection.

        + * receives events happening on an HTTP/2 connection.

        * * @see Session */ - public interface Listener + interface Listener { /** *

        Callback method invoked:

        *
          - *
        • for clients, just before the preface is sent, to gather the - * SETTINGS configuration options the client wants to send to the server;
        • - *
        • for servers, just after having received the preface, to gather - * the SETTINGS configuration options the server wants to send to the - * client.
        • + *
        • for clients, just before the preface is sent, to gather the + * SETTINGS configuration options the client wants to send to the server;
        • + *
        • for servers, just after having received the preface, to gather + * the SETTINGS configuration options the server wants to send to the + * client.
        • *
        * * @param session the session * @return a (possibly empty or null) map containing SETTINGS configuration * options to send. */ - public Map onPreface(Session session); + Map onPreface(Session session); /** *

        Callback method invoked when a new stream is being created upon - * receiving a HEADERS frame representing a HTTP request.

        + * receiving a HEADERS frame representing an HTTP request.

        *

        Applications should implement this method to process HTTP requests, - * typically providing a HTTP response via + * typically providing an HTTP response via * {@link Stream#headers(HeadersFrame, Callback)}.

        *

        Applications can detect whether request DATA frames will be arriving * by testing {@link HeadersFrame#isEndStream()}. If the application is @@ -162,44 +162,44 @@ public interface Session * {@link Stream.Listener#onData(Stream, DataFrame, Callback)}.

        * * @param stream the newly created stream - * @param frame the HEADERS frame received + * @param frame the HEADERS frame received * @return a {@link Stream.Listener} that will be notified of stream events */ - public Stream.Listener onNewStream(Stream stream, HeadersFrame frame); + Stream.Listener onNewStream(Stream stream, HeadersFrame frame); /** *

        Callback method invoked when a SETTINGS frame has been received.

        * * @param session the session - * @param frame the SETTINGS frame received + * @param frame the SETTINGS frame received */ - public void onSettings(Session session, SettingsFrame frame); + void onSettings(Session session, SettingsFrame frame); /** *

        Callback method invoked when a PING frame has been received.

        * * @param session the session - * @param frame the PING frame received + * @param frame the PING frame received */ - public void onPing(Session session, PingFrame frame); + void onPing(Session session, PingFrame frame); /** *

        Callback method invoked when a RST_STREAM frame has been received for an unknown stream.

        * * @param session the session - * @param frame the RST_STREAM frame received + * @param frame the RST_STREAM frame received * @see Stream.Listener#onReset(Stream, ResetFrame) */ - public void onReset(Session session, ResetFrame frame); + void onReset(Session session, ResetFrame frame); /** *

        Callback method invoked when a GOAWAY frame has been received.

        * - * @param session the session - * @param frame the GOAWAY frame received + * @param session the session + * @param frame the GOAWAY frame received * @param callback the callback to notify of the GOAWAY processing */ - public default void onClose(Session session, GoAwayFrame frame, Callback callback) + default void onClose(Session session, GoAwayFrame frame, Callback callback) { try { @@ -212,23 +212,24 @@ public interface Session } } - public void onClose(Session session, GoAwayFrame frame); + void onClose(Session session, GoAwayFrame frame); /** *

        Callback method invoked when the idle timeout expired.

        + * * @param session the session * @return whether the session should be closed */ - public boolean onIdleTimeout(Session session); + boolean onIdleTimeout(Session session); /** *

        Callback method invoked when a failure has been detected for this session.

        * - * @param session the session - * @param failure the failure + * @param session the session + * @param failure the failure * @param callback the callback to notify of failure processing */ - public default void onFailure(Session session, Throwable failure, Callback callback) + default void onFailure(Session session, Throwable failure, Callback callback) { try { @@ -241,12 +242,12 @@ public interface Session } } - public void onFailure(Session session, Throwable failure); + void onFailure(Session session, Throwable failure); /** *

        Empty implementation of {@link Stream.Listener}.

        */ - public static class Adapter implements Session.Listener + class Adapter implements Session.Listener { @Override public Map onPreface(Session session) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java index f76afeaf445..bb413d8d953 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -29,8 +29,8 @@ import org.eclipse.jetty.util.Promise; *

        A {@link Stream} represents a bidirectional exchange of data on top of a {@link Session}.

        *

        Differently from socket streams, where the input and output streams are permanently associated * with the socket (and hence with the connection that the socket represents), there can be multiple - * HTTP/2 streams present concurrent for a HTTP/2 session.

        - *

        A {@link Stream} maps to a HTTP request/response cycle, and after the request/response cycle is + * HTTP/2 streams present concurrent for an HTTP/2 session.

        + *

        A {@link Stream} maps to an HTTP request/response cycle, and after the request/response cycle is * completed, the stream is closed and removed from the session.

        *

        Like {@link Session}, {@link Stream} is the active part and by calling its API applications * can generate events on the stream; conversely, {@link Stream.Listener} is the passive part, and @@ -43,45 +43,45 @@ public interface Stream /** * @return the stream unique id */ - public int getId(); + int getId(); /** * @return the session this stream is associated to */ - public Session getSession(); + Session getSession(); /** - *

        Sends the given HEADERS {@code frame} representing a HTTP response.

        + *

        Sends the given HEADERS {@code frame} representing an HTTP response.

        * - * @param frame the HEADERS frame to send + * @param frame the HEADERS frame to send * @param callback the callback that gets notified when the frame has been sent */ - public void headers(HeadersFrame frame, Callback callback); + void headers(HeadersFrame frame, Callback callback); /** *

        Sends the given PUSH_PROMISE {@code frame}.

        * - * @param frame the PUSH_PROMISE frame to send + * @param frame the PUSH_PROMISE frame to send * @param promise the promise that gets notified of the pushed stream creation * @param listener the listener that gets notified of stream events */ - public void push(PushPromiseFrame frame, Promise promise, Listener listener); + void push(PushPromiseFrame frame, Promise promise, Listener listener); /** *

        Sends the given DATA {@code frame}.

        * - * @param frame the DATA frame to send + * @param frame the DATA frame to send * @param callback the callback that gets notified when the frame has been sent */ - public void data(DataFrame frame, Callback callback); + void data(DataFrame frame, Callback callback); /** *

        Sends the given RST_STREAM {@code frame}.

        * - * @param frame the RST_FRAME to send + * @param frame the RST_FRAME to send * @param callback the callback that gets notified when the frame has been sent */ - public void reset(ResetFrame frame, Callback callback); + void reset(ResetFrame frame, Callback callback); /** * @param key the attribute key @@ -89,81 +89,88 @@ public interface Stream * or null if no object can be found for the given key. * @see #setAttribute(String, Object) */ - public Object getAttribute(String key); + Object getAttribute(String key); /** - * @param key the attribute key + * @param key the attribute key * @param value an arbitrary object to associate with the given key to this stream * @see #getAttribute(String) * @see #removeAttribute(String) */ - public void setAttribute(String key, Object value); + void setAttribute(String key, Object value); /** * @param key the attribute key * @return the arbitrary object associated with the given key to this stream * @see #setAttribute(String, Object) */ - public Object removeAttribute(String key); + Object removeAttribute(String key); /** * @return whether this stream has been reset */ - public boolean isReset(); + boolean isReset(); /** * @return whether this stream is closed, both locally and remotely. */ - public boolean isClosed(); + boolean isClosed(); /** * @return the stream idle timeout * @see #setIdleTimeout(long) */ - public long getIdleTimeout(); + long getIdleTimeout(); /** * @param idleTimeout the stream idle timeout * @see #getIdleTimeout() * @see Stream.Listener#onIdleTimeout(Stream, Throwable) */ - public void setIdleTimeout(long idleTimeout); + void setIdleTimeout(long idleTimeout); /** *

        A {@link Stream.Listener} is the passive counterpart of a {@link Stream} and receives - * events happening on a HTTP/2 stream.

        + * events happening on an HTTP/2 stream.

        * * @see Stream */ - public interface Listener + interface Listener { /** *

        Callback method invoked when a HEADERS frame representing the HTTP response has been received.

        * * @param stream the stream - * @param frame the HEADERS frame received + * @param frame the HEADERS frame received */ - public void onHeaders(Stream stream, HeadersFrame frame); + void onHeaders(Stream stream, HeadersFrame frame); /** *

        Callback method invoked when a PUSH_PROMISE frame has been received.

        * * @param stream the stream - * @param frame the PUSH_PROMISE frame received + * @param frame the PUSH_PROMISE frame received * @return a Stream.Listener that will be notified of pushed stream events */ - public Listener onPush(Stream stream, PushPromiseFrame frame); + Listener onPush(Stream stream, PushPromiseFrame frame); /** *

        Callback method invoked when a DATA frame has been received.

        * - * @param stream the stream - * @param frame the DATA frame received + * @param stream the stream + * @param frame the DATA frame received * @param callback the callback to complete when the bytes of the DATA frame have been consumed */ - public void onData(Stream stream, DataFrame frame, Callback callback); + void onData(Stream stream, DataFrame frame, Callback callback); - public default void onReset(Stream stream, ResetFrame frame, Callback callback) + /** + *

        Callback method invoked when a RST_STREAM frame has been received for this stream.

        + * + * @param stream the stream + * @param frame the RST_FRAME received + * @param callback the callback to complete when the reset has been handled + */ + default void onReset(Stream stream, ResetFrame frame, Callback callback) { try { @@ -180,10 +187,10 @@ public interface Stream *

        Callback method invoked when a RST_STREAM frame has been received for this stream.

        * * @param stream the stream - * @param frame the RST_FRAME received + * @param frame the RST_FRAME received * @see Session.Listener#onReset(Session, ResetFrame) */ - public default void onReset(Stream stream, ResetFrame frame) + default void onReset(Stream stream, ResetFrame frame) { } @@ -191,12 +198,12 @@ public interface Stream *

        Callback method invoked when the stream exceeds its idle timeout.

        * * @param stream the stream - * @param x the timeout failure + * @param x the timeout failure * @see #getIdleTimeout() * @deprecated use {@link #onIdleTimeout(Stream, Throwable)} instead */ @Deprecated - public default void onTimeout(Stream stream, Throwable x) + default void onTimeout(Stream stream, Throwable x) { } @@ -204,25 +211,42 @@ public interface Stream *

        Callback method invoked when the stream exceeds its idle timeout.

        * * @param stream the stream - * @param x the timeout failure - * @see #getIdleTimeout() + * @param x the timeout failure * @return true to reset the stream, false to ignore the idle timeout + * @see #getIdleTimeout() */ - public default boolean onIdleTimeout(Stream stream, Throwable x) + default boolean onIdleTimeout(Stream stream, Throwable x) { onTimeout(stream, x); return true; } - public default void onFailure(Stream stream, int error, String reason, Callback callback) + /** + *

        Callback method invoked when the stream failed.

        + * + * @param stream the stream + * @param error the error code + * @param reason the error reason, or null + * @param callback the callback to complete when the failure has been handled + */ + default void onFailure(Stream stream, int error, String reason, Callback callback) { callback.succeeded(); } + /** + *

        Callback method invoked after the stream has been closed.

        + * + * @param stream the stream + */ + default void onClosed(Stream stream) + { + } + /** *

        Empty implementation of {@link Listener}

        */ - public static class Adapter implements Listener + class Adapter implements Listener { @Override public void onHeaders(Stream stream, HeadersFrame frame) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/server/ServerSessionListener.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/server/ServerSessionListener.java index 07ca8f09e89..4f501c41aab 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/server/ServerSessionListener.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/server/ServerSessionListener.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -27,14 +27,15 @@ public interface ServerSessionListener extends Session.Listener { /** *

        Callback method invoked when a connection has been accepted by the server.

        + * * @param session the session */ - public void onAccept(Session session); + void onAccept(Session session); /** *

        Empty implementation of {@link ServerSessionListener}

        */ - public static class Adapter extends Session.Listener.Adapter implements ServerSessionListener + class Adapter extends Session.Listener.Adapter implements ServerSessionListener { @Override public void onAccept(Session session) diff --git a/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/ScopedInstance.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/ContinuationFrame.java similarity index 56% rename from jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/ScopedInstance.java rename to jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/ContinuationFrame.java index 619c8e74b1f..39d69310ce8 100644 --- a/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/ScopedInstance.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/ContinuationFrame.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,30 +16,33 @@ // ======================================================================== // -package org.eclipse.jetty.cdi.core; +package org.eclipse.jetty.http2.frames; -import javax.enterprise.context.spi.CreationalContext; -import javax.enterprise.inject.spi.Bean; - -public class ScopedInstance +public class ContinuationFrame extends Frame { - public Bean bean; - public CreationalContext creationalContext; - public T instance; + private final int streamId; + private final boolean endHeaders; - public void destroy() + public ContinuationFrame(int streamId, boolean endHeaders) { - bean.destroy(instance,creationalContext); + super(FrameType.CONTINUATION); + this.streamId = streamId; + this.endHeaders = endHeaders; } - + + public int getStreamId() + { + return streamId; + } + + public boolean isEndHeaders() + { + return endHeaders; + } + @Override public String toString() { - StringBuilder s = new StringBuilder(); - s.append("ScopedInstance["); - s.append(bean); - s.append(',').append(creationalContext); - s.append(']'); - return s.toString(); + return String.format("%s#%d{end=%b}", super.toString(), getStreamId(), isEndHeaders()); } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java index a2e929efaf8..5f0c95b62b5 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DisconnectFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DisconnectFrame.java index 9e98ba247a6..b2a590f9d5b 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DisconnectFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DisconnectFrame.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/FailureFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/FailureFrame.java index ea16526d15d..17b913c05f4 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/FailureFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/FailureFrame.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Frame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Frame.java index 6c9cc486063..bca3f38a9bd 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Frame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Frame.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java index 3353c85a5b2..a90456943ae 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -45,7 +45,7 @@ public enum FrameType private final int type; - private FrameType(int type) + FrameType(int type) { this.type = type; Types.types.put(type, this); diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/GoAwayFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/GoAwayFrame.java index 57a2dd5c5d0..64b855f2d2e 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/GoAwayFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/GoAwayFrame.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -77,10 +77,10 @@ public class GoAwayFrame extends Frame public String toString() { return String.format("%s,%d/%s/%s/%s", - super.toString(), - lastStreamId, - ErrorCode.toString(error, null), - tryConvertPayload(), - closeState); + super.toString(), + lastStreamId, + ErrorCode.toString(error, null), + tryConvertPayload(), + closeState); } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/HeadersFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/HeadersFrame.java index 478dae889e9..d3868f7c782 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/HeadersFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/HeadersFrame.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -32,8 +32,8 @@ public class HeadersFrame extends Frame *

        The stream {@code id} will be generated by the implementation while sending * this frame to the other peer.

        * - * @param metaData the metadata containing HTTP request information - * @param priority the PRIORITY frame associated with this HEADERS frame + * @param metaData the metadata containing HTTP request information + * @param priority the PRIORITY frame associated with this HEADERS frame * @param endStream whether this frame ends the stream */ public HeadersFrame(MetaData metaData, PriorityFrame priority, boolean endStream) @@ -46,9 +46,9 @@ public class HeadersFrame extends Frame *

        {@code HEADERS} frames with a specific stream {@code id} are typically used * in responses to request {@code HEADERS} frames.

        * - * @param streamId the stream id - * @param metaData the metadata containing HTTP request/response information - * @param priority the PRIORITY frame associated with this HEADERS frame + * @param streamId the stream id + * @param metaData the metadata containing HTTP request/response information + * @param priority the PRIORITY frame associated with this HEADERS frame * @param endStream whether this frame ends the stream */ public HeadersFrame(int streamId, MetaData metaData, PriorityFrame priority, boolean endStream) @@ -84,6 +84,6 @@ public class HeadersFrame extends Frame public String toString() { return String.format("%s#%d{end=%b}%s", super.toString(), streamId, endStream, - priority == null ? "" : String.format("+%s", priority)); + priority == null ? "" : String.format("+%s", priority)); } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PingFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PingFrame.java index 34f26cb2cae..450b0aa5434 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PingFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PingFrame.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PrefaceFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PrefaceFrame.java index 2879a717b0f..e1aff2b723c 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PrefaceFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PrefaceFrame.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -27,7 +27,7 @@ public class PrefaceFrame extends Frame * request, used in the direct upgrade. */ public static final byte[] PREFACE_PREAMBLE_BYTES = ( - "PRI * HTTP/2.0\r\n" + + "PRI * HTTP/2.0\r\n" + "\r\n" ).getBytes(StandardCharsets.US_ASCII); @@ -35,7 +35,7 @@ public class PrefaceFrame extends Frame * The HTTP/2 preface bytes. */ public static final byte[] PREFACE_BYTES = ( - "PRI * HTTP/2.0\r\n" + + "PRI * HTTP/2.0\r\n" + "\r\n" + "SM\r\n" + "\r\n" diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PriorityFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PriorityFrame.java index 08663a5bc03..cf314f9ce08 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PriorityFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PriorityFrame.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -47,8 +47,8 @@ public class PriorityFrame extends Frame } /** - * @deprecated use {@link #getParentStreamId()} instead. * @return int of the Parent Stream + * @deprecated use {@link #getParentStreamId()} instead. */ @Deprecated public int getDependentStreamId() diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PushPromiseFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PushPromiseFrame.java index 3ac664a4478..b6a0d9faf4a 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PushPromiseFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PushPromiseFrame.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/ResetFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/ResetFrame.java index b05a6812ca6..672c030883b 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/ResetFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/ResetFrame.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java index 76eed25b4bf..c4f78e1371a 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -30,7 +30,7 @@ public class SettingsFrame extends Frame public static final int INITIAL_WINDOW_SIZE = 4; public static final int MAX_FRAME_SIZE = 5; public static final int MAX_HEADER_LIST_SIZE = 6; - + private final Map settings; private final boolean reply; diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/BogusSocket.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/UnknownFrame.java similarity index 65% rename from jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/BogusSocket.java rename to jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/UnknownFrame.java index c55f2962a06..ffd88682b2a 100644 --- a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/BogusSocket.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/UnknownFrame.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,21 +16,21 @@ // ======================================================================== // -package org.eclipse.jetty.cdi.websocket.wsscope; +package org.eclipse.jetty.http2.frames; -import javax.inject.Inject; - -import org.eclipse.jetty.cdi.websocket.annotation.WebSocketScope; -import org.eclipse.jetty.websocket.api.Session; - -public class BogusSocket +public class UnknownFrame extends Frame { - @Inject - @WebSocketScope - private Session session; - - public Session getSession() + private final int frameType; + + public UnknownFrame(int frameType) { - return session; + super(null); + this.frameType = frameType; + } + + @Override + public String toString() + { + return String.format("%s,t=%d", super.toString(), frameType); } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/WindowUpdateFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/WindowUpdateFrame.java index fd657bf2d1d..0ad323d3afe 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/WindowUpdateFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/WindowUpdateFrame.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java index 7ae9b92199d..284f41fb517 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DisconnectGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DisconnectGenerator.java index 6b3395106b1..7085f71d786 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DisconnectGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DisconnectGenerator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/FrameGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/FrameGenerator.java index 9f32f39afa3..0194beccc27 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/FrameGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/FrameGenerator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java index e804dee3507..b7288d3897a 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java index 1b6e1735358..1e04094fc0b 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeaderGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeaderGenerator.java index 434910228ec..33283a72389 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeaderGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeaderGenerator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java index 6376bbfbd1d..4ff03bd28e5 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -140,7 +140,7 @@ public class HeadersGenerator extends FrameGenerator if (priority != null) { priorityGenerator.generatePriorityBody(header, priority.getStreamId(), - priority.getParentStreamId(), priority.getWeight(), priority.isExclusive()); + priority.getParentStreamId(), priority.getWeight(), priority.isExclusive()); } } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PingGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PingGenerator.java index 0c15664aa22..99ac42b47a6 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PingGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PingGenerator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PrefaceGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PrefaceGenerator.java index 1b8e6710654..76cf4694bbc 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PrefaceGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PrefaceGenerator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PriorityGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PriorityGenerator.java index 98630cec647..9b72800d562 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PriorityGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PriorityGenerator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java index 7c982119be8..d4fe2640ef9 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/ResetGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/ResetGenerator.java index 0f8ee2a5211..2a0533a8f08 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/ResetGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/ResetGenerator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java index 5024fff4ce8..dcb9831ff14 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/WindowUpdateGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/WindowUpdateGenerator.java index ca94b09364d..cd7a265caf8 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/WindowUpdateGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/WindowUpdateGenerator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java index 369f312618e..01c6d29e570 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -96,6 +96,11 @@ public abstract class BodyParser return headerParser.getLength(); } + protected int getFrameType() + { + return headerParser.getFrameType(); + } + protected void notifyData(DataFrame frame) { try @@ -223,9 +228,10 @@ public abstract class BodyParser } } - protected void streamFailure(int streamId, int error, String reason) + protected boolean streamFailure(int streamId, int error, String reason) { notifyStreamFailure(streamId, error, reason); + return false; } private void notifyStreamFailure(int streamId, int error, String reason) @@ -239,4 +245,9 @@ public abstract class BodyParser LOG.info("Failure while notifying listener " + listener, x); } } + + protected boolean rateControlOnEvent(Object o) + { + return headerParser.getRateControl().onEvent(o); + } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ContinuationBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ContinuationBodyParser.java index db52392be3b..fc2e03e97a0 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ContinuationBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ContinuationBodyParser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -23,6 +23,7 @@ import java.nio.ByteBuffer; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.ErrorCode; import org.eclipse.jetty.http2.Flags; +import org.eclipse.jetty.http2.frames.ContinuationFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; public class ContinuationBodyParser extends BodyParser @@ -43,7 +44,15 @@ public class ContinuationBodyParser extends BodyParser protected void emptyBody(ByteBuffer buffer) { if (hasFlag(Flags.END_HEADERS)) - onHeaders(); + { + onHeaders(buffer); + } + else + { + ContinuationFrame frame = new ContinuationFrame(getStreamId(), hasFlag(Flags.END_HEADERS)); + if (!rateControlOnEvent(frame)) + connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_continuation_frame_rate"); + } } @Override @@ -81,7 +90,7 @@ public class ContinuationBodyParser extends BodyParser headerBlockFragments.storeFragment(buffer, length, last); reset(); if (last) - return onHeaders(); + return onHeaders(buffer); return true; } } @@ -94,15 +103,20 @@ public class ContinuationBodyParser extends BodyParser return false; } - private boolean onHeaders() + private boolean onHeaders(ByteBuffer buffer) { ByteBuffer headerBlock = headerBlockFragments.complete(); MetaData metaData = headerBlockParser.parse(headerBlock, headerBlock.remaining()); + if (metaData == null) + return true; if (metaData == HeaderBlockParser.SESSION_FAILURE) return false; - if (metaData == null || metaData == HeaderBlockParser.STREAM_FAILURE) - return true; HeadersFrame frame = new HeadersFrame(getStreamId(), metaData, headerBlockFragments.getPriorityFrame(), headerBlockFragments.isEndStream()); + if (metaData == HeaderBlockParser.STREAM_FAILURE) + { + if (!rateControlOnEvent(frame)) + return connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_continuation_frame_rate"); + } notifyHeaders(frame); return true; } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java index abb7b58bc22..be0ede0a5cb 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -48,9 +48,17 @@ public class DataBodyParser extends BodyParser protected void emptyBody(ByteBuffer buffer) { if (isPadding()) + { connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_data_frame"); + } else - onData(BufferUtil.EMPTY_BUFFER, false, 0); + { + DataFrame frame = new DataFrame(getStreamId(), BufferUtil.EMPTY_BUFFER, isEndStream()); + if (!isEndStream() && !rateControlOnEvent(frame)) + connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_data_frame_rate"); + else + onData(frame); + } } @Override @@ -134,7 +142,11 @@ public class DataBodyParser extends BodyParser private void onData(ByteBuffer buffer, boolean fragment, int padding) { - DataFrame frame = new DataFrame(getStreamId(), buffer, !fragment && isEndStream(), padding); + onData(new DataFrame(getStreamId(), buffer, !fragment && isEndStream(), padding)); + } + + private void onData(DataFrame frame) + { notifyData(frame); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/GoAwayBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/GoAwayBodyParser.java index 1e8313a75c2..b84e229fc11 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/GoAwayBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/GoAwayBodyParser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderBlockFragments.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderBlockFragments.java index 86a17256b21..71ca1b3814d 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderBlockFragments.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderBlockFragments.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderBlockParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderBlockParser.java index 7dc2e2c357c..54e4661da67 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderBlockParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderBlockParser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -53,7 +53,7 @@ public class HeaderBlockParser /** * Parses @{code blockLength} HPACK bytes from the given {@code buffer}. * - * @param buffer the buffer to parse + * @param buffer the buffer to parse * @param blockLength the length of the HPACK block * @return null, if the buffer contains less than {@code blockLength} bytes; * {@link #STREAM_FAILURE} if parsing the HPACK block produced a stream failure; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderParser.java index df717084674..e735d9ada3e 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderParser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -30,14 +30,24 @@ import org.eclipse.jetty.http2.frames.FrameType; */ public class HeaderParser { + private final RateControl rateControl; private State state = State.LENGTH; private int cursor; - private int length; private int type; private int flags; private int streamId; + public HeaderParser(RateControl rateControl) + { + this.rateControl = rateControl; + } + + public RateControl getRateControl() + { + return rateControl; + } + protected void reset() { state = State.LENGTH; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java index 2a1df70a4cd..3054d5ee439 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -61,17 +61,23 @@ public class HeadersBodyParser extends BodyParser @Override protected void emptyBody(ByteBuffer buffer) { - if (hasFlag(Flags.END_HEADERS)) + if (hasFlag(Flags.PRIORITY)) + { + connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_headers_priority_frame"); + } + else if (hasFlag(Flags.END_HEADERS)) { MetaData metaData = headerBlockParser.parse(BufferUtil.EMPTY_BUFFER, 0); - onHeaders(0, 0, false, metaData); + HeadersFrame frame = new HeadersFrame(getStreamId(), metaData, null, isEndStream()); + if (!rateControlOnEvent(frame)) + connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_headers_frame_rate"); + else + onHeaders(frame); } else { headerBlockFragments.setStreamId(getStreamId()); headerBlockFragments.setEndStream(isEndStream()); - if (hasFlag(Flags.PRIORITY)) - connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_headers_priority_frame"); } } @@ -179,7 +185,15 @@ public class HeadersBodyParser extends BodyParser state = State.PADDING; loop = paddingLength == 0; if (metaData != HeaderBlockParser.STREAM_FAILURE) + { onHeaders(parentStreamId, weight, exclusive, metaData); + } + else + { + HeadersFrame frame = new HeadersFrame(getStreamId(), metaData, null, isEndStream()); + if (!rateControlOnEvent(frame)) + connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_headers_frame_rate"); + } } } else @@ -230,6 +244,11 @@ public class HeadersBodyParser extends BodyParser if (hasFlag(Flags.PRIORITY)) priorityFrame = new PriorityFrame(getStreamId(), parentStreamId, weight, exclusive); HeadersFrame frame = new HeadersFrame(getStreamId(), metaData, priorityFrame, isEndStream()); + onHeaders(frame); + } + + private void onHeaders(HeadersFrame frame) + { notifyHeaders(frame); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java index e1515134734..7545b6fe159 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -54,18 +54,22 @@ public class Parser private final HpackDecoder hpackDecoder; private final BodyParser[] bodyParsers; private UnknownBodyParser unknownBodyParser; - private int maxFrameLength; + private int maxFrameLength = Frame.DEFAULT_MAX_LENGTH; private int maxSettingsKeys = SettingsFrame.DEFAULT_MAX_KEYS; private boolean continuation; private State state = State.HEADER; public Parser(ByteBufferPool byteBufferPool, Listener listener, int maxDynamicTableSize, int maxHeaderSize) + { + this(byteBufferPool, listener, maxDynamicTableSize, maxHeaderSize, RateControl.NO_RATE_CONTROL); + } + + public Parser(ByteBufferPool byteBufferPool, Listener listener, int maxDynamicTableSize, int maxHeaderSize, RateControl rateControl) { this.byteBufferPool = byteBufferPool; this.listener = listener; - this.headerParser = new HeaderParser(); + this.headerParser = new HeaderParser(rateControl == null ? RateControl.NO_RATE_CONTROL : rateControl); this.hpackDecoder = new HpackDecoder(maxDynamicTableSize, maxHeaderSize); - this.maxFrameLength = Frame.DEFAULT_MAX_LENGTH; this.bodyParsers = new BodyParser[FrameType.values().length]; } @@ -249,29 +253,29 @@ public class Parser public interface Listener { - public void onData(DataFrame frame); + void onData(DataFrame frame); - public void onHeaders(HeadersFrame frame); + void onHeaders(HeadersFrame frame); - public void onPriority(PriorityFrame frame); + void onPriority(PriorityFrame frame); - public void onReset(ResetFrame frame); + void onReset(ResetFrame frame); - public void onSettings(SettingsFrame frame); + void onSettings(SettingsFrame frame); - public void onPushPromise(PushPromiseFrame frame); + void onPushPromise(PushPromiseFrame frame); - public void onPing(PingFrame frame); + void onPing(PingFrame frame); - public void onGoAway(GoAwayFrame frame); + void onGoAway(GoAwayFrame frame); - public void onWindowUpdate(WindowUpdateFrame frame); + void onWindowUpdate(WindowUpdateFrame frame); - public void onStreamFailure(int streamId, int error, String reason); + void onStreamFailure(int streamId, int error, String reason); - public void onConnectionFailure(int error, String reason); + void onConnectionFailure(int error, String reason); - public static class Adapter implements Listener + class Adapter implements Listener { @Override public void onData(DataFrame frame) @@ -330,7 +334,7 @@ public class Parser } } - public static class Wrapper implements Listener + class Wrapper implements Listener { private final Parser.Listener listener; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java index 3cc280ca56a..e56e573236e 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -66,7 +66,7 @@ public class PingBodyParser extends BodyParser if (buffer.remaining() >= 8) { buffer.get(payload); - return onPing(payload); + return onPing(buffer, payload); } else { @@ -80,7 +80,7 @@ public class PingBodyParser extends BodyParser payload[8 - cursor] = buffer.get(); --cursor; if (cursor == 0) - return onPing(payload); + return onPing(buffer, payload); break; } default: @@ -92,9 +92,11 @@ public class PingBodyParser extends BodyParser return false; } - private boolean onPing(byte[] payload) + private boolean onPing(ByteBuffer buffer, byte[] payload) { PingFrame frame = new PingFrame(payload, hasFlag(Flags.ACK)); + if (!rateControlOnEvent(frame)) + return connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_ping_frame_rate"); reset(); notifyPing(frame); return true; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PrefaceParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PrefaceParser.java index c007bd360d7..741bba433a7 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PrefaceParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PrefaceParser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -42,7 +42,7 @@ public class PrefaceParser *

        Advances this parser after the {@link PrefaceFrame#PREFACE_PREAMBLE_BYTES}.

        *

        This allows the HTTP/1.1 parser to parse the preamble of the preface, * which is a legal HTTP/1.1 request, and this parser will parse the remaining - * bytes, that are not parseable by a HTTP/1.1 parser.

        + * bytes, that are not parseable by an HTTP/1.1 parser.

        */ protected void directUpgrade() { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java index 6c1f94d956c..914e9387b30 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -103,7 +103,7 @@ public class PriorityBodyParser extends BodyParser if (getStreamId() == parentStreamId) return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_priority_frame"); int weight = (buffer.get() & 0xFF) + 1; - return onPriority(parentStreamId, weight, exclusive); + return onPriority(buffer, parentStreamId, weight, exclusive); } default: { @@ -114,9 +114,11 @@ public class PriorityBodyParser extends BodyParser return false; } - private boolean onPriority(int parentStreamId, int weight, boolean exclusive) + private boolean onPriority(ByteBuffer buffer, int parentStreamId, int weight, boolean exclusive) { PriorityFrame frame = new PriorityFrame(getStreamId(), parentStreamId, weight, exclusive); + if (!rateControlOnEvent(frame)) + return connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_priority_frame_rate"); reset(); notifyPriority(frame); return true; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java index c46da3dcb39..9e4341acb00 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/RoleCheckPolicy.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/RateControl.java similarity index 51% rename from jetty-jaas/src/main/java/org/eclipse/jetty/jaas/RoleCheckPolicy.java rename to jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/RateControl.java index 7be76593f59..be8f82a7cf2 100644 --- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/RoleCheckPolicy.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/RateControl.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,20 +16,24 @@ // ======================================================================== // -package org.eclipse.jetty.jaas; +package org.eclipse.jetty.http2.parser; -import java.security.Principal; -import java.security.acl.Group; - -public interface RoleCheckPolicy +/** + * Controls rate of events via {@link #onEvent(Object)}. + */ +public interface RateControl { - /* ------------------------------------------------ */ - /** Check if a role is either a runAsRole or in a set of roles - * @param roleName the role to check - * @param runAsRole a pushed role (can be null) - * @param roles a Group whose Principals are role names - * @return true if role equals runAsRole or is a member of roles. + public static final RateControl NO_RATE_CONTROL = event -> true; + + /** + *

        Applications should call this method when they want to signal an + * event that is subject to rate control.

        + *

        Implementations should return true if the event does not exceed + * the desired rate, or false to signal that the event exceeded the + * desired rate.

        + * + * @param event the event subject to rate control. + * @return true IFF the rate is within limits */ - public boolean checkRole (String roleName, Principal runAsRole, Group roles); - + public boolean onEvent(Object event); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java index 0108d485713..45d99104d18 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ServerParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ServerParser.java index 2f688b1161c..067e263cd33 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ServerParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ServerParser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -37,9 +37,9 @@ public class ServerParser extends Parser private State state = State.PREFACE; private boolean notifyPreface = true; - public ServerParser(ByteBufferPool byteBufferPool, Listener listener, int maxDynamicTableSize, int maxHeaderSize) + public ServerParser(ByteBufferPool byteBufferPool, Listener listener, int maxDynamicTableSize, int maxHeaderSize, RateControl rateControl) { - super(byteBufferPool, listener, maxDynamicTableSize, maxHeaderSize); + super(byteBufferPool, listener, maxDynamicTableSize, maxHeaderSize, rateControl); this.listener = listener; this.prefaceParser = new PrefaceParser(listener); } @@ -149,9 +149,9 @@ public class ServerParser extends Parser public interface Listener extends Parser.Listener { - public void onPreface(); + void onPreface(); - public static class Adapter extends Parser.Listener.Adapter implements Listener + class Adapter extends Parser.Listener.Adapter implements Listener { @Override public void onPreface() @@ -159,7 +159,7 @@ public class ServerParser extends Parser } } - public static class Wrapper extends Parser.Listener.Wrapper implements Listener + class Wrapper extends Parser.Listener.Wrapper implements Listener { public Wrapper(ServerParser.Listener listener) { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java index 6c9ede766f1..b58fa8a8b51 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,6 +19,7 @@ package org.eclipse.jetty.http2.parser; import java.nio.ByteBuffer; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicReference; @@ -72,7 +73,12 @@ public class SettingsBodyParser extends BodyParser @Override protected void emptyBody(ByteBuffer buffer) { - onSettings(buffer, new HashMap<>()); + 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); } @Override @@ -130,7 +136,7 @@ public class SettingsBodyParser extends BodyParser { settingValue = buffer.getInt(); if (LOG.isDebugEnabled()) - LOG.debug(String.format("setting %d=%d",settingId, settingValue)); + LOG.debug(String.format("setting %d=%d", settingId, settingValue)); if (!onSetting(buffer, settings, settingId, settingValue)) return false; state = State.SETTING_ID; @@ -157,7 +163,7 @@ public class SettingsBodyParser extends BodyParser if (cursor == 0) { if (LOG.isDebugEnabled()) - LOG.debug(String.format("setting %d=%d",settingId, settingValue)); + LOG.debug(String.format("setting %d=%d", settingId, settingValue)); if (!onSetting(buffer, settings, settingId, settingValue)) return false; state = State.SETTING_ID; @@ -200,6 +206,11 @@ public class SettingsBodyParser extends BodyParser return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_settings_max_frame_size"); SettingsFrame frame = new SettingsFrame(settings, hasFlag(Flags.ACK)); + return onSettings(frame); + } + + private boolean onSettings(SettingsFrame frame) + { reset(); notifySettings(frame); return true; @@ -207,40 +218,25 @@ public class SettingsBodyParser extends BodyParser public static SettingsFrame parseBody(final ByteBuffer buffer) { - final int bodyLength = buffer.remaining(); - final AtomicReference frameRef = new AtomicReference<>(); - SettingsBodyParser parser = new SettingsBodyParser(null, null) + AtomicReference frameRef = new AtomicReference<>(); + SettingsBodyParser parser = new SettingsBodyParser(new HeaderParser(RateControl.NO_RATE_CONTROL), new Parser.Listener.Adapter() { @Override - protected int getStreamId() + public void onSettings(SettingsFrame frame) { - return 0; + frameRef.set(frame); } @Override - protected int getBodyLength() - { - return bodyLength; - } - - @Override - protected boolean onSettings(ByteBuffer buffer, Map settings) - { - frameRef.set(new SettingsFrame(settings, false)); - return true; - } - - @Override - protected boolean connectionFailure(ByteBuffer buffer, int error, String reason) + public void onConnectionFailure(int error, String reason) { frameRef.set(null); - return false; } - }; - if (bodyLength == 0) - parser.emptyBody(buffer); - else + }); + if (buffer.hasRemaining()) parser.parse(buffer); + else + parser.emptyBody(buffer); return frameRef.get(); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/UnknownBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/UnknownBodyParser.java index 97a418c2ec4..90293fee9db 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/UnknownBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/UnknownBodyParser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,6 +20,9 @@ package org.eclipse.jetty.http2.parser; import java.nio.ByteBuffer; +import org.eclipse.jetty.http2.ErrorCode; +import org.eclipse.jetty.http2.frames.UnknownFrame; + public class UnknownBodyParser extends BodyParser { private int cursor; @@ -34,7 +37,11 @@ public class UnknownBodyParser extends BodyParser { int length = cursor == 0 ? getBodyLength() : cursor; cursor = consume(buffer, length); - return cursor == 0; + 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; } private int consume(ByteBuffer buffer, int length) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/WindowRateControl.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/WindowRateControl.java new file mode 100644 index 00000000000..00a2c769737 --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/WindowRateControl.java @@ -0,0 +1,65 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.parser; + +import java.time.Duration; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.atomic.AtomicInteger; + +/** + *

        An implementation of {@link RateControl} that limits the number of + * events within a time period.

        + *

        Events are kept in a queue and for each event the queue is first + * drained of the old events outside the time window, and then the new + * event is added to the queue. The size of the queue is maintained + * separately in an AtomicInteger and if it exceeds the max + * number of events then {@link #onEvent(Object)} returns {@code false}.

        + */ +public class WindowRateControl implements RateControl +{ + private final Queue events = new ConcurrentLinkedQueue<>(); + private final AtomicInteger size = new AtomicInteger(); + private final int maxEvents; + private final long window; + + public WindowRateControl(int maxEvents, Duration window) + { + this.maxEvents = maxEvents; + this.window = window.toNanos(); + } + + @Override + public boolean onEvent(Object event) + { + long now = System.nanoTime(); + while (true) + { + Long time = events.peek(); + if (time == null) + break; + if (now < time) + break; + if (events.remove(time)) + size.decrementAndGet(); + } + events.add(now + window); + return size.incrementAndGet() <= maxEvents; + } +} diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/WindowUpdateBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/WindowUpdateBodyParser.java index 145353730c0..2c3ec6b736c 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/WindowUpdateBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/WindowUpdateBodyParser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -61,7 +61,7 @@ public class WindowUpdateBodyParser extends BodyParser if (buffer.remaining() >= 4) { windowDelta = buffer.getInt() & 0x7F_FF_FF_FF; - return onWindowUpdate(windowDelta); + return onWindowUpdate(buffer, windowDelta); } else { @@ -78,7 +78,7 @@ public class WindowUpdateBodyParser extends BodyParser if (cursor == 0) { windowDelta &= 0x7F_FF_FF_FF; - return onWindowUpdate(windowDelta); + return onWindowUpdate(buffer, windowDelta); } break; } @@ -91,9 +91,17 @@ public class WindowUpdateBodyParser extends BodyParser return false; } - private boolean onWindowUpdate(int windowDelta) + private boolean onWindowUpdate(ByteBuffer buffer, int windowDelta) { - WindowUpdateFrame frame = new WindowUpdateFrame(getStreamId(), windowDelta); + int streamId = getStreamId(); + if (windowDelta == 0) + { + if (streamId == 0) + return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_window_update_frame"); + else + return streamFailure(streamId, ErrorCode.PROTOCOL_ERROR.code, "invalid_window_update_frame"); + } + WindowUpdateFrame frame = new WindowUpdateFrame(streamId, windowDelta); reset(); notifyWindowUpdate(frame); return true; diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ContinuationParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ContinuationParseTest.java index e1f6aba087b..4db00c3db4b 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ContinuationParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ContinuationParseTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,10 +18,6 @@ package org.eclipse.jetty.http2.frames; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; @@ -40,9 +36,12 @@ import org.eclipse.jetty.http2.hpack.HpackEncoder; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.MappedByteBufferPool; - import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class ContinuationParseTest { @Test diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java index 097de2d32d6..3b018233a83 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,9 +18,6 @@ package org.eclipse.jetty.http2.frames; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; @@ -33,9 +30,11 @@ import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.MappedByteBufferPool; import org.eclipse.jetty.util.BufferUtil; - import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class DataGenerateParseTest { private final byte[] smallContent = new byte[128]; @@ -72,7 +71,7 @@ public class DataGenerateParseTest } @Test - public void testGenerateParseLargeContent() + public void testGenerateParseLargeContent() { ByteBuffer content = ByteBuffer.wrap(largeContent); List frames = testGenerateParse(content); diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/FrameFloodTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/FrameFloodTest.java new file mode 100644 index 00000000000..04685dcb743 --- /dev/null +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/FrameFloodTest.java @@ -0,0 +1,161 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.frames; + +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; +import org.eclipse.jetty.http2.Flags; +import org.eclipse.jetty.http2.hpack.HpackEncoder; +import org.eclipse.jetty.http2.parser.Parser; +import org.eclipse.jetty.http2.parser.WindowRateControl; +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.io.MappedByteBufferPool; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.lessThan; + +public class FrameFloodTest +{ + private final ByteBufferPool byteBufferPool = new MappedByteBufferPool(); + + // Frame structure: + // | Len0 | Len1 | Len2 | Type | Flags | StreamID0 |StreamID1 |StreamID2 |StreamID3 | Payload... | + + private byte[] frameFrom(int length, int frameType, int flags, int streamId, byte[] payload) + { + byte[] result = new byte[3 + 1 + 1 + 4 + payload.length]; + result[0] = (byte)((length >>> 16) & 0xFF); + result[1] = (byte)((length >>> 8) & 0xFF); + result[2] = (byte)(length & 0xFF); + result[3] = (byte)frameType; + result[4] = (byte)flags; + result[5] = (byte)((streamId >>> 24) & 0xFF); + result[6] = (byte)((streamId >>> 16) & 0xFF); + result[7] = (byte)((streamId >>> 8) & 0xFF); + result[8] = (byte)(streamId & 0xFF); + System.arraycopy(payload, 0, result, 9, payload.length); + return result; + } + + @Test + public void testDataFrameFlood() + { + byte[] payload = new byte[0]; + testFrameFlood(null, frameFrom(payload.length, FrameType.DATA.getType(), 0, 13, payload)); + } + + @Test + public void testHeadersFrameFlood() + { + byte[] payload = new byte[0]; + testFrameFlood(null, frameFrom(payload.length, FrameType.HEADERS.getType(), Flags.END_HEADERS, 13, payload)); + } + + @Test + public void testInvalidHeadersFrameFlood() + { + // Invalid MetaData (no method, no scheme, etc). + MetaData.Request metadata = new MetaData.Request(null, (String)null, null, null, HttpVersion.HTTP_2, null, -1); + HpackEncoder encoder = new HpackEncoder(); + ByteBuffer buffer = ByteBuffer.allocate(1024); + encoder.encode(buffer, metadata); + buffer.flip(); + byte[] payload = new byte[buffer.remaining()]; + buffer.get(payload); + testFrameFlood(null, frameFrom(payload.length, FrameType.HEADERS.getType(), Flags.END_HEADERS, 13, payload)); + } + + @Test + public void testPriorityFrameFlood() + { + byte[] payload = new byte[]{0, 0, 0, 7, 0}; + testFrameFlood(null, frameFrom(payload.length, FrameType.PRIORITY.getType(), 0, 13, payload)); + } + + @Test + public void testSettingsFrameFlood() + { + byte[] payload = new byte[0]; + 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() + { + int streamId = 13; + byte[] headersPayload = new byte[0]; + byte[] headersBytes = frameFrom(headersPayload.length, FrameType.HEADERS.getType(), 0, streamId, headersPayload); + byte[] continuationPayload = new byte[0]; + testFrameFlood(headersBytes, frameFrom(continuationPayload.length, FrameType.CONTINUATION.getType(), 0, streamId, continuationPayload)); + } + + @Test + public void testUnknownFrameFlood() + { + byte[] payload = {0, 0, 0, 0}; + testFrameFlood(null, frameFrom(payload.length, 64, 0, 0, payload)); + } + + private void testFrameFlood(byte[] preamble, byte[] bytes) + { + AtomicBoolean failed = new AtomicBoolean(); + Parser parser = new Parser(byteBufferPool, 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) + { + ByteBuffer buffer = ByteBuffer.wrap(preamble); + while (buffer.hasRemaining()) + { + parser.parse(buffer); + } + } + + int count = 0; + while (!failed.get()) + { + ByteBuffer buffer = ByteBuffer.wrap(bytes); + while (buffer.hasRemaining()) + { + parser.parse(buffer); + } + assertThat("too many frames allowed", ++count, lessThan(1024)); + } + } +} diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java index 36bae05839c..0cc7e37c870 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,10 +18,6 @@ package org.eclipse.jetty.http2.frames; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; - import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; @@ -33,9 +29,12 @@ import org.eclipse.jetty.http2.generator.HeaderGenerator; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.MappedByteBufferPool; - import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + public class GoAwayGenerateParseTest { private final ByteBufferPool byteBufferPool = new MappedByteBufferPool(); diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java index b5a0ba1787f..b67fe45d589 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,10 +18,6 @@ package org.eclipse.jetty.http2.frames; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; @@ -39,9 +35,12 @@ import org.eclipse.jetty.http2.hpack.HpackEncoder; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.MappedByteBufferPool; - import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class HeadersGenerateParseTest { private final ByteBufferPool byteBufferPool = new MappedByteBufferPool(); diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/MaxFrameSizeParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/MaxFrameSizeParseTest.java index 2004b33d82a..43a97f0da81 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/MaxFrameSizeParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/MaxFrameSizeParseTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -59,7 +59,9 @@ public class MaxFrameSizeParseTest buffer.putInt(0, maxFrameLength + 1); buffer.position(1); while (buffer.hasRemaining()) + { parser.parse(buffer); + } } assertEquals(ErrorCode.FRAME_SIZE_ERROR.code, failure.get()); diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java index 45f2a69fa24..0b7c31f9674 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,10 +18,6 @@ package org.eclipse.jetty.http2.frames; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; @@ -33,9 +29,12 @@ import org.eclipse.jetty.http2.generator.PingGenerator; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.MappedByteBufferPool; - import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class PingGenerateParseTest { private final ByteBufferPool byteBufferPool = new MappedByteBufferPool(); diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java index 9aa3f5d8db6..ecbdd10caf8 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,8 +18,6 @@ package org.eclipse.jetty.http2.frames; -import static org.junit.jupiter.api.Assertions.assertEquals; - import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; @@ -30,9 +28,10 @@ import org.eclipse.jetty.http2.generator.PriorityGenerator; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.MappedByteBufferPool; - import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class PriorityGenerateParseTest { private final ByteBufferPool byteBufferPool = new MappedByteBufferPool(); diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java index 9448d92bb17..3d6d8db2938 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,9 +18,6 @@ package org.eclipse.jetty.http2.frames; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; @@ -38,9 +35,11 @@ import org.eclipse.jetty.http2.hpack.HpackEncoder; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.MappedByteBufferPool; - import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class PushPromiseGenerateParseTest { private final ByteBufferPool byteBufferPool = new MappedByteBufferPool(); diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java index 9d412663755..4a2f9a35d8e 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,8 +18,6 @@ package org.eclipse.jetty.http2.frames; -import static org.junit.jupiter.api.Assertions.assertEquals; - import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; @@ -30,9 +28,10 @@ import org.eclipse.jetty.http2.generator.ResetGenerator; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.MappedByteBufferPool; - import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class ResetGenerateParseTest { private final ByteBufferPool byteBufferPool = new MappedByteBufferPool(); diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java index 0cd08e7a614..9fcdb743dc6 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,9 +18,6 @@ package org.eclipse.jetty.http2.frames; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections; @@ -36,9 +33,11 @@ import org.eclipse.jetty.http2.generator.SettingsGenerator; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.MappedByteBufferPool; - import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class SettingsGenerateParseTest { private final ByteBufferPool byteBufferPool = new MappedByteBufferPool(); @@ -207,7 +206,9 @@ public class SettingsGenerateParseTest Map settings = new HashMap<>(); for (int i = 0; i < maxSettingsKeys + 1; ++i) + { settings.put(i + 10, i); + } ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); generator.generateSettings(lease, settings, false); @@ -215,7 +216,9 @@ public class SettingsGenerateParseTest for (ByteBuffer buffer : lease.getByteBuffers()) { while (buffer.hasRemaining()) + { parser.parse(buffer); + } } assertEquals(ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, errorRef.get()); @@ -257,7 +260,9 @@ public class SettingsGenerateParseTest buffer.flip().position(1); while (buffer.hasRemaining()) + { parser.parse(buffer); + } assertEquals(ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, errorRef.get()); } @@ -285,12 +290,16 @@ public class SettingsGenerateParseTest ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); for (int i = 0; i < maxSettingsKeys + 1; ++i) + { generator.generateSettings(lease, settings, false); + } for (ByteBuffer buffer : lease.getByteBuffers()) { while (buffer.hasRemaining()) + { parser.parse(buffer); + } } assertEquals(ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, errorRef.get()); diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/UnknownParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/UnknownParseTest.java index a9a6ec29897..9f81bfed88d 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/UnknownParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/UnknownParseTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -68,7 +68,9 @@ public class UnknownParseTest byte[] bytes = new byte[]{0, 0x40, 0x01, 64, 0, 0, 0, 0, 0}; ByteBuffer buffer = ByteBuffer.wrap(bytes); while (buffer.hasRemaining()) + { parser.parse(buffer); + } assertEquals(ErrorCode.FRAME_SIZE_ERROR.code, failure.get()); } @@ -92,7 +94,9 @@ public class UnknownParseTest byte[] bytes = new byte[]{0, 0, 4, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0}; ByteBuffer buffer = ByteBuffer.wrap(bytes); while (buffer.hasRemaining()) + { parser.parse(fn.apply(buffer)); + } } assertFalse(failure.get()); diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java index 51ad3cb2abf..04825a5e7a6 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,8 +18,6 @@ package org.eclipse.jetty.http2.frames; -import static org.junit.jupiter.api.Assertions.assertEquals; - import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; @@ -30,9 +28,10 @@ import org.eclipse.jetty.http2.generator.WindowUpdateGenerator; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.MappedByteBufferPool; - import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class WindowUpdateGenerateParseTest { private final ByteBufferPool byteBufferPool = new MappedByteBufferPool(); diff --git a/jetty-http2/http2-hpack/pom.xml b/jetty-http2/http2-hpack/pom.xml index fe042116485..b0fbcb380cb 100644 --- a/jetty-http2/http2-hpack/pom.xml +++ b/jetty-http2/http2-hpack/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.http2 http2-parent - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 @@ -51,18 +51,18 @@ - + org.apache.felix maven-bundle-plugin true - - - Http2 Hpack - osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional - osgi.serviceloader;osgi.serviceloader=org.eclipse.jetty.http.HttpFieldPreEncoder - <_nouses>true - - + + + Http2 Hpack + osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional + osgi.serviceloader;osgi.serviceloader=org.eclipse.jetty.http.HttpFieldPreEncoder + <_nouses>true + + diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/AuthorityHttpField.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/AuthorityHttpField.java index 57fc182e4a0..712b4853694 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/AuthorityHttpField.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/AuthorityHttpField.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,28 +16,26 @@ // ======================================================================== // - package org.eclipse.jetty.http2.hpack; import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpHeader; - -/* ------------------------------------------------------------ */ /** + * */ public class AuthorityHttpField extends HostPortHttpField { - public final static String AUTHORITY = HpackContext.STATIC_TABLE[1][0]; - + public static final String AUTHORITY = HpackContext.STATIC_TABLE[1][0]; + public AuthorityHttpField(String authority) { - super(HttpHeader.C_AUTHORITY,AUTHORITY,authority); + super(HttpHeader.C_AUTHORITY, AUTHORITY, authority); } - + @Override public String toString() { - return String.format("%s(preparsed h=%s p=%d)",super.toString(),getHost(),getPort()); + return String.format("%s(preparsed h=%s p=%d)", super.toString(), getHost(), getPort()); } } diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java index 2d7b6757d3d..dda8ec30cb7 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -48,87 +48,88 @@ public class HpackContext public static final Logger LOG = Log.getLogger(HpackContext.class); private static final String EMPTY = ""; public static final String[][] STATIC_TABLE = - { - {null,null}, - /* 1 */ {":authority",EMPTY}, - /* 2 */ {":method","GET"}, - /* 3 */ {":method","POST"}, - /* 4 */ {":path","/"}, - /* 5 */ {":path","/index.html"}, - /* 6 */ {":scheme","http"}, - /* 7 */ {":scheme","https"}, - /* 8 */ {":status","200"}, - /* 9 */ {":status","204"}, - /* 10 */ {":status","206"}, - /* 11 */ {":status","304"}, - /* 12 */ {":status","400"}, - /* 13 */ {":status","404"}, - /* 14 */ {":status","500"}, - /* 15 */ {"accept-charset",EMPTY}, - /* 16 */ {"accept-encoding","gzip, deflate"}, - /* 17 */ {"accept-language",EMPTY}, - /* 18 */ {"accept-ranges",EMPTY}, - /* 19 */ {"accept",EMPTY}, - /* 20 */ {"access-control-allow-origin",EMPTY}, - /* 21 */ {"age",EMPTY}, - /* 22 */ {"allow",EMPTY}, - /* 23 */ {"authorization",EMPTY}, - /* 24 */ {"cache-control",EMPTY}, - /* 25 */ {"content-disposition",EMPTY}, - /* 26 */ {"content-encoding",EMPTY}, - /* 27 */ {"content-language",EMPTY}, - /* 28 */ {"content-length",EMPTY}, - /* 29 */ {"content-location",EMPTY}, - /* 30 */ {"content-range",EMPTY}, - /* 31 */ {"content-type",EMPTY}, - /* 32 */ {"cookie",EMPTY}, - /* 33 */ {"date",EMPTY}, - /* 34 */ {"etag",EMPTY}, - /* 35 */ {"expect",EMPTY}, - /* 36 */ {"expires",EMPTY}, - /* 37 */ {"from",EMPTY}, - /* 38 */ {"host",EMPTY}, - /* 39 */ {"if-match",EMPTY}, - /* 40 */ {"if-modified-since",EMPTY}, - /* 41 */ {"if-none-match",EMPTY}, - /* 42 */ {"if-range",EMPTY}, - /* 43 */ {"if-unmodified-since",EMPTY}, - /* 44 */ {"last-modified",EMPTY}, - /* 45 */ {"link",EMPTY}, - /* 46 */ {"location",EMPTY}, - /* 47 */ {"max-forwards",EMPTY}, - /* 48 */ {"proxy-authenticate",EMPTY}, - /* 49 */ {"proxy-authorization",EMPTY}, - /* 50 */ {"range",EMPTY}, - /* 51 */ {"referer",EMPTY}, - /* 52 */ {"refresh",EMPTY}, - /* 53 */ {"retry-after",EMPTY}, - /* 54 */ {"server",EMPTY}, - /* 55 */ {"set-cookie",EMPTY}, - /* 56 */ {"strict-transport-security",EMPTY}, - /* 57 */ {"transfer-encoding",EMPTY}, - /* 58 */ {"user-agent",EMPTY}, - /* 59 */ {"vary",EMPTY}, - /* 60 */ {"via",EMPTY}, - /* 61 */ {"www-authenticate",EMPTY}, - }; + { + {null, null}, + /* 1 */ {":authority", EMPTY}, + /* 2 */ {":method", "GET"}, + /* 3 */ {":method", "POST"}, + /* 4 */ {":path", "/"}, + /* 5 */ {":path", "/index.html"}, + /* 6 */ {":scheme", "http"}, + /* 7 */ {":scheme", "https"}, + /* 8 */ {":status", "200"}, + /* 9 */ {":status", "204"}, + /* 10 */ {":status", "206"}, + /* 11 */ {":status", "304"}, + /* 12 */ {":status", "400"}, + /* 13 */ {":status", "404"}, + /* 14 */ {":status", "500"}, + /* 15 */ {"accept-charset", EMPTY}, + /* 16 */ {"accept-encoding", "gzip, deflate"}, + /* 17 */ {"accept-language", EMPTY}, + /* 18 */ {"accept-ranges", EMPTY}, + /* 19 */ {"accept", EMPTY}, + /* 20 */ {"access-control-allow-origin", EMPTY}, + /* 21 */ {"age", EMPTY}, + /* 22 */ {"allow", EMPTY}, + /* 23 */ {"authorization", EMPTY}, + /* 24 */ {"cache-control", EMPTY}, + /* 25 */ {"content-disposition", EMPTY}, + /* 26 */ {"content-encoding", EMPTY}, + /* 27 */ {"content-language", EMPTY}, + /* 28 */ {"content-length", EMPTY}, + /* 29 */ {"content-location", EMPTY}, + /* 30 */ {"content-range", EMPTY}, + /* 31 */ {"content-type", EMPTY}, + /* 32 */ {"cookie", EMPTY}, + /* 33 */ {"date", EMPTY}, + /* 34 */ {"etag", EMPTY}, + /* 35 */ {"expect", EMPTY}, + /* 36 */ {"expires", EMPTY}, + /* 37 */ {"from", EMPTY}, + /* 38 */ {"host", EMPTY}, + /* 39 */ {"if-match", EMPTY}, + /* 40 */ {"if-modified-since", EMPTY}, + /* 41 */ {"if-none-match", EMPTY}, + /* 42 */ {"if-range", EMPTY}, + /* 43 */ {"if-unmodified-since", EMPTY}, + /* 44 */ {"last-modified", EMPTY}, + /* 45 */ {"link", EMPTY}, + /* 46 */ {"location", EMPTY}, + /* 47 */ {"max-forwards", EMPTY}, + /* 48 */ {"proxy-authenticate", EMPTY}, + /* 49 */ {"proxy-authorization", EMPTY}, + /* 50 */ {"range", EMPTY}, + /* 51 */ {"referer", EMPTY}, + /* 52 */ {"refresh", EMPTY}, + /* 53 */ {"retry-after", EMPTY}, + /* 54 */ {"server", EMPTY}, + /* 55 */ {"set-cookie", EMPTY}, + /* 56 */ {"strict-transport-security", EMPTY}, + /* 57 */ {"transfer-encoding", EMPTY}, + /* 58 */ {"user-agent", EMPTY}, + /* 59 */ {"vary", EMPTY}, + /* 60 */ {"via", EMPTY}, + /* 61 */ {"www-authenticate", EMPTY} + }; - private static final Map __staticFieldMap = new HashMap<>(); - private static final Trie __staticNameMap = new ArrayTernaryTrie<>(true,512); + private static final Map __staticFieldMap = new HashMap<>(); + private static final Trie __staticNameMap = new ArrayTernaryTrie<>(true, 512); 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; + private static final StaticEntry[] __staticTable = new StaticEntry[STATIC_TABLE.length]; + public static final int STATIC_SIZE = STATIC_TABLE.length - 1; + static { Set added = new HashSet<>(); - for (int i=1;i _fieldMap = new HashMap<>(); - private final Map _nameMap = new HashMap<>(); + private final Map _fieldMap = new HashMap<>(); + private final Map _nameMap = new HashMap<>(); HpackContext(int maxDynamicTableSize) { - _maxDynamicTableSizeInBytes=maxDynamicTableSize; - int guesstimateEntries = 10+maxDynamicTableSize/(32+10+10); - _dynamicTable=new DynamicTable(guesstimateEntries); + _maxDynamicTableSizeInBytes = maxDynamicTableSize; + int guesstimateEntries = 10 + maxDynamicTableSize / (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(), maxDynamicTableSize)); } 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(), _maxDynamicTableSizeInBytes, newMaxDynamicTableSize)); + _maxDynamicTableSizeInBytes = newMaxDynamicTableSize; _dynamicTable.evict(); } public Entry get(HttpField field) { Entry entry = _fieldMap.get(field); - if (entry==null) - entry=__staticFieldMap.get(field); + if (entry == null) + entry = __staticFieldMap.get(field); return entry; } public Entry get(String name) { Entry entry = __staticNameMap.get(name); - if (entry!=null) + if (entry != null) return entry; return _nameMap.get(StringUtil.asciiToLowerCase(name)); } public Entry get(int index) { - if (index<=STATIC_SIZE) + if (index <= STATIC_SIZE) return __staticTable[index]; return _dynamicTable.get(index); @@ -237,7 +237,7 @@ public class HpackContext public Entry get(HttpHeader header) { Entry e = __staticTableByHeader[header.ordinal()]; - if (e==null) + if (e == null) return get(header.asString()); return e; } @@ -249,22 +249,22 @@ public class HpackContext public Entry add(HttpField field) { - Entry entry=new Entry(field); + Entry entry = new Entry(field); int size = entry.getSize(); - if (size>_maxDynamicTableSizeInBytes) + if (size > _maxDynamicTableSizeInBytes) { 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, _maxDynamicTableSizeInBytes)); _dynamicTable.evictAll(); return null; } - _dynamicTableSizeInBytes+=size; + _dynamicTableSizeInBytes += size; _dynamicTable.add(entry); - _fieldMap.put(field,entry); - _nameMap.put(StringUtil.asciiToLowerCase(field.getName()),entry); + _fieldMap.put(field, entry); + _nameMap.put(StringUtil.asciiToLowerCase(field.getName()), entry); if (LOG.isDebugEnabled()) - LOG.debug(String.format("HdrTbl[%x] added %s",hashCode(),entry)); + LOG.debug(String.format("HdrTbl[%x] added %s", hashCode(), entry)); _dynamicTable.evict(); return entry; } @@ -295,7 +295,7 @@ public class HpackContext public int index(Entry entry) { - if (entry._slot<0) + if (entry._slot < 0) return 0; if (entry.isStatic()) return entry._slot; @@ -305,64 +305,63 @@ public class HpackContext public static int staticIndex(HttpHeader header) { - if (header==null) + if (header == null) return 0; - Entry entry=__staticNameMap.get(header.asString()); - if (entry==null) + Entry entry = __staticNameMap.get(header.asString()); + if (entry == null) return 0; return entry._slot; } - @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(), _dynamicTableSizeInBytes, _maxDynamicTableSizeInBytes); } - private class DynamicTable + private class DynamicTable { Entry[] _entries; int _size; int _offset; int _growby; - + private DynamicTable(int initCapacity) { - _entries=new Entry[initCapacity]; - _growby=initCapacity; + _entries = new Entry[initCapacity]; + _growby = initCapacity; } public void add(Entry entry) { - if (_size==_entries.length) + if (_size == _entries.length) { - Entry[] entries = new Entry[_entries.length+_growby]; - for (int i=0;i<_size;i++) + Entry[] entries = new Entry[_entries.length + _growby]; + for (int i = 0; i < _size; i++) { - int slot = (_offset+i)%_entries.length; - entries[i]=_entries[slot]; - entries[i]._slot=i; + int slot = (_offset + i) % _entries.length; + entries[i] = _entries[slot]; + entries[i]._slot = i; } - _entries=entries; - _offset=0; + _entries = entries; + _offset = 0; } - int slot=(_size++ + _offset)%_entries.length; - _entries[slot]=entry; - entry._slot=slot; + int slot = (_size++ + _offset) % _entries.length; + _entries[slot] = entry; + entry._slot = slot; } public int index(Entry entry) { - return STATIC_SIZE + _size-(entry._slot-_offset+_entries.length)%_entries.length; + return STATIC_SIZE + _size - (entry._slot - _offset + _entries.length) % _entries.length; } - + public Entry get(int index) { - int d = index-STATIC_SIZE-1; - if (d<0 || d>=_size) + int d = index - STATIC_SIZE - 1; + if (d < 0 || d >= _size) return null; - int slot = (_offset+_size-d-1)%_entries.length; + int slot = (_offset + _size - d - 1) % _entries.length; return _entries[slot]; } @@ -373,36 +372,35 @@ public class HpackContext private void evict() { - while (_dynamicTableSizeInBytes>_maxDynamicTableSizeInBytes) + while (_dynamicTableSizeInBytes > _maxDynamicTableSizeInBytes) { Entry entry = _entries[_offset]; - _entries[_offset]=null; - _offset = (_offset+1)%_entries.length; + _entries[_offset] = null; + _offset = (_offset + 1) % _entries.length; _size--; if (LOG.isDebugEnabled()) - LOG.debug(String.format("HdrTbl[%x] evict %s",HpackContext.this.hashCode(),entry)); - _dynamicTableSizeInBytes-=entry.getSize(); - entry._slot=-1; + LOG.debug(String.format("HdrTbl[%x] evict %s", HpackContext.this.hashCode(), entry)); + _dynamicTableSizeInBytes -= entry.getSize(); + entry._slot = -1; _fieldMap.remove(entry.getHttpField()); - String lc=StringUtil.asciiToLowerCase(entry.getHttpField().getName()); - if (entry==_nameMap.get(lc)) + String lc = StringUtil.asciiToLowerCase(entry.getHttpField().getName()); + if (entry == _nameMap.get(lc)) _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(), _dynamicTableSizeInBytes, _maxDynamicTableSizeInBytes)); } - + private void evictAll() { if (LOG.isDebugEnabled()) - LOG.debug(String.format("HdrTbl[%x] evictAll",HpackContext.this.hashCode())); + LOG.debug(String.format("HdrTbl[%x] evictAll", HpackContext.this.hashCode())); _fieldMap.clear(); _nameMap.clear(); _offset = 0; _size = 0; _dynamicTableSizeInBytes = 0; - Arrays.fill(_entries,null); + Arrays.fill(_entries, null); } } @@ -413,13 +411,13 @@ public class HpackContext Entry() { - _slot=-1; - _field=null; + _slot = -1; + _field = null; } Entry(HttpField field) { - _field=field; + _field = field; } public int getSize() @@ -446,7 +444,7 @@ public class HpackContext @Override public String toString() { - return String.format("{%s,%d,%s,%x}",isStatic()?"S":"D",_slot,_field,hashCode()); + return String.format("{%s,%d,%s,%x}", isStatic() ? "S" : "D", _slot, _field, hashCode()); } } @@ -455,29 +453,29 @@ public class HpackContext private final byte[] _huffmanValue; private final byte _encodedField; - StaticEntry(int index,HttpField field) + StaticEntry(int index, HttpField field) { super(field); - _slot=index; + _slot = index; String value = field.getValue(); - if (value!=null && value.length()>0) + if (value != null && value.length() > 0) { int huffmanLen = Huffman.octetsNeeded(value); - int lenLen = NBitInteger.octectsNeeded(7,huffmanLen); - _huffmanValue = new byte[1+lenLen+huffmanLen]; + int lenLen = NBitInteger.octectsNeeded(7, huffmanLen); + _huffmanValue = new byte[1 + lenLen + huffmanLen]; ByteBuffer buffer = ByteBuffer.wrap(_huffmanValue); // Indicate Huffman buffer.put((byte)0x80); // Add huffman length - NBitInteger.encode(buffer,7,huffmanLen); + NBitInteger.encode(buffer, 7, huffmanLen); // Encode value - Huffman.encode(buffer,value); + Huffman.encode(buffer, value); } else - _huffmanValue=null; + _huffmanValue = null; - _encodedField=(byte)(0x80|index); + _encodedField = (byte)(0x80 | index); } @Override diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java index df7b2a6e971..bb1d3ede5fb 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,13 +16,13 @@ // ======================================================================== // - package org.eclipse.jetty.http2.hpack; import java.nio.ByteBuffer; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.http.HttpTokens; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.hpack.HpackContext.Entry; import org.eclipse.jetty.util.TypeUtil; @@ -36,21 +36,21 @@ import org.eclipse.jetty.util.log.Logger; public class HpackDecoder { public static final Logger LOG = Log.getLogger(HpackDecoder.class); - public final static HttpField.LongValueHttpField CONTENT_LENGTH_0 = - new HttpField.LongValueHttpField(HttpHeader.CONTENT_LENGTH,0L); + public static final HttpField.LongValueHttpField CONTENT_LENGTH_0 = + new HttpField.LongValueHttpField(HttpHeader.CONTENT_LENGTH, 0L); private final HpackContext _context; private final MetaDataBuilder _builder; private int _localMaxDynamicTableSize; /** - * @param localMaxDynamicTableSize The maximum allowed size of the local dynamic header field table. + * @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 */ public HpackDecoder(int localMaxDynamicTableSize, int maxHeaderSize) { - _context=new HpackContext(localMaxDynamicTableSize); - _localMaxDynamicTableSize=localMaxDynamicTableSize; + _context = new HpackContext(localMaxDynamicTableSize); + _localMaxDynamicTableSize = localMaxDynamicTableSize; _builder = new MetaDataBuilder(maxHeaderSize); } @@ -61,43 +61,43 @@ public class HpackDecoder public void setLocalMaxDynamicTableSize(int localMaxdynamciTableSize) { - _localMaxDynamicTableSize=localMaxdynamciTableSize; + _localMaxDynamicTableSize = localMaxdynamciTableSize; } public MetaData decode(ByteBuffer buffer) throws HpackException.SessionException, HpackException.StreamException { if (LOG.isDebugEnabled()) - LOG.debug(String.format("CtxTbl[%x] decoding %d octets",_context.hashCode(),buffer.remaining())); + 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()) + if (buffer.remaining() > _builder.getMaxSize()) throw new HpackException.SessionException("431 Request Header Fields too large"); - + boolean emitted = false; - while(buffer.hasRemaining()) + while (buffer.hasRemaining()) { if (LOG.isDebugEnabled() && buffer.hasArray()) { - int l=Math.min(buffer.remaining(),32); + int l = Math.min(buffer.remaining(), 32); LOG.debug("decode {}{}", - TypeUtil.toHexString(buffer.array(),buffer.arrayOffset()+buffer.position(),l), - l>4); + byte f = (byte)((b & 0xF0) >> 4); String name; HttpHeader header; String value; boolean indexed; - int name_index; + int nameIndex; switch (f) { case 2: // 7.3 case 3: // 7.3 // change table size - int size = NBitInteger.decode(buffer,5); + int size = NBitInteger.decode(buffer, 5); if (LOG.isDebugEnabled()) - LOG.debug("decode resize="+size); - if (size>_localMaxDynamicTableSize) + LOG.debug("decode resize=" + size); + if (size > _localMaxDynamicTableSize) throw new IllegalArgumentException(); if (emitted) throw new HpackException.CompressionException("Dynamic table resize after fields"); @@ -142,79 +142,100 @@ public class HpackDecoder case 0: // 7.2.2 case 1: // 7.2.3 - indexed=false; - name_index=NBitInteger.decode(buffer,4); + indexed = false; + nameIndex = NBitInteger.decode(buffer, 4); break; case 4: // 7.2.1 case 5: // 7.2.1 case 6: // 7.2.1 case 7: // 7.2.1 - indexed=true; - name_index=NBitInteger.decode(buffer,6); + indexed = true; + nameIndex = NBitInteger.decode(buffer, 6); break; default: throw new IllegalStateException(); } - boolean huffmanName=false; + boolean huffmanName = false; // decode the name - if (name_index>0) + if (nameIndex > 0) { - Entry name_entry=_context.get(name_index); - name=name_entry.getHttpField().getName(); - header=name_entry.getHttpField().getHeader(); + Entry nameEntry = _context.get(nameIndex); + name = nameEntry.getHttpField().getName(); + header = nameEntry.getHttpField().getHeader(); } else { - huffmanName = (buffer.get()&0x80)==0x80; - int length = NBitInteger.decode(buffer,7); - _builder.checkSize(length,huffmanName); + huffmanName = (buffer.get() & 0x80) == 0x80; + int length = NBitInteger.decode(buffer, 7); + _builder.checkSize(length, huffmanName); if (huffmanName) - name=Huffman.decode(buffer,length); + name = Huffman.decode(buffer, length); else - name=toASCIIString(buffer,length); - for (int i=0;i 0;) { - char c=name.charAt(i); - if (c>='A'&&c<='Z') + char c = name.charAt(i); + if (c > 0xff) { - _builder.streamException("Uppercase header name %s",name); + _builder.streamException("Illegal header name %s", name); break; } + HttpTokens.Token token = HttpTokens.TOKENS[0xFF & c]; + switch (token.getType()) + { + case ALPHA: + if (c >= 'A' && c <= 'Z') + { + _builder.streamException("Uppercase header name %s", name); + break check; + } + break; + + case COLON: + case TCHAR: + case DIGIT: + break; + + default: + _builder.streamException("Illegal header name %s", name); + break check; + } } - header=HttpHeader.CACHE.get(name); + header = HttpHeader.CACHE.get(name); } // decode the value - boolean huffmanValue = (buffer.get()&0x80)==0x80; - int length = NBitInteger.decode(buffer,7); - _builder.checkSize(length,huffmanValue); + boolean huffmanValue = (buffer.get() & 0x80) == 0x80; + int length = NBitInteger.decode(buffer, 7); + _builder.checkSize(length, huffmanValue); if (huffmanValue) - value=Huffman.decode(buffer,length); + value = Huffman.decode(buffer, length); else - value=toASCIIString(buffer,length); + value = toASCIIString(buffer, length); // Make the new field HttpField field; - if (header==null) + if (header == null) { // just make a normal field and bypass header name lookup - field = new HttpField(null,name,value); + field = new HttpField(null, name, value); } else { // might be worthwhile to create a value HttpField if it is indexed // and/or of a type that may be looked up multiple times. - switch(header) + switch (header) { case C_STATUS: if (indexed) - field = new HttpField.IntValueHttpField(header,name,value); + field = new HttpField.IntValueHttpField(header, name, value); else - field = new HttpField(header,name,value); + field = new HttpField(header, name, value); break; case C_AUTHORITY: @@ -225,11 +246,11 @@ public class HpackDecoder if ("0".equals(value)) field = CONTENT_LENGTH_0; else - field = new HttpField.LongValueHttpField(header,name,value); + field = new HttpField.LongValueHttpField(header, name, value); break; default: - field = new HttpField(header,name,value); + field = new HttpField(header, name, value); break; } } @@ -237,10 +258,10 @@ public class HpackDecoder if (LOG.isDebugEnabled()) { LOG.debug("decoded '{}' by {}/{}/{}", - field, - name_index > 0 ? "IdxName" : (huffmanName ? "HuffName" : "LitName"), - huffmanValue ? "HuffVal" : "LitVal", - indexed ? "Idx" : ""); + field, + nameIndex > 0 ? "IdxName" : (huffmanName ? "HuffName" : "LitName"), + huffmanValue ? "HuffVal" : "LitVal", + indexed ? "Idx" : ""); } // emit the field @@ -256,22 +277,24 @@ public class HpackDecoder return _builder.build(); } - public static String toASCIIString(ByteBuffer buffer,int length) + public static String toASCIIString(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 __DO_NOT_HUFFMAN = - EnumSet.of( - HttpHeader.AUTHORIZATION, - HttpHeader.CONTENT_MD5, - HttpHeader.PROXY_AUTHENTICATE, - HttpHeader.PROXY_AUTHORIZATION); - final static EnumSet __DO_NOT_INDEX = - EnumSet.of( - // HttpHeader.C_PATH, // TODO more data needed - // HttpHeader.DATE, // TODO more data needed - HttpHeader.AUTHORIZATION, - HttpHeader.CONTENT_MD5, - HttpHeader.CONTENT_RANGE, - HttpHeader.ETAG, - HttpHeader.IF_MODIFIED_SINCE, - HttpHeader.IF_UNMODIFIED_SINCE, - HttpHeader.IF_NONE_MATCH, - HttpHeader.IF_RANGE, - HttpHeader.IF_MATCH, - HttpHeader.LOCATION, - HttpHeader.RANGE, - HttpHeader.RETRY_AFTER, - // HttpHeader.EXPIRES, - HttpHeader.LAST_MODIFIED, - HttpHeader.SET_COOKIE, - HttpHeader.SET_COOKIE2); - final static EnumSet __NEVER_INDEX = - EnumSet.of( - HttpHeader.AUTHORIZATION, - HttpHeader.SET_COOKIE, - HttpHeader.SET_COOKIE2); + private static final HttpField[] __status = new HttpField[599]; + static final EnumSet __DO_NOT_HUFFMAN = + EnumSet.of( + HttpHeader.AUTHORIZATION, + HttpHeader.CONTENT_MD5, + HttpHeader.PROXY_AUTHENTICATE, + HttpHeader.PROXY_AUTHORIZATION); + static final EnumSet __DO_NOT_INDEX = + EnumSet.of( + // HttpHeader.C_PATH, // TODO more data needed + // HttpHeader.DATE, // TODO more data needed + HttpHeader.AUTHORIZATION, + HttpHeader.CONTENT_MD5, + HttpHeader.CONTENT_RANGE, + HttpHeader.ETAG, + HttpHeader.IF_MODIFIED_SINCE, + HttpHeader.IF_UNMODIFIED_SINCE, + HttpHeader.IF_NONE_MATCH, + HttpHeader.IF_RANGE, + HttpHeader.IF_MATCH, + HttpHeader.LOCATION, + HttpHeader.RANGE, + HttpHeader.RETRY_AFTER, + // HttpHeader.EXPIRES, + HttpHeader.LAST_MODIFIED, + HttpHeader.SET_COOKIE, + HttpHeader.SET_COOKIE2); + static final EnumSet __NEVER_INDEX = + EnumSet.of( + HttpHeader.AUTHORIZATION, + HttpHeader.SET_COOKIE, + HttpHeader.SET_COOKIE2); private static final PreEncodedHttpField CONNECTION_TE = new PreEncodedHttpField(HttpHeader.CONNECTION, "te"); private static final PreEncodedHttpField TE_TRAILERS = new PreEncodedHttpField(HttpHeader.TE, "trailers"); private static final Trie specialHopHeaders = new ArrayTrie<>(6); @@ -84,7 +83,9 @@ public class HpackEncoder static { for (HttpStatus.Code code : HttpStatus.Code.values()) - __status[code.getCode()]=new PreEncodedHttpField(HttpHeader.C_STATUS,Integer.toString(code.getCode())); + { + __status[code.getCode()] = new PreEncodedHttpField(HttpHeader.C_STATUS, Integer.toString(code.getCode())); + } specialHopHeaders.put("close", true); specialHopHeaders.put("te", true); } @@ -98,26 +99,26 @@ public class HpackEncoder public HpackEncoder() { - this(4096,4096,-1); + this(4096, 4096, -1); } public HpackEncoder(int localMaxDynamicTableSize) { - this(localMaxDynamicTableSize,4096,-1); + this(localMaxDynamicTableSize, 4096, -1); } - - public HpackEncoder(int localMaxDynamicTableSize,int remoteMaxDynamicTableSize) + + public HpackEncoder(int localMaxDynamicTableSize, int remoteMaxDynamicTableSize) { - this(localMaxDynamicTableSize,remoteMaxDynamicTableSize,-1); + this(localMaxDynamicTableSize, remoteMaxDynamicTableSize, -1); } - - public HpackEncoder(int localMaxDynamicTableSize,int remoteMaxDynamicTableSize, int maxHeaderListSize) + + public HpackEncoder(int localMaxDynamicTableSize, int remoteMaxDynamicTableSize, int maxHeaderListSize) { - _context=new HpackContext(remoteMaxDynamicTableSize); - _remoteMaxDynamicTableSize=remoteMaxDynamicTableSize; - _localMaxDynamicTableSize=localMaxDynamicTableSize; - _maxHeaderListSize=maxHeaderListSize; - _debug=LOG.isDebugEnabled(); + _context = new HpackContext(remoteMaxDynamicTableSize); + _remoteMaxDynamicTableSize = remoteMaxDynamicTableSize; + _localMaxDynamicTableSize = localMaxDynamicTableSize; + _maxHeaderListSize = maxHeaderListSize; + _debug = LOG.isDebugEnabled(); } public int getMaxHeaderListSize() @@ -137,26 +138,26 @@ public class HpackEncoder public void setRemoteMaxDynamicTableSize(int remoteMaxDynamicTableSize) { - _remoteMaxDynamicTableSize=remoteMaxDynamicTableSize; + _remoteMaxDynamicTableSize = remoteMaxDynamicTableSize; } public void setLocalMaxDynamicTableSize(int localMaxDynamicTableSize) { - _localMaxDynamicTableSize=localMaxDynamicTableSize; + _localMaxDynamicTableSize = localMaxDynamicTableSize; } public void encode(ByteBuffer buffer, MetaData metadata) { if (LOG.isDebugEnabled()) - LOG.debug(String.format("CtxTbl[%x] encoding",_context.hashCode())); + LOG.debug(String.format("CtxTbl[%x] encoding", _context.hashCode())); - _headerListSize=0; + _headerListSize = 0; int pos = buffer.position(); // Check the dynamic table sizes! - int maxDynamicTableSize=Math.min(_remoteMaxDynamicTableSize,_localMaxDynamicTableSize); - if (maxDynamicTableSize!=_context.getMaxDynamicTableSize()) - encodeMaxDynamicTableSize(buffer,maxDynamicTableSize); + int maxDynamicTableSize = Math.min(_remoteMaxDynamicTableSize, _localMaxDynamicTableSize); + if (maxDynamicTableSize != _context.getMaxDynamicTableSize()) + encodeMaxDynamicTableSize(buffer, maxDynamicTableSize); // Add Request/response meta fields if (metadata.isRequest()) @@ -164,20 +165,20 @@ public class HpackEncoder MetaData.Request request = (MetaData.Request)metadata; // TODO optimise these to avoid HttpField creation - String scheme=request.getURI().getScheme(); - encode(buffer,new HttpField(HttpHeader.C_SCHEME,scheme==null?HttpScheme.HTTP.asString():scheme)); - encode(buffer,new HttpField(HttpHeader.C_METHOD,request.getMethod())); - encode(buffer,new HttpField(HttpHeader.C_AUTHORITY,request.getURI().getAuthority())); - encode(buffer,new HttpField(HttpHeader.C_PATH,request.getURI().getPathQuery())); + String scheme = request.getURI().getScheme(); + encode(buffer, new HttpField(HttpHeader.C_SCHEME, scheme == null ? HttpScheme.HTTP.asString() : scheme)); + encode(buffer, new HttpField(HttpHeader.C_METHOD, request.getMethod())); + encode(buffer, new HttpField(HttpHeader.C_AUTHORITY, request.getURI().getAuthority())); + encode(buffer, new HttpField(HttpHeader.C_PATH, request.getURI().getPathQuery())); } else if (metadata.isResponse()) { MetaData.Response response = (MetaData.Response)metadata; - int code=response.getStatus(); - HttpField status = code<__status.length?__status[code]:null; - if (status==null) - status=new HttpField.IntValueHttpField(HttpHeader.C_STATUS,code); - encode(buffer,status); + int code = response.getStatus(); + HttpField status = code < __status.length ? __status[code] : null; + if (status == null) + status = new HttpField.IntValueHttpField(HttpHeader.C_STATUS, code); + encode(buffer, status); } // Add all non-connection fields. @@ -185,9 +186,9 @@ public class HpackEncoder if (fields != null) { Set hopHeaders = fields.getCSV(HttpHeader.CONNECTION, false).stream() - .filter(v -> specialHopHeaders.get(v) == Boolean.TRUE) - .map(StringUtil::asciiToLowerCase) - .collect(Collectors.toSet()); + .filter(v -> specialHopHeaders.get(v) == Boolean.TRUE) + .map(StringUtil::asciiToLowerCase) + .collect(Collectors.toSet()); for (HttpField field : fields) { if (field.getHeader() == HttpHeader.CONNECTION) @@ -201,61 +202,61 @@ public class HpackEncoder encode(buffer, CONNECTION_TE); encode(buffer, TE_TRAILERS); } - encode(buffer,field); + encode(buffer, field); } } // Check size - if (_maxHeaderListSize>0 && _headerListSize>_maxHeaderListSize) + if (_maxHeaderListSize > 0 && _headerListSize > _maxHeaderListSize) { - LOG.warn("Header list size too large {} > {} for {}",_headerListSize,_maxHeaderListSize); + LOG.warn("Header list size too large {} > {} for {}", _headerListSize, _maxHeaderListSize); if (LOG.isDebugEnabled()) - LOG.debug("metadata={}",metadata); + LOG.debug("metadata={}", metadata); } - + if (LOG.isDebugEnabled()) - LOG.debug(String.format("CtxTbl[%x] encoded %d octets",_context.hashCode(), buffer.position() - pos)); + LOG.debug(String.format("CtxTbl[%x] encoded %d octets", _context.hashCode(), buffer.position() - pos)); } public void encodeMaxDynamicTableSize(ByteBuffer buffer, int maxDynamicTableSize) { - if (maxDynamicTableSize>_remoteMaxDynamicTableSize) + if (maxDynamicTableSize > _remoteMaxDynamicTableSize) throw new IllegalArgumentException(); buffer.put((byte)0x20); - NBitInteger.encode(buffer,5,maxDynamicTableSize); + NBitInteger.encode(buffer, 5, maxDynamicTableSize); _context.resize(maxDynamicTableSize); } public void encode(ByteBuffer buffer, HttpField field) { - if (field.getValue()==null) - field = new HttpField(field.getHeader(),field.getName(),""); - - int field_size = field.getName().length() + field.getValue().length(); - _headerListSize+=field_size+32; - - final int p=_debug?buffer.position():-1; + if (field.getValue() == null) + field = new HttpField(field.getHeader(), field.getName(), ""); - String encoding=null; + int fieldSize = field.getName().length() + field.getValue().length(); + _headerListSize += fieldSize + 32; + + final int p = _debug ? buffer.position() : -1; + + String encoding = null; // Is there an entry for the field? Entry entry = _context.get(field); - if (entry!=null) + if (entry != null) { // Known field entry, so encode it as indexed if (entry.isStatic()) { buffer.put(((StaticEntry)entry).getEncodedField()); if (_debug) - encoding="IdxFieldS1"; + encoding = "IdxFieldS1"; } else { - int index=_context.index(entry); + int index = _context.index(entry); buffer.put((byte)0x80); - NBitInteger.encode(buffer,7,index); + NBitInteger.encode(buffer, 7, index); if (_debug) - encoding="IdxField"+(entry.isStatic()?"S":"")+(1+NBitInteger.octectsNeeded(7,index)); + encoding = "IdxField" + (entry.isStatic() ? "S" : "") + (1 + NBitInteger.octectsNeeded(7, index)); } } else @@ -267,41 +268,41 @@ public class HpackEncoder HttpHeader header = field.getHeader(); // Select encoding strategy - if (header==null) + if (header == null) { // Select encoding strategy for unknown header names Entry name = _context.get(field.getName()); if (field instanceof PreEncodedHttpField) { - int i=buffer.position(); - ((PreEncodedHttpField)field).putTo(buffer,HttpVersion.HTTP_2); - byte b=buffer.get(i); - indexed=b<0||b>=0x40; + int i = buffer.position(); + ((PreEncodedHttpField)field).putTo(buffer, HttpVersion.HTTP_2); + byte b = buffer.get(i); + indexed = b < 0 || b >= 0x40; if (_debug) - encoding=indexed?"PreEncodedIdx":"PreEncoded"; + encoding = indexed ? "PreEncodedIdx" : "PreEncoded"; } // has the custom header name been seen before? - else if (name==null) + else if (name == null) { // unknown name and value, so let's index this just in case it is // the first time we have seen a custom name or a custom field. // unless the name is changing, this is worthwhile - indexed=true; - encodeName(buffer,(byte)0x40,6,field.getName(),null); - encodeValue(buffer,true,field.getValue()); + indexed = true; + encodeName(buffer, (byte)0x40, 6, field.getName(), null); + encodeValue(buffer, true, field.getValue()); if (_debug) - encoding="LitHuffNHuffVIdx"; + encoding = "LitHuffNHuffVIdx"; } else { // known custom name, but unknown value. // This is probably a custom field with changing value, so don't index. - indexed=false; - encodeName(buffer,(byte)0x00,4,field.getName(),null); - encodeValue(buffer,true,field.getValue()); + indexed = false; + encodeName(buffer, (byte)0x00, 4, field.getName(), null); + encodeValue(buffer, true, field.getValue()); if (_debug) - encoding="LitHuffNHuffV!Idx"; + encoding = "LitHuffNHuffV!Idx"; } } else @@ -312,47 +313,47 @@ public class HpackEncoder if (field instanceof PreEncodedHttpField) { // Preencoded field - int i=buffer.position(); - ((PreEncodedHttpField)field).putTo(buffer,HttpVersion.HTTP_2); - byte b=buffer.get(i); - indexed=b<0||b>=0x40; + int i = buffer.position(); + ((PreEncodedHttpField)field).putTo(buffer, HttpVersion.HTTP_2); + byte b = buffer.get(i); + indexed = b < 0 || b >= 0x40; if (_debug) - encoding=indexed?"PreEncodedIdx":"PreEncoded"; + encoding = indexed ? "PreEncodedIdx" : "PreEncoded"; } else if (__DO_NOT_INDEX.contains(header)) { // Non indexed field - indexed=false; - boolean never_index=__NEVER_INDEX.contains(header); - boolean huffman=!__DO_NOT_HUFFMAN.contains(header); - encodeName(buffer,never_index?(byte)0x10:(byte)0x00,4,header.asString(),name); - encodeValue(buffer,huffman,field.getValue()); + indexed = false; + boolean neverIndex = __NEVER_INDEX.contains(header); + boolean huffman = !__DO_NOT_HUFFMAN.contains(header); + encodeName(buffer, neverIndex ? (byte)0x10 : (byte)0x00, 4, header.asString(), name); + encodeValue(buffer, huffman, field.getValue()); if (_debug) - encoding="Lit"+ - ((name==null)?"HuffN":("IdxN"+(name.isStatic()?"S":"")+(1+NBitInteger.octectsNeeded(4,_context.index(name)))))+ - (huffman?"HuffV":"LitV")+ - (never_index?"!!Idx":"!Idx"); + encoding = "Lit" + + ((name == null) ? "HuffN" : ("IdxN" + (name.isStatic() ? "S" : "") + (1 + NBitInteger.octectsNeeded(4, _context.index(name))))) + + (huffman ? "HuffV" : "LitV") + + (neverIndex ? "!!Idx" : "!Idx"); } - else if (field_size>=_context.getMaxDynamicTableSize() || header==HttpHeader.CONTENT_LENGTH && field.getValue().length()>2) + else if (fieldSize >= _context.getMaxDynamicTableSize() || header == HttpHeader.CONTENT_LENGTH && field.getValue().length() > 2) { // Non indexed if field too large or a content length for 3 digits or more - indexed=false; - encodeName(buffer,(byte)0x00,4,header.asString(),name); - encodeValue(buffer,true,field.getValue()); + indexed = false; + encodeName(buffer, (byte)0x00, 4, header.asString(), name); + encodeValue(buffer, true, field.getValue()); if (_debug) - encoding="LitIdxNS"+(1+NBitInteger.octectsNeeded(4,_context.index(name)))+"HuffV!Idx"; + encoding = "LitIdxNS" + (1 + NBitInteger.octectsNeeded(4, _context.index(name))) + "HuffV!Idx"; } else { // indexed - indexed=true; - boolean huffman=!__DO_NOT_HUFFMAN.contains(header); - encodeName(buffer,(byte)0x40,6,header.asString(),name); - encodeValue(buffer,huffman,field.getValue()); + indexed = true; + boolean huffman = !__DO_NOT_HUFFMAN.contains(header); + 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)))))+ - (huffman?"HuffVIdx":"LitVIdx"); + encoding = ((name == null) ? "LitHuffN" : ("LitIdxN" + (name.isStatic() ? "S" : "") + (1 + NBitInteger.octectsNeeded(6, _context.index(name))))) + + (huffman ? "HuffVIdx" : "LitVIdx"); } } @@ -363,26 +364,26 @@ public class HpackEncoder if (_debug) { - int e=buffer.position(); + int e = buffer.position(); if (LOG.isDebugEnabled()) - LOG.debug("encode {}:'{}' to '{}'",encoding,field,TypeUtil.toHexString(buffer.array(),buffer.arrayOffset()+p,e-p)); + LOG.debug("encode {}:'{}' to '{}'", encoding, field, TypeUtil.toHexString(buffer.array(), buffer.arrayOffset() + p, e - p)); } } private void encodeName(ByteBuffer buffer, byte mask, int bits, String name, Entry entry) { buffer.put(mask); - if (entry==null) + if (entry == null) { // 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); + NBitInteger.encode(buffer, 7, Huffman.octetsNeededLC(name)); + Huffman.encodeLC(buffer, name); } else { - NBitInteger.encode(buffer,bits,_context.index(entry)); + NBitInteger.encode(buffer, bits, _context.index(entry)); } } @@ -411,11 +412,11 @@ public class HpackEncoder { // add literal assuming iso_8859_1 buffer.put((byte)0x00).mark(); - NBitInteger.encode(buffer,7,value.length()); - for (int i=0;i127) + char c = value.charAt(i); + if (c < ' ' || c > 127) { // Not iso_8859_1, so re-encode remaining as UTF-8 buffer.reset(); diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackException.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackException.java index 78516c73bd2..0a3e254b514 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackException.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackException.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,7 +18,6 @@ package org.eclipse.jetty.http2.hpack; - @SuppressWarnings("serial") public abstract class HpackException extends Exception { @@ -26,19 +25,19 @@ public abstract class HpackException extends Exception { super(String.format(messageFormat, args)); } - + /** * A Stream HPACK exception. - *

        Stream exceptions are not fatal to the connection and the + *

        Stream exceptions are not fatal to the connection and the * hpack state is complete and able to continue handling other - * decoding/encoding for the session. + * decoding/encoding for the session. *

        */ public static class StreamException extends HpackException { StreamException(String messageFormat, Object... args) { - super(messageFormat,args); + super(messageFormat, args); } } @@ -51,7 +50,7 @@ public abstract class HpackException extends Exception { SessionException(String messageFormat, Object... args) { - super(messageFormat,args); + super(messageFormat, args); } } @@ -59,7 +58,7 @@ public abstract class HpackException extends Exception { public CompressionException(String messageFormat, Object... args) { - super(messageFormat,args); + super(messageFormat, args); } } } diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackFieldPreEncoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackFieldPreEncoder.java index 140483e92d8..2b3d30dc345 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackFieldPreEncoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackFieldPreEncoder.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,7 +16,6 @@ // ======================================================================== // - package org.eclipse.jetty.http2.hpack; import java.nio.ByteBuffer; @@ -26,13 +25,12 @@ import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.util.BufferUtil; - -/* ------------------------------------------------------------ */ /** + * */ public class HpackFieldPreEncoder implements HttpFieldPreEncoder { - /* ------------------------------------------------------------ */ + /** * @see org.eclipse.jetty.http.HttpFieldPreEncoder#getHttpVersion() */ @@ -42,56 +40,55 @@ public class HpackFieldPreEncoder implements HttpFieldPreEncoder 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) { - boolean not_indexed=HpackEncoder.__DO_NOT_INDEX.contains(header); - - ByteBuffer buffer = BufferUtil.allocate(name.length()+value.length()+10); + boolean notIndexed = HpackEncoder.__DO_NOT_INDEX.contains(header); + + ByteBuffer buffer = BufferUtil.allocate(name.length() + value.length() + 10); BufferUtil.clearToFill(buffer); boolean huffman; int bits; - - if (not_indexed) + + if (notIndexed) { // Non indexed field - boolean never_index=HpackEncoder.__NEVER_INDEX.contains(header); - huffman=!HpackEncoder.__DO_NOT_HUFFMAN.contains(header); - buffer.put(never_index?(byte)0x10:(byte)0x00); - bits=4; + boolean neverIndex = HpackEncoder.__NEVER_INDEX.contains(header); + huffman = !HpackEncoder.__DO_NOT_HUFFMAN.contains(header); + buffer.put(neverIndex ? (byte)0x10 : (byte)0x00); + bits = 4; } - else if (header==HttpHeader.CONTENT_LENGTH && value.length()>1) + else if (header == HttpHeader.CONTENT_LENGTH && value.length() > 1) { // Non indexed content length for 2 digits or more buffer.put((byte)0x00); - huffman=true; - bits=4; + huffman = true; + bits = 4; } else { // indexed buffer.put((byte)0x40); - huffman=!HpackEncoder.__DO_NOT_HUFFMAN.contains(header); - bits=6; + huffman = !HpackEncoder.__DO_NOT_HUFFMAN.contains(header); + bits = 6; } - - int name_idx=HpackContext.staticIndex(header); - if (name_idx>0) - NBitInteger.encode(buffer,bits,name_idx); + + int nameIdx = HpackContext.staticIndex(header); + if (nameIdx > 0) + NBitInteger.encode(buffer, bits, nameIdx); else { buffer.put((byte)0x80); - NBitInteger.encode(buffer,7,Huffman.octetsNeededLC(name)); - Huffman.encodeLC(buffer,name); + NBitInteger.encode(buffer, 7, Huffman.octetsNeededLC(name)); + Huffman.encodeLC(buffer, name); } - HpackEncoder.encodeValue(buffer,huffman,value); - - BufferUtil.flipToFlush(buffer,0); + HpackEncoder.encodeValue(buffer, huffman, value); + + BufferUtil.flipToFlush(buffer, 0); return BufferUtil.toArray(buffer); } } diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/Huffman.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/Huffman.java index f2d5309ec44..0bb3e584ee4 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/Huffman.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/Huffman.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -28,269 +28,269 @@ 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}, - }; + { + /* ( 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; @@ -298,94 +298,93 @@ public class Huffman static final byte[] rowbits; // Build the Huffman lookup tree and LC TABLE - static + 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 8) + while (len > 8) { len -= 8; int i = ((code >>> len) & 0xFF); - int t=current*256+i; + int t = current * 256 + i; current = tree[t]; if (current == 0) { tree[t] = (char)++r; - current=r; + current = r; } } int terminal = ++r; - rowsym[r]=(char)sym; + rowsym[r] = (char)sym; int b = len & 0x07; - int terminalBits = b == 0?8:b; + int terminalBits = b == 0 ? 8 : b; - rowbits[r]=(byte)terminalBits; + rowbits[r] = (byte)terminalBits; int shift = 8 - len; - int start = current*256 + ((code << shift) & 0xFF); - int end = start + (1<= 8) + while (bits >= 8) { int c = (current >>> (bits - 8)) & 0xFF; - node = tree[node*256+c]; - if (rowbits[node]!=0) + node = tree[node * 256 + c]; + if (rowbits[node] != 0) { - if(rowsym[node] == EOS) + 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 + } + else { // non-terminal node bits -= 8; @@ -393,19 +392,21 @@ public class Huffman } } - while (bits > 0) + while (bits > 0) { int c = (current << (8 - bits)) & 0xFF; int lastNode = node; - node = tree[node*256+c]; + node = tree[node * 256 + c]; - if (rowbits[node]==0 || rowbits[node] > bits) + if (rowbits[node] == 0 || rowbits[node] > bits) { int requiredPadding = 0; - for(int i=0; i>(8-bits)) != requiredPadding) + if ((c >> (8 - bits)) != requiredPadding) throw new HpackException.CompressionException("Incorrect padding"); node = lastNode; @@ -417,27 +418,27 @@ public class Huffman node = 0; } - if(node != 0) + if (node != 0) throw new HpackException.CompressionException("Bad termination"); return utf8.toString(); } public static int octetsNeeded(String s) - { - return octetsNeeded(CODES,s); + { + return octetsNeeded(CODES, s); } - + public static int octetsNeeded(byte[] b) { return octetsNeeded(CODES,b); } - public static void encode(ByteBuffer buffer,String s) + public static void encode(ByteBuffer buffer, String s) { - encode(CODES,buffer,s); + encode(CODES, buffer, s); } - + public static void encode(ByteBuffer buffer,byte[] b) { encode(CODES,buffer,b); @@ -445,27 +446,27 @@ public class Huffman public static int octetsNeededLC(String s) { - return octetsNeeded(LCCODES,s); + return octetsNeeded(LCCODES, s); } public static void encodeLC(ByteBuffer buffer, String s) { - encode(LCCODES,buffer,s); + encode(LCCODES, buffer, s); } - - private static int octetsNeeded(final int[][] table,String s) - { - int needed=0; + + private static int octetsNeeded(final int[][] table, String s) + { + int needed = 0; int len = s.length(); - for (int i=0;i=128 || c<' ') + char c = s.charAt(i); + if (c >= 128 || c < ' ') throw new IllegalArgumentException(); needed += table[c][1]; } - return (needed+7) / 8; + return (needed + 7) / 8; } private static int octetsNeeded(final int[][] table,byte[] b) @@ -480,19 +481,15 @@ public class Huffman return (needed+7) / 8; } - private static void encode(final int[][] table,ByteBuffer buffer,String s) + private static void encode(final int[][] table, ByteBuffer buffer, String s) { long current = 0; int n = 0; - - byte[] array = buffer.array(); - int p=buffer.arrayOffset()+buffer.position(); - int len = s.length(); - for (int i=0;i=128 || c<' ') + char c = s.charAt(i); + if (c >= 128 || c < ' ') throw new IllegalArgumentException(); int code = table[c][0]; int bits = table[c][1]; @@ -501,23 +498,20 @@ public class Huffman current |= code; n += bits; - while (n >= 8) + while (n >= 8) { n -= 8; - array[p++]=(byte)(current >> n); + buffer.put((byte)(current >> n)); } } - if (n > 0) + if (n > 0) { - current <<= (8 - n); - current |= (0xFF >>> n); - array[p++]=(byte)current; + current <<= (8 - n); + current |= (0xFF >>> n); + buffer.put((byte)(current)); } - - buffer.position(p-buffer.arrayOffset()); } - private static void encode(final int[][] table,ByteBuffer buffer,byte[] b) { long current = 0; diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java index d891ab3dfe5..ce1f8b36cbe 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,10 +16,8 @@ // ======================================================================== // - package org.eclipse.jetty.http2.hpack; - import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; @@ -33,13 +31,13 @@ public class MetaDataBuilder { private final int _maxSize; private int _size; - private int _status=-1; + private Integer _status; private String _method; private HttpScheme _scheme; private HostPortHttpField _authority; private String _path; - private long _contentLength=Long.MIN_VALUE; - private HttpFields _fields = new HttpFields(10); + private long _contentLength = Long.MIN_VALUE; + private HttpFields _fields = new HttpFields(); private HpackException.StreamException _streamException; private boolean _request; private boolean _response; @@ -47,12 +45,14 @@ public class MetaDataBuilder /** * @param maxHeadersSize The maximum size of the headers, expressed as total name and value characters. */ - MetaDataBuilder(int maxHeadersSize) + protected MetaDataBuilder(int maxHeadersSize) { - _maxSize=maxHeadersSize; + _maxSize = maxHeadersSize; } - /** Get the maxSize. + /** + * Get the maxSize. + * * @return the maxSize */ public int getMaxSize() @@ -60,7 +60,9 @@ public class MetaDataBuilder return _maxSize; } - /** Get the size. + /** + * Get the size. + * * @return the current size in bytes */ public int getSize() @@ -72,31 +74,33 @@ public class MetaDataBuilder { HttpHeader header = field.getHeader(); String name = field.getName(); + if (name == null || name.length() == 0) + throw new HpackException.SessionException("Header size 0"); String value = field.getValue(); - int field_size = name.length() + (value == null ? 0 : value.length()); - _size+=field_size+32; - if (_size>_maxSize) - throw new HpackException.SessionException("Header Size %d > %d",_size,_maxSize); + 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); if (field instanceof StaticTableHttpField) { StaticTableHttpField staticField = (StaticTableHttpField)field; - switch(header) + switch (header) { case C_STATUS: - if(checkHeader(header, _status)) + if (checkPseudoHeader(header, _status)) _status = (Integer)staticField.getStaticValue(); _response = true; break; case C_METHOD: - if(checkPseudoHeader(header, _method)) + if (checkPseudoHeader(header, _method)) _method = value; _request = true; break; case C_SCHEME: - if(checkPseudoHeader(header, _scheme)) + if (checkPseudoHeader(header, _scheme)) _scheme = (HttpScheme)staticField.getStaticValue(); _request = true; break; @@ -105,30 +109,30 @@ public class MetaDataBuilder throw new IllegalArgumentException(name); } } - else if (header!=null) + else if (header != null) { - switch(header) + switch (header) { case C_STATUS: - if(checkHeader(header, _status)) + if (checkPseudoHeader(header, _status)) _status = field.getIntValue(); _response = true; break; case C_METHOD: - if(checkPseudoHeader(header, _method)) - _method = value; + if (checkPseudoHeader(header, _method)) + _method = value; _request = true; break; case C_SCHEME: - if(checkPseudoHeader(header, _scheme) && value != null) + if (checkPseudoHeader(header, _scheme) && value != null) _scheme = HttpScheme.CACHE.get(value); _request = true; break; case C_AUTHORITY: - if(checkPseudoHeader(header, _authority)) + if (checkPseudoHeader(header, _authority)) { if (field instanceof HostPortHttpField) _authority = (HostPortHttpField)field; @@ -140,7 +144,7 @@ public class MetaDataBuilder case HOST: // :authority fields must come first. If we have one, ignore the host header as far as authority goes. - if (_authority==null) + if (_authority == null) { if (field instanceof HostPortHttpField) _authority = (HostPortHttpField)field; @@ -151,9 +155,9 @@ public class MetaDataBuilder break; case C_PATH: - if(checkPseudoHeader(header, _path)) + if (checkPseudoHeader(header, _path)) { - if (value!=null && value.length()>0) + if (value != null && value.length() > 0) _path = value; else streamException("No Path"); @@ -165,23 +169,23 @@ public class MetaDataBuilder _contentLength = field.getLongValue(); _fields.add(field); break; - + case TE: if ("trailers".equalsIgnoreCase(value)) _fields.add(field); else streamException("Unsupported TE value '%s'", value); break; - + case CONNECTION: if ("TE".equalsIgnoreCase(value)) _fields.add(field); else streamException("Connection specific field '%s'", header); - break; + break; - default: - if (name.charAt(0)==':') + default: + if (name.charAt(0) == ':') streamException("Unknown pseudo header '%s'", name); else _fields.add(field); @@ -190,43 +194,30 @@ public class MetaDataBuilder } else { - if (name.charAt(0)==':') - streamException("Unknown pseudo header '%s'",name); + if (name.charAt(0) == ':') + streamException("Unknown pseudo header '%s'", name); else _fields.add(field); } } - void streamException(String messageFormat, Object... args) + protected void streamException(String messageFormat, Object... args) { HpackException.StreamException stream = new HpackException.StreamException(messageFormat, args); - if (_streamException==null) + if (_streamException == null) _streamException = stream; else _streamException.addSuppressed(stream); } - private boolean checkHeader(HttpHeader header, int value) + protected boolean checkPseudoHeader(HttpHeader header, Object value) { - if (_fields.size()>0) + if (_fields.size() > 0) { streamException("Pseudo header %s after fields", header.asString()); return false; } - if (value==-1) - return true; - streamException("Duplicate pseudo header %s", header.asString()); - return false; - } - - private boolean checkPseudoHeader(HttpHeader header, Object value) - { - if (_fields.size()>0) - { - streamException("Pseudo header %s after fields", header.asString()); - return false; - } - if (value==null) + if (value == null) return true; streamException("Duplicate pseudo header %s", header.asString()); return false; @@ -234,51 +225,55 @@ public class MetaDataBuilder public MetaData build() throws HpackException.StreamException { - if (_streamException!=null) + if (_streamException != null) { _streamException.addSuppressed(new Throwable()); throw _streamException; } - + if (_request && _response) throw new HpackException.StreamException("Request and Response headers"); - HttpFields fields = _fields; try { if (_request) { - if (_method==null) + if (_method == null) throw new HpackException.StreamException("No Method"); - if (_scheme==null) + if (_scheme == null) throw new HpackException.StreamException("No Scheme"); - if (_path==null) + if (_path == null) throw new HpackException.StreamException("No Path"); - return new MetaData.Request(_method,_scheme,_authority,_path,HttpVersion.HTTP_2,fields,_contentLength); + return new MetaData.Request(_method, _scheme, _authority, _path, HttpVersion.HTTP_2, fields, _contentLength); } if (_response) - return new MetaData.Response(HttpVersion.HTTP_2,_status,fields,_contentLength); - - return new MetaData(HttpVersion.HTTP_2,fields,_contentLength); + { + if (_status == null) + throw new HpackException.StreamException("No Status"); + return new MetaData.Response(HttpVersion.HTTP_2, _status, fields, _contentLength); + } + + return new MetaData(HttpVersion.HTTP_2, fields, _contentLength); } finally { - _fields = new HttpFields(Math.max(10,fields.size()+5)); - _request=false; - _response=false; - _status=-1; - _method=null; - _scheme=null; - _authority=null; - _path=null; - _size=0; - _contentLength=Long.MIN_VALUE; + _fields = new HttpFields(Math.max(16, fields.size() + 5)); + _request = false; + _response = false; + _status = null; + _method = null; + _scheme = null; + _authority = null; + _path = null; + _size = 0; + _contentLength = Long.MIN_VALUE; } } /** * 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 @@ -287,8 +282,8 @@ public class MetaDataBuilder { // 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); + length = (length * 4) / 3; + if ((_size + length) > _maxSize) + throw new HpackException.SessionException("Header too large %d > %d", _size + length, _maxSize); } } diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/NBitInteger.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/NBitInteger.java index 489b292b261..7d700cd4338 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/NBitInteger.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/NBitInteger.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -22,35 +22,35 @@ import java.nio.ByteBuffer; public class NBitInteger { - public static int octectsNeeded(int n,int i) + public static int octectsNeeded(int n, int i) { - if (n==8) + if (n == 8) { int nbits = 0xFF; - i=i-nbits; - if (i<0) + i = i - nbits; + if (i < 0) return 1; - if (i==0) + if (i == 0) return 2; - int lz=Integer.numberOfLeadingZeros(i); - int log=32-lz; - return 1+(log+6)/7; + 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) + i = i - nbits; + if (i < 0) return 0; - if (i==0) + if (i == 0) return 1; - int lz=Integer.numberOfLeadingZeros(i); - int log=32-lz; - return (log+6)/7; + 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 (n == 8) { if (i < 0xFF) { @@ -78,16 +78,16 @@ public class NBitInteger } else { - int p=buf.position()-1; + int p = buf.position() - 1; int bits = 0xFF >>> (8 - n); if (i < bits) { - buf.put(p,(byte)((buf.get(p)&~bits)|i)); + buf.put(p, (byte)((buf.get(p) & ~bits) | i)); } else { - buf.put(p,(byte)(buf.get(p)|bits)); + buf.put(p, (byte)(buf.get(p) | bits)); int length = i - bits; while (true) @@ -109,42 +109,42 @@ public class NBitInteger public static int decode(ByteBuffer buffer, int n) { - if (n==8) + if (n == 8) { int nbits = 0xFF; - int i=buffer.get()&0xff; - + int i = buffer.get() & 0xff; + if (i == nbits) - { - int m=1; + { + int m = 1; int b; do { - b = 0xff&buffer.get(); - i = i + (b&127) * m; - m = m*128; + b = 0xff & buffer.get(); + i = i + (b & 127) * m; + m = m * 128; } - while ((b&128) == 128); + while ((b & 128) == 128); } return i; } - + int nbits = 0xFF >>> (8 - n); - int i=buffer.get(buffer.position()-1)&nbits; - + int i = buffer.get(buffer.position() - 1) & nbits; + if (i == nbits) - { - int m=1; + { + int m = 1; int b; do { - b = 0xff&buffer.get(); - i = i + (b&127) * m; - m = m*128; + b = 0xff & buffer.get(); + i = i + (b & 127) * m; + m = m * 128; } - while ((b&128) == 128); + while ((b & 128) == 128); } return i; } diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/StaticTableHttpField.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/StaticTableHttpField.java index de093c99d31..56bd4bc4be6 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/StaticTableHttpField.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/StaticTableHttpField.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,46 +16,44 @@ // ======================================================================== // - package org.eclipse.jetty.http2.hpack; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpHeader; -/* ------------------------------------------------------------ */ public class StaticTableHttpField extends HttpField { private final Object _value; public StaticTableHttpField(HttpHeader header, String name, String valueString, Object value) { - super(header,name,valueString); - if (value==null) + super(header, name, valueString); + if (value == null) throw new IllegalArgumentException(); - _value=value; + _value = value; } - - public StaticTableHttpField(HttpHeader header,String valueString, Object value) + + public StaticTableHttpField(HttpHeader header, String valueString, Object value) { - this (header,header.asString(),valueString, value); + this(header, header.asString(), valueString, value); } - + public StaticTableHttpField(String name, String valueString, Object value) { - super(name,valueString); - if (value==null) + super(name, valueString); + if (value == null) throw new IllegalArgumentException(); - _value=value; + _value = value; } public Object getStaticValue() { return _value; } - + @Override public String toString() { - return super.toString()+"(evaluated)"; + return super.toString() + "(evaluated)"; } -} \ No newline at end of file +} diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java index 28db8f7a738..a24de7a396a 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,9 +16,14 @@ // ======================================================================== // - package org.eclipse.jetty.http2.hpack; +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.http2.hpack.HpackContext.Entry; +import org.hamcrest.Matchers; +import org.junit.jupiter.api.Test; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -27,17 +32,8 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; -import java.nio.ByteBuffer; - -import org.eclipse.jetty.http.HttpField; -import org.eclipse.jetty.http2.hpack.HpackContext.Entry; -import org.hamcrest.Matchers; - -import org.junit.jupiter.api.Test; - - -/* ------------------------------------------------------------ */ /** + * */ public class HpackContextTest { @@ -46,92 +42,94 @@ public class HpackContextTest public void testStaticName() { HpackContext ctx = new HpackContext(4096); - Entry entry=ctx.get(":method"); - assertEquals(":method",entry.getHttpField().getName()); + Entry entry = ctx.get(":method"); + assertEquals(":method", entry.getHttpField().getName()); assertTrue(entry.isStatic()); - assertThat(entry.toString(),Matchers.startsWith("{S,2,:method: ")); + assertThat(entry.toString(), Matchers.startsWith("{S,2,:method: ")); } - + @Test public void testEmptyAdd() { HpackContext ctx = new HpackContext(0); - HttpField field = new HttpField("foo","bar"); + HttpField field = new HttpField("foo", "bar"); assertNull(ctx.add(field)); } - + @Test public void testTooBigAdd() { HpackContext ctx = new HpackContext(37); - HttpField field = new HttpField("foo","bar"); + HttpField field = new HttpField("foo", "bar"); assertNull(ctx.add(field)); } - + @Test public void testJustRight() { HpackContext ctx = new HpackContext(38); - HttpField field = new HttpField("foo","bar"); - Entry entry=ctx.add(field); + HttpField field = new HttpField("foo", "bar"); + Entry entry = ctx.add(field); assertNotNull(entry); - assertThat(entry.toString(),Matchers.startsWith("{D,0,foo: bar,")); + assertThat(entry.toString(), Matchers.startsWith("{D,0,foo: bar,")); } - + @Test public void testEvictOne() { HpackContext ctx = new HpackContext(38); - HttpField field0 = new HttpField("foo","bar"); - - assertEquals(field0,ctx.add(field0).getHttpField()); - assertEquals(field0,ctx.get("foo").getHttpField()); - - HttpField field1 = new HttpField("xxx","yyy"); - assertEquals(field1,ctx.add(field1).getHttpField()); + HttpField field0 = new HttpField("foo", "bar"); + + assertEquals(field0, ctx.add(field0).getHttpField()); + assertEquals(field0, ctx.get("foo").getHttpField()); + + HttpField field1 = new HttpField("xxx", "yyy"); + assertEquals(field1, ctx.add(field1).getHttpField()); assertNull(ctx.get(field0)); assertNull(ctx.get("foo")); - assertEquals(field1,ctx.get(field1).getHttpField()); - assertEquals(field1,ctx.get("xxx").getHttpField()); - + assertEquals(field1, ctx.get(field1).getHttpField()); + assertEquals(field1, ctx.get("xxx").getHttpField()); } @Test public void testEvictNames() { - HpackContext ctx = new HpackContext(38*2); - HttpField[] field = - { - new HttpField("name","v0"), - new HttpField("name","v1"), - new HttpField("name","v2"), - new HttpField("name","v3"), - new HttpField("name","v4"), - new HttpField("name","v5"), - }; - + HpackContext ctx = new HpackContext(38 * 2); + HttpField[] field = + { + new HttpField("name", "v0"), + new HttpField("name", "v1"), + new HttpField("name", "v2"), + new HttpField("name", "v3"), + new HttpField("name", "v4"), + new HttpField("name", "v5"), + }; + Entry[] entry = new Entry[field.length]; - + // Add 2 name entries to fill table - for (int i=0;i<=1;i++) - entry[i]=ctx.add(field[i]); - + for (int i = 0; i <= 1; i++) + { + entry[i] = ctx.add(field[i]); + } + // check there is a name reference and it is the most recent added - assertEquals(entry[1],ctx.get("name")); + assertEquals(entry[1], ctx.get("name")); // Add 1 other entry to table and evict 1 - ctx.add(new HttpField("xxx","yyy")); - + ctx.add(new HttpField("xxx", "yyy")); + // check the name reference has been not been evicted - assertEquals(entry[1],ctx.get("name")); - + assertEquals(entry[1], ctx.get("name")); + // Add 1 other entry to table and evict 1 - ctx.add(new HttpField("foo","bar")); - + ctx.add(new HttpField("foo", "bar")); + // name is evicted assertNull(ctx.get("name")); } + @Test @SuppressWarnings("ReferenceEquality") public void testGetAddStatic() @@ -139,316 +137,317 @@ public class HpackContextTest HpackContext ctx = new HpackContext(4096); // Look for the field. Should find static version. - HttpField methodGet = new HttpField(":method","GET"); - assertEquals(methodGet,ctx.get(methodGet).getHttpField()); + HttpField methodGet = new HttpField(":method", "GET"); + assertEquals(methodGet, ctx.get(methodGet).getHttpField()); assertTrue(ctx.get(methodGet).isStatic()); - + // Add static version to dynamic table - Entry e0=ctx.add(ctx.get(methodGet).getHttpField()); - + Entry e0 = ctx.add(ctx.get(methodGet).getHttpField()); + // Look again and should see dynamic version - assertEquals(methodGet,ctx.get(methodGet).getHttpField()); - assertFalse(methodGet==ctx.get(methodGet).getHttpField()); + assertEquals(methodGet, ctx.get(methodGet).getHttpField()); + assertFalse(methodGet == ctx.get(methodGet).getHttpField()); assertFalse(ctx.get(methodGet).isStatic()); - + // Duplicates allows - Entry e1=ctx.add(ctx.get(methodGet).getHttpField()); - + Entry e1 = ctx.add(ctx.get(methodGet).getHttpField()); + // Look again and should see dynamic version - assertEquals(methodGet,ctx.get(methodGet).getHttpField()); - assertFalse(methodGet==ctx.get(methodGet).getHttpField()); + assertEquals(methodGet, ctx.get(methodGet).getHttpField()); + assertFalse(methodGet == ctx.get(methodGet).getHttpField()); assertFalse(ctx.get(methodGet).isStatic()); - assertFalse(e0==e1); + assertFalse(e0 == e1); } - + @Test public void testGetAddStaticName() { HpackContext ctx = new HpackContext(4096); - HttpField methodOther = new HttpField(":method","OTHER"); + HttpField methodOther = new HttpField(":method", "OTHER"); // Look for the field by name. Should find static version. - assertEquals(":method",ctx.get(":method").getHttpField().getName()); + assertEquals(":method", ctx.get(":method").getHttpField().getName()); assertTrue(ctx.get(":method").isStatic()); - + // Add dynamic entry with method ctx.add(methodOther); - + // Look for the field by name. Should find static version. - assertEquals(":method",ctx.get(":method").getHttpField().getName()); - assertTrue(ctx.get(":method").isStatic()); + assertEquals(":method", ctx.get(":method").getHttpField().getName()); + assertTrue(ctx.get(":method").isStatic()); } @Test public void testIndexes() { // Only enough space for 5 entries - HpackContext ctx = new HpackContext(38*5); - - HttpField methodPost = new HttpField(":method","POST"); - HttpField[] field = - { - new HttpField("fo0","b0r"), - new HttpField("fo1","b1r"), - new HttpField("fo2","b2r"), - new HttpField("fo3","b3r"), - new HttpField("fo4","b4r"), - new HttpField("fo5","b5r"), - new HttpField("fo6","b6r"), - new HttpField("fo7","b7r"), - new HttpField("fo8","b8r"), - new HttpField("fo9","b9r"), - new HttpField("foA","bAr"), - }; - + HpackContext ctx = new HpackContext(38 * 5); + + HttpField methodPost = new HttpField(":method", "POST"); + HttpField[] field = + { + new HttpField("fo0", "b0r"), + new HttpField("fo1", "b1r"), + new HttpField("fo2", "b2r"), + new HttpField("fo3", "b3r"), + new HttpField("fo4", "b4r"), + new HttpField("fo5", "b5r"), + new HttpField("fo6", "b6r"), + new HttpField("fo7", "b7r"), + new HttpField("fo8", "b8r"), + new HttpField("fo9", "b9r"), + new HttpField("foA", "bAr"), + }; + Entry[] entry = new Entry[100]; - + // Lookup the index of a static field - assertEquals(0,ctx.size()); - assertEquals(":authority",ctx.get(1).getHttpField().getName()); - assertEquals(3,ctx.index(ctx.get(methodPost))); - assertEquals(methodPost,ctx.get(3).getHttpField()); - assertEquals("www-authenticate",ctx.get(61).getHttpField().getName()); - assertEquals(null,ctx.get(62)); - + assertEquals(0, ctx.size()); + assertEquals(":authority", ctx.get(1).getHttpField().getName()); + assertEquals(3, ctx.index(ctx.get(methodPost))); + assertEquals(methodPost, ctx.get(3).getHttpField()); + assertEquals("www-authenticate", ctx.get(61).getHttpField().getName()); + assertEquals(null, ctx.get(62)); + // Add a single entry - entry[0]=ctx.add(field[0]); - + entry[0] = ctx.add(field[0]); + // Check new entry is 62 - assertEquals(1,ctx.size()); - assertEquals(62,ctx.index(entry[0])); - assertEquals(entry[0],ctx.get(62)); - + assertEquals(1, ctx.size()); + assertEquals(62, ctx.index(entry[0])); + assertEquals(entry[0], ctx.get(62)); + // and statics still OK - assertEquals(":authority",ctx.get(1).getHttpField().getName()); - assertEquals(3,ctx.index(ctx.get(methodPost))); - assertEquals(methodPost,ctx.get(3).getHttpField()); - assertEquals("www-authenticate",ctx.get(61).getHttpField().getName()); - assertEquals(null,ctx.get(62+ctx.size())); - + assertEquals(":authority", ctx.get(1).getHttpField().getName()); + assertEquals(3, ctx.index(ctx.get(methodPost))); + assertEquals(methodPost, ctx.get(3).getHttpField()); + assertEquals("www-authenticate", ctx.get(61).getHttpField().getName()); + assertEquals(null, ctx.get(62 + ctx.size())); // Add 4 more entries - for (int i=1;i<=4;i++) - entry[i]=ctx.add(field[i]); + for (int i = 1; i <= 4; i++) + { + entry[i] = ctx.add(field[i]); + } // Check newest entry is at 62 oldest at 66 - assertEquals(5,ctx.size()); - int index=66; - for (int i=0;i<=4;i++) + assertEquals(5, ctx.size()); + int index = 66; + for (int i = 0; i <= 4; i++) { - assertEquals(index,ctx.index(entry[i])); - assertEquals(entry[i],ctx.get(index)); + assertEquals(index, ctx.index(entry[i])); + assertEquals(entry[i], ctx.get(index)); index--; } // and statics still OK - assertEquals(":authority",ctx.get(1).getHttpField().getName()); - assertEquals(3,ctx.index(ctx.get(methodPost))); - assertEquals(methodPost,ctx.get(3).getHttpField()); - assertEquals("www-authenticate",ctx.get(61).getHttpField().getName()); - assertEquals(null,ctx.get(62+ctx.size())); - + assertEquals(":authority", ctx.get(1).getHttpField().getName()); + assertEquals(3, ctx.index(ctx.get(methodPost))); + assertEquals(methodPost, ctx.get(3).getHttpField()); + assertEquals("www-authenticate", ctx.get(61).getHttpField().getName()); + assertEquals(null, ctx.get(62 + ctx.size())); + // add 1 more entry and this should cause an eviction! - entry[5]=ctx.add(field[5]); + entry[5] = ctx.add(field[5]); // Check newest entry is at 1 oldest at 5 - index=66; - for (int i=1;i<=5;i++) + index = 66; + for (int i = 1; i <= 5; i++) { - assertEquals(index,ctx.index(entry[i])); - assertEquals(entry[i],ctx.get(index)); + assertEquals(index, ctx.index(entry[i])); + assertEquals(entry[i], ctx.get(index)); index--; } // check entry 0 evicted assertNull(ctx.get(field[0])); - assertEquals(0,ctx.index(entry[0])); + assertEquals(0, ctx.index(entry[0])); // and statics still OK - assertEquals(":authority",ctx.get(1).getHttpField().getName()); - assertEquals(3,ctx.index(ctx.get(methodPost))); - assertEquals(methodPost,ctx.get(3).getHttpField()); - assertEquals("www-authenticate",ctx.get(61).getHttpField().getName()); - assertEquals(null,ctx.get(62+ctx.size())); - + assertEquals(":authority", ctx.get(1).getHttpField().getName()); + assertEquals(3, ctx.index(ctx.get(methodPost))); + assertEquals(methodPost, ctx.get(3).getHttpField()); + assertEquals("www-authenticate", ctx.get(61).getHttpField().getName()); + assertEquals(null, ctx.get(62 + ctx.size())); + // Add 4 more entries - for (int i=6;i<=9;i++) - entry[i]=ctx.add(field[i]); - - // Check newest entry is at 1 oldest at 5 - index=66; - for (int i=5;i<=9;i++) + for (int i = 6; i <= 9; i++) { - assertEquals(index,ctx.index(entry[i])); - assertEquals(entry[i],ctx.get(index)); + entry[i] = ctx.add(field[i]); + } + + // Check newest entry is at 1 oldest at 5 + index = 66; + for (int i = 5; i <= 9; i++) + { + assertEquals(index, ctx.index(entry[i])); + assertEquals(entry[i], ctx.get(index)); index--; } // check entry 0-4 evicted - for (int i=0;i<=4;i++) + for (int i = 0; i <= 4; i++) { assertNull(ctx.get(field[i])); - assertEquals(0,ctx.index(entry[i])); + assertEquals(0, ctx.index(entry[i])); } - // Add new entries enough so that array queue will wrap - for (int i=10;i<=52;i++) - entry[i]=ctx.add(new HttpField("n"+i,"v"+i)); - - index=66; - for (int i=48;i<=52;i++) + for (int i = 10; i <= 52; i++) { - assertEquals(index,ctx.index(entry[i])); - assertEquals(entry[i],ctx.get(index)); + entry[i] = ctx.add(new HttpField("n" + i, "v" + i)); + } + + index = 66; + for (int i = 48; i <= 52; i++) + { + assertEquals(index, ctx.index(entry[i])); + assertEquals(entry[i], ctx.get(index)); index--; } } - @Test public void testResize() { // Only enough space for 5 entries - HpackContext ctx = new HpackContext(38*5); - - HttpField[] field = - { - new HttpField("fo0","b0r"), - new HttpField("fo1","b1r"), - new HttpField("fo2","b2r"), - new HttpField("fo3","b3r"), - new HttpField("fo4","b4r"), - new HttpField("fo5","b5r"), - new HttpField("fo6","b6r"), - new HttpField("fo7","b7r"), - new HttpField("fo8","b8r"), - new HttpField("fo9","b9r"), - new HttpField("foA","bAr"), - }; + HpackContext ctx = new HpackContext(38 * 5); + + HttpField[] field = + { + new HttpField("fo0", "b0r"), + new HttpField("fo1", "b1r"), + new HttpField("fo2", "b2r"), + new HttpField("fo3", "b3r"), + new HttpField("fo4", "b4r"), + new HttpField("fo5", "b5r"), + new HttpField("fo6", "b6r"), + new HttpField("fo7", "b7r"), + new HttpField("fo8", "b8r"), + new HttpField("fo9", "b9r"), + new HttpField("foA", "bAr"), + }; Entry[] entry = new Entry[field.length]; - + // Add 5 entries - for (int i=0;i<=4;i++) - entry[i]=ctx.add(field[i]); - - assertEquals(5,ctx.size()); - - // check indexes - int index=66; - for (int i=0;i<=4;i++) + for (int i = 0; i <= 4; i++) { - assertEquals(index,ctx.index(entry[i])); - assertEquals(entry[i],ctx.get(index)); + entry[i] = ctx.add(field[i]); + } + + assertEquals(5, ctx.size()); + + // check indexes + int index = 66; + for (int i = 0; i <= 4; i++) + { + assertEquals(index, ctx.index(entry[i])); + assertEquals(entry[i], ctx.get(index)); index--; } // resize so that only 2 entries may be held - ctx.resize(38*2); - assertEquals(2,ctx.size()); - - // check indexes - index=63; - for (int i=3;i<=4;i++) - { - assertEquals(index,ctx.index(entry[i])); - assertEquals(entry[i],ctx.get(index)); - index--; - } - - // resize so that 6.5 entries may be held - ctx.resize(38*6+19); - assertEquals(2,ctx.size()); + ctx.resize(38 * 2); + assertEquals(2, ctx.size()); // check indexes - index=63; - for (int i=3;i<=4;i++) + index = 63; + for (int i = 3; i <= 4; i++) { - assertEquals(index,ctx.index(entry[i])); - assertEquals(entry[i],ctx.get(index)); + assertEquals(index, ctx.index(entry[i])); + assertEquals(entry[i], ctx.get(index)); + index--; + } + + // resize so that 6.5 entries may be held + ctx.resize(38 * 6 + 19); + assertEquals(2, ctx.size()); + + // check indexes + index = 63; + for (int i = 3; i <= 4; i++) + { + assertEquals(index, ctx.index(entry[i])); + assertEquals(entry[i], ctx.get(index)); index--; } - // Add 5 entries - for (int i=5;i<=9;i++) - entry[i]=ctx.add(field[i]); - - assertEquals(6,ctx.size()); + for (int i = 5; i <= 9; i++) + { + entry[i] = ctx.add(field[i]); + } + + assertEquals(6, ctx.size()); // check indexes - index=67; - for (int i=4;i<=9;i++) + index = 67; + for (int i = 4; i <= 9; i++) { - assertEquals(index,ctx.index(entry[i])); - assertEquals(entry[i],ctx.get(index)); + assertEquals(index, ctx.index(entry[i])); + assertEquals(entry[i], ctx.get(index)); index--; } - // resize so that only 100 entries may be held - ctx.resize(38*100); - assertEquals(6,ctx.size()); + ctx.resize(38 * 100); + assertEquals(6, ctx.size()); // check indexes - index=67; - for (int i=4;i<=9;i++) + index = 67; + for (int i = 4; i <= 9; i++) { - assertEquals(index,ctx.index(entry[i])); - assertEquals(entry[i],ctx.get(index)); + assertEquals(index, ctx.index(entry[i])); + assertEquals(entry[i], ctx.get(index)); index--; } - + // add 50 fields - for (int i=0;i<50;i++) - ctx.add(new HttpField("n"+i,"v"+i)); + for (int i = 0; i < 50; i++) + { + ctx.add(new HttpField("n" + i, "v" + i)); + } // check indexes - index=67+50; - for (int i=4;i<=9;i++) + index = 67 + 50; + for (int i = 4; i <= 9; i++) { - assertEquals(index,ctx.index(entry[i])); - assertEquals(entry[i],ctx.get(index)); + assertEquals(index, ctx.index(entry[i])); + assertEquals(entry[i], ctx.get(index)); index--; } - - } - + @Test public void testStaticHuffmanValues() throws Exception { HpackContext ctx = new HpackContext(4096); - for (int i=2;i<=14;i++) + for (int i = 2; i <= 14; i++) { - Entry entry=ctx.get(i); + Entry entry = ctx.get(i); assertTrue(entry.isStatic()); - + ByteBuffer buffer = ByteBuffer.wrap(entry.getStaticHuffmanValue()); - int huff = 0xff&buffer.get(); - assertTrue((0x80&huff)==0x80); - - int len = NBitInteger.decode(buffer,7); - - assertEquals(len,buffer.remaining()); + int huff = 0xff & buffer.get(); + assertTrue((0x80 & huff) == 0x80); + + int len = NBitInteger.decode(buffer, 7); + + assertEquals(len, buffer.remaining()); String value = Huffman.decode(buffer); - - assertEquals(entry.getHttpField().getValue(),value); - + + assertEquals(entry.getHttpField().getValue(), value); } } - - @Test public void testNameInsensitivity() { HpackContext ctx = new HpackContext(4096); - assertEquals("content-length",ctx.get("content-length").getHttpField().getName()); - assertEquals("content-length",ctx.get("Content-Length").getHttpField().getName()); + assertEquals("content-length", ctx.get("content-length").getHttpField().getName()); + assertEquals("content-length", ctx.get("Content-Length").getHttpField().getName()); assertTrue(ctx.get("Content-Length").isStatic()); assertTrue(ctx.get("Content-Type").isStatic()); - - ctx.add(new HttpField("Wibble","Wobble")); - assertEquals("Wibble",ctx.get("wibble").getHttpField().getName()); - assertEquals("Wibble",ctx.get("Wibble").getHttpField().getName()); - + + ctx.add(new HttpField("Wibble", "Wobble")); + assertEquals("Wibble", ctx.get("wibble").getHttpField().getName()); + assertEquals("Wibble", ctx.get("Wibble").getHttpField().getName()); } } diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java index 5c0bd8b9e2d..791ecd3d060 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,109 +16,127 @@ // ======================================================================== // - package org.eclipse.jetty.http2.hpack; +import java.nio.ByteBuffer; +import java.util.Iterator; + import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.hpack.HpackException.CompressionException; +import org.eclipse.jetty.http2.hpack.HpackException.SessionException; import org.eclipse.jetty.http2.hpack.HpackException.StreamException; import org.eclipse.jetty.util.TypeUtil; import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; - -import java.nio.ByteBuffer; -import java.util.Iterator; - import static org.eclipse.jetty.http.HttpFieldsMatchers.containsHeaderValue; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; -import static org.junit.jupiter.api.Assertions.*; - +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.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; public class HpackDecoderTest { + /* + 0 1 2 3 4 5 6 7 + +---+---+---+---+---+---+---+---+ + | 0 | 0 | 0 | 0 | 0 | + +---+---+-----------------------+ + | H | Name Length (7+) | + +---+---------------------------+ + | Name String (Length octets) | + +---+---------------------------+ + | H | Value Length (7+) | + +---+---------------------------+ + | Value String (Length octets) | + +-------------------------------+ + */ + @Test public void testDecodeD_3() throws Exception { - HpackDecoder decoder = new HpackDecoder(4096,8192); + HpackDecoder decoder = new HpackDecoder(4096, 8192); // First request - String encoded="828684410f7777772e6578616d706c652e636f6d"; + String encoded = "828684410f7777772e6578616d706c652e636f6d"; ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); MetaData.Request request = (MetaData.Request)decoder.decode(buffer); assertEquals("GET", request.getMethod()); - assertEquals(HttpScheme.HTTP.asString(),request.getURI().getScheme()); - assertEquals("/",request.getURI().getPath()); - assertEquals("www.example.com",request.getURI().getHost()); + assertEquals(HttpScheme.HTTP.asString(), request.getURI().getScheme()); + assertEquals("/", request.getURI().getPath()); + assertEquals("www.example.com", request.getURI().getHost()); assertFalse(request.iterator().hasNext()); // Second request - encoded="828684be58086e6f2d6361636865"; + encoded = "828684be58086e6f2d6361636865"; buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); request = (MetaData.Request)decoder.decode(buffer); assertEquals("GET", request.getMethod()); - assertEquals(HttpScheme.HTTP.asString(),request.getURI().getScheme()); - assertEquals("/",request.getURI().getPath()); - assertEquals("www.example.com",request.getURI().getHost()); - Iterator iterator=request.iterator(); + assertEquals(HttpScheme.HTTP.asString(), request.getURI().getScheme()); + assertEquals("/", request.getURI().getPath()); + assertEquals("www.example.com", request.getURI().getHost()); + Iterator iterator = request.iterator(); assertTrue(iterator.hasNext()); - assertEquals(new HttpField("cache-control","no-cache"),iterator.next()); + assertEquals(new HttpField("cache-control", "no-cache"), iterator.next()); assertFalse(iterator.hasNext()); // Third request - encoded="828785bf400a637573746f6d2d6b65790c637573746f6d2d76616c7565"; + encoded = "828785bf400a637573746f6d2d6b65790c637573746f6d2d76616c7565"; buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); request = (MetaData.Request)decoder.decode(buffer); - assertEquals("GET",request.getMethod()); - assertEquals(HttpScheme.HTTPS.asString(),request.getURI().getScheme()); - assertEquals("/index.html",request.getURI().getPath()); - assertEquals("www.example.com",request.getURI().getHost()); - iterator=request.iterator(); + assertEquals("GET", request.getMethod()); + assertEquals(HttpScheme.HTTPS.asString(), request.getURI().getScheme()); + assertEquals("/index.html", request.getURI().getPath()); + assertEquals("www.example.com", request.getURI().getHost()); + iterator = request.iterator(); assertTrue(iterator.hasNext()); - assertEquals(new HttpField("custom-key","custom-value"),iterator.next()); + assertEquals(new HttpField("custom-key", "custom-value"), iterator.next()); assertFalse(iterator.hasNext()); } @Test public void testDecodeD_4() throws Exception { - HpackDecoder decoder = new HpackDecoder(4096,8192); + HpackDecoder decoder = new HpackDecoder(4096, 8192); // First request - String encoded="828684418cf1e3c2e5f23a6ba0ab90f4ff"; + String encoded = "828684418cf1e3c2e5f23a6ba0ab90f4ff"; ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); MetaData.Request request = (MetaData.Request)decoder.decode(buffer); assertEquals("GET", request.getMethod()); - assertEquals(HttpScheme.HTTP.asString(),request.getURI().getScheme()); - assertEquals("/",request.getURI().getPath()); - assertEquals("www.example.com",request.getURI().getHost()); + assertEquals(HttpScheme.HTTP.asString(), request.getURI().getScheme()); + assertEquals("/", request.getURI().getPath()); + assertEquals("www.example.com", request.getURI().getHost()); assertFalse(request.iterator().hasNext()); // Second request - encoded="828684be5886a8eb10649cbf"; + encoded = "828684be5886a8eb10649cbf"; buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); request = (MetaData.Request)decoder.decode(buffer); assertEquals("GET", request.getMethod()); - assertEquals(HttpScheme.HTTP.asString(),request.getURI().getScheme()); - assertEquals("/",request.getURI().getPath()); - assertEquals("www.example.com",request.getURI().getHost()); - Iterator iterator=request.iterator(); + assertEquals(HttpScheme.HTTP.asString(), request.getURI().getScheme()); + assertEquals("/", request.getURI().getPath()); + assertEquals("www.example.com", request.getURI().getHost()); + Iterator iterator = request.iterator(); assertTrue(iterator.hasNext()); - assertEquals(new HttpField("cache-control","no-cache"),iterator.next()); + assertEquals(new HttpField("cache-control", "no-cache"), iterator.next()); assertFalse(iterator.hasNext()); } @@ -127,7 +145,7 @@ public class HpackDecoderTest { String value = "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="; - HpackDecoder decoder = new HpackDecoder(4096,8192); + HpackDecoder decoder = new HpackDecoder(4096, 8192); String encoded = "8682418cF1E3C2E5F23a6bA0Ab90F4Ff841f0822426173696320515778685a475270626a70766347567549484e6c633246745a513d3d"; byte[] bytes = TypeUtil.fromHexString(encoded); byte[] array = new byte[bytes.length + 1]; @@ -137,10 +155,10 @@ public class HpackDecoderTest MetaData.Request request = (MetaData.Request)decoder.decode(buffer); assertEquals("GET", request.getMethod()); - assertEquals(HttpScheme.HTTP.asString(),request.getURI().getScheme()); - assertEquals("/",request.getURI().getPath()); - assertEquals("www.example.com",request.getURI().getHost()); - assertEquals(1,request.getFields().size()); + assertEquals(HttpScheme.HTTP.asString(), request.getURI().getScheme()); + assertEquals("/", request.getURI().getPath()); + assertEquals("www.example.com", request.getURI().getHost()); + assertEquals(1, request.getFields().size()); HttpField field = request.iterator().next(); assertEquals(HttpHeader.AUTHORIZATION, field.getHeader()); assertEquals(value, field.getValue()); @@ -149,9 +167,9 @@ public class HpackDecoderTest @Test public void testDecodeHuffmanWithArrayOffset() throws Exception { - HpackDecoder decoder = new HpackDecoder(4096,8192); + HpackDecoder decoder = new HpackDecoder(4096, 8192); - String encoded="8286418cf1e3c2e5f23a6ba0ab90f4ff84"; + String encoded = "8286418cf1e3c2e5f23a6ba0ab90f4ff84"; byte[] bytes = TypeUtil.fromHexString(encoded); byte[] array = new byte[bytes.length + 1]; System.arraycopy(bytes, 0, array, 1, bytes.length); @@ -160,30 +178,30 @@ public class HpackDecoderTest MetaData.Request request = (MetaData.Request)decoder.decode(buffer); assertEquals("GET", request.getMethod()); - assertEquals(HttpScheme.HTTP.asString(),request.getURI().getScheme()); - assertEquals("/",request.getURI().getPath()); - assertEquals("www.example.com",request.getURI().getHost()); + assertEquals(HttpScheme.HTTP.asString(), request.getURI().getScheme()); + assertEquals("/", request.getURI().getPath()); + assertEquals("www.example.com", request.getURI().getHost()); assertFalse(request.iterator().hasNext()); } - + @Test public void testNghttpx() throws Exception - { + { // Response encoded by nghttpx - String encoded="886196C361Be940b6a65B6850400B8A00571972e080a62D1Bf5f87497cA589D34d1f9a0f0d0234327690Aa69D29aFcA954D3A5358980Ae112e0f7c880aE152A9A74a6bF3"; + String encoded = "886196C361Be940b6a65B6850400B8A00571972e080a62D1Bf5f87497cA589D34d1f9a0f0d0234327690Aa69D29aFcA954D3A5358980Ae112e0f7c880aE152A9A74a6bF3"; ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); - HpackDecoder decoder = new HpackDecoder(4096,8192); + HpackDecoder decoder = new HpackDecoder(4096, 8192); MetaData.Response response = (MetaData.Response)decoder.decode(buffer); - assertThat(response.getStatus(),is(200)); - assertThat(response.getFields().size(),is(6)); - assertThat(response.getFields(), containsHeaderValue(HttpHeader.DATE,"Fri, 15 Jul 2016 02:36:20 GMT")); - assertThat(response.getFields(), containsHeaderValue(HttpHeader.CONTENT_TYPE,"text/html")); - assertThat(response.getFields(), containsHeaderValue(HttpHeader.CONTENT_ENCODING,"")); - assertThat(response.getFields(), containsHeaderValue(HttpHeader.CONTENT_LENGTH,"42")); - assertThat(response.getFields(), containsHeaderValue(HttpHeader.SERVER,"nghttpx nghttp2/1.12.0")); - assertThat(response.getFields(), containsHeaderValue(HttpHeader.VIA,"1.1 nghttpx")); + assertThat(response.getStatus(), is(200)); + assertThat(response.getFields().size(), is(6)); + assertThat(response.getFields(), containsHeaderValue(HttpHeader.DATE, "Fri, 15 Jul 2016 02:36:20 GMT")); + assertThat(response.getFields(), containsHeaderValue(HttpHeader.CONTENT_TYPE, "text/html")); + assertThat(response.getFields(), containsHeaderValue(HttpHeader.CONTENT_ENCODING, "")); + assertThat(response.getFields(), containsHeaderValue(HttpHeader.CONTENT_LENGTH, "42")); + assertThat(response.getFields(), containsHeaderValue(HttpHeader.SERVER, "nghttpx nghttp2/1.12.0")); + assertThat(response.getFields(), containsHeaderValue(HttpHeader.VIA, "1.1 nghttpx")); } @Test @@ -193,12 +211,10 @@ public class HpackDecoderTest ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); HpackDecoder decoder = new HpackDecoder(4096, 8192); MetaData metaData = decoder.decode(buffer); - assertThat(metaData.getFields().get(HttpHeader.HOST),is( "localhost0")); - assertThat(metaData.getFields().get(HttpHeader.COOKIE),is("abcdefghij")); - assertThat(decoder.getHpackContext().getMaxDynamicTableSize(),is(50)); - assertThat(decoder.getHpackContext().size(),is(1)); - - + assertThat(metaData.getFields().get(HttpHeader.HOST), is("localhost0")); + assertThat(metaData.getFields().get(HttpHeader.COOKIE), is("abcdefghij")); + assertThat(decoder.getHpackContext().getMaxDynamicTableSize(), is(50)); + assertThat(decoder.getHpackContext().size(), is(1)); } @Test @@ -212,7 +228,7 @@ public class HpackDecoderTest Expected: GOAWAY Frame (Error Code: COMPRESSION_ERROR) Connection closed */ - + String encoded = "203f136687A0E41d139d090760881c6490B2Cd39Ba7f20"; ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); HpackDecoder decoder = new HpackDecoder(4096, 8192); @@ -221,9 +237,9 @@ public class HpackDecoderTest decoder.decode(buffer); fail(); } - catch(CompressionException e) + catch (CompressionException e) { - assertThat(e.getMessage(),Matchers.containsString("Dynamic table resize after fields")); + assertThat(e.getMessage(), Matchers.containsString("Dynamic table resize after fields")); } } @@ -233,11 +249,11 @@ public class HpackDecoderTest String encoded = "3f610f17FfEc02Df3990A190A0D4Ee5b3d2940Ec98Aa4a62D127D29e273a0aA20dEcAa190a503b262d8a2671D4A2672a927aA874988a2471D05510750c951139EdA2452a3a548cAa1aA90bE4B228342864A9E0D450A5474a92992a1aA513395448E3A0Aa17B96cFe3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f14E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F353F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F54f"; ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); - HpackDecoder decoder = new HpackDecoder(128,8192); + HpackDecoder decoder = new HpackDecoder(128, 8192); MetaData metaData = decoder.decode(buffer); - assertThat(decoder.getHpackContext().getDynamicTableSize(),is(0)); - assertThat(metaData.getFields().get("host"),Matchers.startsWith("This is a very large field")); + assertThat(decoder.getHpackContext().getDynamicTableSize(), is(0)); + assertThat(metaData.getFields().get("host"), Matchers.startsWith("This is a very large field")); } @Test @@ -246,197 +262,189 @@ public class HpackDecoderTest String encoded = "BE"; ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); - HpackDecoder decoder = new HpackDecoder(128,8192); + HpackDecoder decoder = new HpackDecoder(128, 8192); try { decoder.decode(buffer); fail(); } - catch (HpackException.SessionException e) + catch (SessionException e) { - assertThat(e.getMessage(),Matchers.startsWith("Unknown index")); + assertThat(e.getMessage(), Matchers.startsWith("Unknown index")); } - } - + /* 8.1.2.1. Pseudo-Header Fields */ - @Test() + @Test public void test8_1_2_1_PsuedoHeaderFields() throws Exception { // 1:Sends a HEADERS frame that contains a unknown pseudo-header field MetaDataBuilder mdb = new MetaDataBuilder(4096); - mdb.emit(new HttpField(":unknown","value")); + mdb.emit(new HttpField(":unknown", "value")); try { mdb.build(); fail(); } - catch(StreamException ex) + catch (StreamException ex) { - assertThat(ex.getMessage(),Matchers.containsString("Unknown pseudo header")); + assertThat(ex.getMessage(), Matchers.containsString("Unknown pseudo header")); } - + // 2: Sends a HEADERS frame that contains the pseudo-header field defined for response mdb = new MetaDataBuilder(4096); - mdb.emit(new HttpField(HttpHeader.C_SCHEME,"http")); - mdb.emit(new HttpField(HttpHeader.C_METHOD,"GET")); - mdb.emit(new HttpField(HttpHeader.C_PATH,"/path")); - mdb.emit(new HttpField(HttpHeader.C_STATUS,"100")); + mdb.emit(new HttpField(HttpHeader.C_SCHEME, "http")); + mdb.emit(new HttpField(HttpHeader.C_METHOD, "GET")); + mdb.emit(new HttpField(HttpHeader.C_PATH, "/path")); + mdb.emit(new HttpField(HttpHeader.C_STATUS, "100")); try { mdb.build(); fail(); } - catch(StreamException ex) + catch (StreamException ex) { - assertThat(ex.getMessage(),Matchers.containsString("Request and Response headers")); + assertThat(ex.getMessage(), Matchers.containsString("Request and Response headers")); } // 3: Sends a HEADERS frame that contains a pseudo-header field as trailers - + // 4: Sends a HEADERS frame that contains a pseudo-header field that appears in a header block after a regular header field mdb = new MetaDataBuilder(4096); - mdb.emit(new HttpField(HttpHeader.C_SCHEME,"http")); - mdb.emit(new HttpField(HttpHeader.C_METHOD,"GET")); - mdb.emit(new HttpField(HttpHeader.C_PATH,"/path")); - mdb.emit(new HttpField("Accept","No Compromise")); - mdb.emit(new HttpField(HttpHeader.C_AUTHORITY,"localhost")); + mdb.emit(new HttpField(HttpHeader.C_SCHEME, "http")); + mdb.emit(new HttpField(HttpHeader.C_METHOD, "GET")); + mdb.emit(new HttpField(HttpHeader.C_PATH, "/path")); + mdb.emit(new HttpField("Accept", "No Compromise")); + mdb.emit(new HttpField(HttpHeader.C_AUTHORITY, "localhost")); try { mdb.build(); fail(); } - catch(StreamException ex) + catch (StreamException ex) { - assertThat(ex.getMessage(),Matchers.containsString("Pseudo header :authority after fields")); + assertThat(ex.getMessage(), Matchers.containsString("Pseudo header :authority after fields")); } } - - @Test() + + @Test public void test8_1_2_2_ConnectionSpecificHeaderFields() throws Exception { MetaDataBuilder mdb; // 1: Sends a HEADERS frame that contains the connection-specific header field mdb = new MetaDataBuilder(4096); - mdb.emit(new HttpField(HttpHeader.CONNECTION,"value")); + mdb.emit(new HttpField(HttpHeader.CONNECTION, "value")); try { mdb.build(); fail(); } - catch(StreamException ex) + catch (StreamException ex) { - assertThat(ex.getMessage(),Matchers.containsString("Connection specific field 'Connection'")); + assertThat(ex.getMessage(), Matchers.containsString("Connection specific field 'Connection'")); } // 2: Sends a HEADERS frame that contains the TE header field with any value other than "trailers" mdb = new MetaDataBuilder(4096); - mdb.emit(new HttpField(HttpHeader.TE,"not_trailers")); + mdb.emit(new HttpField(HttpHeader.TE, "not_trailers")); try { mdb.build(); fail(); } - catch(StreamException ex) + catch (StreamException ex) { - assertThat(ex.getMessage(),Matchers.containsString("Unsupported TE value 'not_trailers'")); + assertThat(ex.getMessage(), Matchers.containsString("Unsupported TE value 'not_trailers'")); } - mdb = new MetaDataBuilder(4096); - mdb.emit(new HttpField(HttpHeader.CONNECTION,"TE")); - mdb.emit(new HttpField(HttpHeader.TE,"trailers")); + mdb.emit(new HttpField(HttpHeader.CONNECTION, "TE")); + mdb.emit(new HttpField(HttpHeader.TE, "trailers")); assertNotNull(mdb.build()); } - - @Test() + @Test public void test8_1_2_3_RequestPseudoHeaderFields() throws Exception { { - MetaDataBuilder mdb = new MetaDataBuilder( 4096 ); - mdb.emit( new HttpField( HttpHeader.C_METHOD, "GET" ) ); - mdb.emit( new HttpField( HttpHeader.C_SCHEME, "http" ) ); - mdb.emit( new HttpField( HttpHeader.C_AUTHORITY, "localhost:8080" ) ); - mdb.emit( new HttpField( HttpHeader.C_PATH, "/" ) ); - assertThat( mdb.build(), Matchers.instanceOf( MetaData.Request.class ) ); + MetaDataBuilder mdb = new MetaDataBuilder(4096); + mdb.emit(new HttpField(HttpHeader.C_METHOD, "GET")); + mdb.emit(new HttpField(HttpHeader.C_SCHEME, "http")); + mdb.emit(new HttpField(HttpHeader.C_AUTHORITY, "localhost:8080")); + mdb.emit(new HttpField(HttpHeader.C_PATH, "/")); + assertThat(mdb.build(), Matchers.instanceOf(MetaData.Request.class)); } { // 1: Sends a HEADERS frame with empty ":path" pseudo-header field - final MetaDataBuilder mdb = new MetaDataBuilder( 4096 ); - mdb.emit( new HttpField( HttpHeader.C_METHOD, "GET" ) ); - mdb.emit( new HttpField( HttpHeader.C_SCHEME, "http" ) ); - mdb.emit( new HttpField( HttpHeader.C_AUTHORITY, "localhost:8080" ) ); - mdb.emit( new HttpField( HttpHeader.C_PATH, "" ) ); - StreamException ex = assertThrows( StreamException.class, () -> mdb.build() ); - assertThat( ex.getMessage(), Matchers.containsString( "No Path" ) ); - + final MetaDataBuilder mdb = new MetaDataBuilder(4096); + mdb.emit(new HttpField(HttpHeader.C_METHOD, "GET")); + mdb.emit(new HttpField(HttpHeader.C_SCHEME, "http")); + mdb.emit(new HttpField(HttpHeader.C_AUTHORITY, "localhost:8080")); + mdb.emit(new HttpField(HttpHeader.C_PATH, "")); + StreamException ex = assertThrows(StreamException.class, mdb::build); + assertThat(ex.getMessage(), Matchers.containsString("No Path")); } { // 2: Sends a HEADERS frame that omits ":method" pseudo-header field - final MetaDataBuilder mdb = new MetaDataBuilder( 4096 ); - mdb.emit( new HttpField( HttpHeader.C_SCHEME, "http" ) ); - mdb.emit( new HttpField( HttpHeader.C_AUTHORITY, "localhost:8080" ) ); - mdb.emit( new HttpField( HttpHeader.C_PATH, "/" ) ); - StreamException ex = assertThrows( StreamException.class, () -> mdb.build() ); - assertThat( ex.getMessage(), Matchers.containsString( "No Method" ) ); - + final MetaDataBuilder mdb = new MetaDataBuilder(4096); + mdb.emit(new HttpField(HttpHeader.C_SCHEME, "http")); + mdb.emit(new HttpField(HttpHeader.C_AUTHORITY, "localhost:8080")); + mdb.emit(new HttpField(HttpHeader.C_PATH, "/")); + StreamException ex = assertThrows(StreamException.class, mdb::build); + assertThat(ex.getMessage(), Matchers.containsString("No Method")); } { // 3: Sends a HEADERS frame that omits ":scheme" pseudo-header field - final MetaDataBuilder mdb = new MetaDataBuilder( 4096 ); - mdb.emit( new HttpField( HttpHeader.C_METHOD, "GET" ) ); - mdb.emit( new HttpField( HttpHeader.C_AUTHORITY, "localhost:8080" ) ); - mdb.emit( new HttpField( HttpHeader.C_PATH, "/" ) ); - StreamException ex = assertThrows( StreamException.class, () -> mdb.build() ); - assertThat( ex.getMessage(), Matchers.containsString( "No Scheme" ) ); - + final MetaDataBuilder mdb = new MetaDataBuilder(4096); + mdb.emit(new HttpField(HttpHeader.C_METHOD, "GET")); + mdb.emit(new HttpField(HttpHeader.C_AUTHORITY, "localhost:8080")); + mdb.emit(new HttpField(HttpHeader.C_PATH, "/")); + StreamException ex = assertThrows(StreamException.class, mdb::build); + assertThat(ex.getMessage(), Matchers.containsString("No Scheme")); } { // 4: Sends a HEADERS frame that omits ":path" pseudo-header field - final MetaDataBuilder mdb = new MetaDataBuilder( 4096 ); - mdb.emit( new HttpField( HttpHeader.C_METHOD, "GET" ) ); - mdb.emit( new HttpField( HttpHeader.C_SCHEME, "http" ) ); - mdb.emit( new HttpField( HttpHeader.C_AUTHORITY, "localhost:8080" ) ); - StreamException ex = assertThrows( StreamException.class, () -> mdb.build() ); - assertThat( ex.getMessage(), Matchers.containsString( "No Path" ) ); - + final MetaDataBuilder mdb = new MetaDataBuilder(4096); + mdb.emit(new HttpField(HttpHeader.C_METHOD, "GET")); + mdb.emit(new HttpField(HttpHeader.C_SCHEME, "http")); + mdb.emit(new HttpField(HttpHeader.C_AUTHORITY, "localhost:8080")); + StreamException ex = assertThrows(StreamException.class, mdb::build); + assertThat(ex.getMessage(), Matchers.containsString("No Path")); } { // 5: Sends a HEADERS frame with duplicated ":method" pseudo-header field - final MetaDataBuilder mdb = new MetaDataBuilder( 4096 ); - mdb.emit( new HttpField( HttpHeader.C_METHOD, "GET" ) ); - mdb.emit( new HttpField( HttpHeader.C_METHOD, "GET" ) ); - mdb.emit( new HttpField( HttpHeader.C_SCHEME, "http" ) ); - mdb.emit( new HttpField( HttpHeader.C_AUTHORITY, "localhost:8080" ) ); - mdb.emit( new HttpField( HttpHeader.C_PATH, "/" ) ); - StreamException ex = assertThrows( StreamException.class, () -> mdb.build() ); - assertThat( ex.getMessage(), Matchers.containsString( "Duplicate" ) ); + final MetaDataBuilder mdb = new MetaDataBuilder(4096); + mdb.emit(new HttpField(HttpHeader.C_METHOD, "GET")); + mdb.emit(new HttpField(HttpHeader.C_METHOD, "GET")); + mdb.emit(new HttpField(HttpHeader.C_SCHEME, "http")); + mdb.emit(new HttpField(HttpHeader.C_AUTHORITY, "localhost:8080")); + mdb.emit(new HttpField(HttpHeader.C_PATH, "/")); + StreamException ex = assertThrows(StreamException.class, mdb::build); + assertThat(ex.getMessage(), Matchers.containsString("Duplicate")); } { // 6: Sends a HEADERS frame with duplicated ":scheme" pseudo-header field - final MetaDataBuilder mdb = new MetaDataBuilder( 4096 ); - mdb.emit( new HttpField( HttpHeader.C_METHOD, "GET" ) ); - mdb.emit( new HttpField( HttpHeader.C_SCHEME, "http" ) ); - mdb.emit( new HttpField( HttpHeader.C_SCHEME, "http" ) ); - mdb.emit( new HttpField( HttpHeader.C_AUTHORITY, "localhost:8080" ) ); - mdb.emit( new HttpField( HttpHeader.C_PATH, "/" ) ); + final MetaDataBuilder mdb = new MetaDataBuilder(4096); + mdb.emit(new HttpField(HttpHeader.C_METHOD, "GET")); + mdb.emit(new HttpField(HttpHeader.C_SCHEME, "http")); + mdb.emit(new HttpField(HttpHeader.C_SCHEME, "http")); + mdb.emit(new HttpField(HttpHeader.C_AUTHORITY, "localhost:8080")); + mdb.emit(new HttpField(HttpHeader.C_PATH, "/")); - StreamException ex = assertThrows( StreamException.class, () -> mdb.build() ); - assertThat( ex.getMessage(), Matchers.containsString( "Duplicate" ) ); + StreamException ex = assertThrows(StreamException.class, mdb::build); + assertThat(ex.getMessage(), Matchers.containsString("Duplicate")); } } - - @Test() + @Test public void testHuffmanEncodedStandard() throws Exception { HpackDecoder decoder = new HpackDecoder(4096, 8192); @@ -453,75 +461,110 @@ public class HpackDecoderTest assertFalse(request.iterator().hasNext()); } - /* 5.2.1: Sends a Huffman-encoded string literal representation with padding longer than 7 bits */ - @Test() - public void testHuffmanEncodedExtraPadding() throws Exception + @Test + public void testHuffmanEncodedExtraPadding() { HpackDecoder decoder = new HpackDecoder(4096, 8192); String encoded = "82868441" + "84" + "49509FFF"; ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); - CompressionException ex = assertThrows( CompressionException.class, () -> decoder.decode(buffer)); + CompressionException ex = assertThrows(CompressionException.class, () -> decoder.decode(buffer)); assertThat(ex.getMessage(), Matchers.containsString("Bad termination")); } - /* 5.2.2: Sends a Huffman-encoded string literal representation padded by zero */ - @Test() - public void testHuffmanEncodedZeroPadding() throws Exception + @Test + public void testHuffmanEncodedZeroPadding() { HpackDecoder decoder = new HpackDecoder(4096, 8192); String encoded = "82868441" + "83" + "495090"; ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); - CompressionException ex = assertThrows( CompressionException.class, () -> decoder.decode(buffer)); + CompressionException ex = assertThrows(CompressionException.class, () -> decoder.decode(buffer)); 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() throws Exception + @Test + public void testHuffmanEncodedWithEOS() { HpackDecoder decoder = new HpackDecoder(4096, 8192); String encoded = "82868441" + "87" + "497FFFFFFF427F"; ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); - CompressionException ex = assertThrows( CompressionException.class, () -> decoder.decode(buffer)); + CompressionException ex = assertThrows(CompressionException.class, () -> decoder.decode(buffer)); assertThat(ex.getMessage(), Matchers.containsString("EOS in content")); - } - - @Test() - public void testHuffmanEncodedOneIncompleteOctet() throws Exception + @Test + public void testHuffmanEncodedOneIncompleteOctet() { HpackDecoder decoder = new HpackDecoder(4096, 8192); String encoded = "82868441" + "81" + "FE"; ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); - CompressionException ex = assertThrows( CompressionException.class, () -> decoder.decode(buffer)); + CompressionException ex = assertThrows(CompressionException.class, () -> decoder.decode(buffer)); assertThat(ex.getMessage(), Matchers.containsString("Bad termination")); - } - - @Test() - public void testHuffmanEncodedTwoIncompleteOctet() throws Exception + @Test + public void testHuffmanEncodedTwoIncompleteOctet() { HpackDecoder decoder = new HpackDecoder(4096, 8192); String encoded = "82868441" + "82" + "FFFE"; ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); - - CompressionException ex = assertThrows( CompressionException.class, () -> decoder.decode(buffer)); + CompressionException ex = assertThrows(CompressionException.class, () -> decoder.decode(buffer)); assertThat(ex.getMessage(), Matchers.containsString("Bad termination")); + } + @Test + public void testZeroLengthName() + { + HpackDecoder decoder = new HpackDecoder(4096, 8192); + + String encoded = "00000130"; + ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); + SessionException ex = assertThrows(SessionException.class, () -> decoder.decode(buffer)); + assertThat(ex.getMessage(), Matchers.containsString("Header size 0")); + } + + @Test + public void testZeroLengthValue() throws Exception + { + HpackDecoder decoder = new HpackDecoder(4096, 8192); + + String encoded = "00016800"; + ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); + MetaData metaData = decoder.decode(buffer); + assertThat(metaData.getFields().size(), is(1)); + assertThat(metaData.getFields().get("h"), is("")); + } + + @Test + public void testUpperCaseName() + { + HpackDecoder decoder = new HpackDecoder(4096, 8192); + + String encoded = "0001480130"; + ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); + StreamException ex = assertThrows(StreamException.class, () -> decoder.decode(buffer)); + assertThat(ex.getMessage(), Matchers.containsString("Uppercase header")); + } + + @Test + public void testWhiteSpaceName() + { + HpackDecoder decoder = new HpackDecoder(4096, 8192); + + String encoded = "0001200130"; + ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); + StreamException ex = assertThrows(StreamException.class, () -> decoder.decode(buffer)); + assertThat(ex.getMessage(), Matchers.containsString("Illegal header")); } } diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java index 43571dcc8b9..2fada9a66c5 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,176 +16,169 @@ // ======================================================================== // - package org.eclipse.jetty.http2.hpack; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.junit.jupiter.api.Assertions.assertEquals; - import java.nio.ByteBuffer; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; -import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.util.BufferUtil; import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.junit.jupiter.api.Assertions.assertEquals; -/* ------------------------------------------------------------ */ /** + * */ public class HpackEncoderTest { @Test public void testUnknownFieldsContextManagement() { - HpackEncoder encoder = new HpackEncoder(38*5); + HpackEncoder encoder = new HpackEncoder(38 * 5); HttpFields fields = new HttpFields(); - - HttpField[] field = - { - new HttpField("fo0","b0r"), - new HttpField("fo1","b1r"), - new HttpField("fo2","b2r"), - new HttpField("fo3","b3r"), - new HttpField("fo4","b4r"), - new HttpField("fo5","b5r"), - new HttpField("fo6","b6r"), - new HttpField("fo7","b7r"), - new HttpField("fo8","b8r"), - new HttpField("fo9","b9r"), - new HttpField("foA","bAr"), - }; - + HttpField[] field = + { + new HttpField("fo0", "b0r"), + new HttpField("fo1", "b1r"), + new HttpField("fo2", "b2r"), + new HttpField("fo3", "b3r"), + new HttpField("fo4", "b4r"), + new HttpField("fo5", "b5r"), + new HttpField("fo6", "b6r"), + new HttpField("fo7", "b7r"), + new HttpField("fo8", "b8r"), + new HttpField("fo9", "b9r"), + new HttpField("foA", "bAr"), + }; + // Add 4 entries - for (int i=0;i<=3;i++) + for (int i = 0; i <= 3; i++) + { fields.add(field[i]); - + } + // encode them ByteBuffer buffer = BufferUtil.allocate(4096); int pos = BufferUtil.flipToFill(buffer); - encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); - BufferUtil.flipToFlush(buffer,pos); - + encoder.encode(buffer, new MetaData(HttpVersion.HTTP_2, fields)); + BufferUtil.flipToFlush(buffer, pos); + // something was encoded! - assertThat(buffer.remaining(),Matchers.greaterThan(0)); - + assertThat(buffer.remaining(), Matchers.greaterThan(0)); + // All are in the dynamic table - assertEquals(4,encoder.getHpackContext().size()); - + assertEquals(4, encoder.getHpackContext().size()); + // encode exact same fields again! BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); - BufferUtil.flipToFlush(buffer,0); + encoder.encode(buffer, new MetaData(HttpVersion.HTTP_2, fields)); + BufferUtil.flipToFlush(buffer, 0); // All are in the dynamic table - assertEquals(4,encoder.getHpackContext().size()); - + assertEquals(4, encoder.getHpackContext().size()); + // Add 4 more fields - for (int i=4;i<=7;i++) + for (int i = 4; i <= 7; i++) + { fields.add(field[i]); - + } + // encode BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); - BufferUtil.flipToFlush(buffer,0); + encoder.encode(buffer, new MetaData(HttpVersion.HTTP_2, fields)); + BufferUtil.flipToFlush(buffer, 0); // something was encoded! - assertThat(buffer.remaining(),Matchers.greaterThan(0)); + assertThat(buffer.remaining(), Matchers.greaterThan(0)); // max dynamic table size reached - assertEquals(5,encoder.getHpackContext().size()); - - + assertEquals(5, encoder.getHpackContext().size()); + // remove some fields - for (int i=0;i<=7;i+=2) + for (int i = 0; i <= 7; i += 2) + { fields.remove(field[i].getName()); + } // encode BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); - BufferUtil.flipToFlush(buffer,0); - + encoder.encode(buffer, new MetaData(HttpVersion.HTTP_2, fields)); + BufferUtil.flipToFlush(buffer, 0); + // something was encoded! - assertThat(buffer.remaining(),Matchers.greaterThan(0)); + assertThat(buffer.remaining(), Matchers.greaterThan(0)); // max dynamic table size reached - assertEquals(5,encoder.getHpackContext().size()); - + assertEquals(5, encoder.getHpackContext().size()); // remove another fields fields.remove(field[1].getName()); // encode BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); - BufferUtil.flipToFlush(buffer,0); - + encoder.encode(buffer, new MetaData(HttpVersion.HTTP_2, fields)); + BufferUtil.flipToFlush(buffer, 0); + // something was encoded! - assertThat(buffer.remaining(),Matchers.greaterThan(0)); + assertThat(buffer.remaining(), Matchers.greaterThan(0)); // max dynamic table size reached - assertEquals(5,encoder.getHpackContext().size()); + assertEquals(5, encoder.getHpackContext().size()); - // re add the field fields.add(field[1]); // encode BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); - BufferUtil.flipToFlush(buffer,0); - + encoder.encode(buffer, new MetaData(HttpVersion.HTTP_2, fields)); + BufferUtil.flipToFlush(buffer, 0); + // something was encoded! - assertThat(buffer.remaining(),Matchers.greaterThan(0)); + assertThat(buffer.remaining(), Matchers.greaterThan(0)); // max dynamic table size reached - assertEquals(5,encoder.getHpackContext().size()); - + assertEquals(5, encoder.getHpackContext().size()); } - @Test public void testNeverIndexSetCookie() { - HpackEncoder encoder = new HpackEncoder(38*5); + HpackEncoder encoder = new HpackEncoder(38 * 5); ByteBuffer buffer = BufferUtil.allocate(4096); - + HttpFields fields = new HttpFields(); - fields.put("set-cookie","some cookie value"); + fields.put("set-cookie", "some cookie value"); // encode BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); - BufferUtil.flipToFlush(buffer,0); - + encoder.encode(buffer, new MetaData(HttpVersion.HTTP_2, fields)); + BufferUtil.flipToFlush(buffer, 0); + // something was encoded! - assertThat(buffer.remaining(),Matchers.greaterThan(0)); - + assertThat(buffer.remaining(), Matchers.greaterThan(0)); + // empty dynamic table - assertEquals(0,encoder.getHpackContext().size()); - + assertEquals(0, encoder.getHpackContext().size()); // encode again BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); - BufferUtil.flipToFlush(buffer,0); - + encoder.encode(buffer, new MetaData(HttpVersion.HTTP_2, fields)); + BufferUtil.flipToFlush(buffer, 0); + // something was encoded! - assertThat(buffer.remaining(),Matchers.greaterThan(0)); - + assertThat(buffer.remaining(), Matchers.greaterThan(0)); + // empty dynamic table - assertEquals(0,encoder.getHpackContext().size()); - + assertEquals(0, encoder.getHpackContext().size()); } - @Test public void testFieldLargerThanTable() @@ -195,82 +188,79 @@ public class HpackEncoderTest HpackEncoder encoder = new HpackEncoder(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.encode(buffer0, new MetaData(HttpVersion.HTTP_2, fields)); + BufferUtil.flipToFlush(buffer0, pos); + encoder = new HpackEncoder(128); - fields.add(new HttpField("user-agent","jetty/test")); + 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.encode(buffer1, new MetaData(HttpVersion.HTTP_2, fields)); + BufferUtil.flipToFlush(buffer1, pos); + encoder = new HpackEncoder(128); 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!"+ - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX "+ - "YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY "+ - "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ ")); + "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!" + + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX " + + "YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY " + + "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ ")); ByteBuffer buffer2 = BufferUtil.allocate(4096); pos = BufferUtil.flipToFill(buffer2); - encoder.encode(buffer2,new MetaData(HttpVersion.HTTP_2,fields)); - BufferUtil.flipToFlush(buffer2,pos); - + encoder.encode(buffer2, new MetaData(HttpVersion.HTTP_2, fields)); + BufferUtil.flipToFlush(buffer2, pos); + encoder = new HpackEncoder(128); - fields.add(new HttpField("host","somehost")); + fields.add(new HttpField("host", "somehost")); ByteBuffer buffer = BufferUtil.allocate(4096); pos = BufferUtil.flipToFill(buffer); - encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); - BufferUtil.flipToFlush(buffer,pos); + encoder.encode(buffer, new MetaData(HttpVersion.HTTP_2, fields)); + BufferUtil.flipToFlush(buffer, pos); //System.err.println(BufferUtil.toHexString(buffer0)); //System.err.println(BufferUtil.toHexString(buffer1)); //System.err.println(BufferUtil.toHexString(buffer2)); //System.err.println(BufferUtil.toHexString(buffer)); - + // something was encoded! - assertThat(buffer.remaining(),Matchers.greaterThan(0)); - + assertThat(buffer.remaining(), Matchers.greaterThan(0)); + // check first field is static index name and dynamic index body - assertThat((buffer.get(buffer0.remaining())&0xFF)>>6,equalTo(1)); - + assertThat((buffer.get(buffer0.remaining()) & 0xFF) >> 6, equalTo(1)); + // check first field is static index name and literal body - assertThat((buffer.get(buffer1.remaining())&0xFF)>>4,equalTo(0)); - + assertThat((buffer.get(buffer1.remaining()) & 0xFF) >> 4, equalTo(0)); + // check first field is static index name and dynamic index body - assertThat((buffer.get(buffer2.remaining())&0xFF)>>6,equalTo(1)); - + assertThat((buffer.get(buffer2.remaining()) & 0xFF) >> 6, equalTo(1)); + // Only first and third fields are put in the table HpackContext context = encoder.getHpackContext(); - assertThat(context.size(),equalTo(2)); - assertThat(context.get(HpackContext.STATIC_SIZE+1).getHttpField().getName(),equalTo("host")); - assertThat(context.get(HpackContext.STATIC_SIZE+2).getHttpField().getName(),equalTo("user-agent")); - assertThat(context.getDynamicTableSize(),equalTo( - context.get(HpackContext.STATIC_SIZE+1).getSize()+context.get(HpackContext.STATIC_SIZE+2).getSize())); - + assertThat(context.size(), equalTo(2)); + assertThat(context.get(HpackContext.STATIC_SIZE + 1).getHttpField().getName(), equalTo("host")); + assertThat(context.get(HpackContext.STATIC_SIZE + 2).getHttpField().getName(), equalTo("user-agent")); + assertThat(context.getDynamicTableSize(), equalTo( + context.get(HpackContext.STATIC_SIZE + 1).getSize() + context.get(HpackContext.STATIC_SIZE + 2).getSize())); } - + @Test public void testResize() { HttpFields fields = new HttpFields(); - fields.add("host", "localhost0"); - fields.add("cookie","abcdefghij"); + fields.add("host", "localhost0"); + fields.add("cookie", "abcdefghij"); HpackEncoder encoder = new HpackEncoder(4096); - + ByteBuffer buffer = BufferUtil.allocate(4096); int pos = BufferUtil.flipToFill(buffer); - encoder.encodeMaxDynamicTableSize(buffer,0); + encoder.encodeMaxDynamicTableSize(buffer, 0); encoder.setRemoteMaxDynamicTableSize(50); - encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); - BufferUtil.flipToFlush(buffer,pos); - - HpackContext context = encoder.getHpackContext(); - - assertThat(context.getMaxDynamicTableSize(),Matchers.is(50)); - assertThat(context.size(),Matchers.is(1)); - + encoder.encode(buffer, new MetaData(HttpVersion.HTTP_2, fields)); + BufferUtil.flipToFlush(buffer, pos); + HpackContext context = encoder.getHpackContext(); + + assertThat(context.getMaxDynamicTableSize(), Matchers.is(50)); + assertThat(context.size(), Matchers.is(1)); } } diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackPerfTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackPerfTest.java index 719a22c06ae..959a064eafb 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackPerfTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackPerfTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,7 +16,6 @@ // ======================================================================== // - package org.eclipse.jetty.http2.hpack; import java.io.File; @@ -35,33 +34,31 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; - public class HpackPerfTest { - int _maxDynamicTableSize=4*1024; + int _maxDynamicTableSize = 4 * 1024; int _unencodedSize; int _encodedSize; - + @BeforeEach public void before() { - _unencodedSize=0; - _encodedSize=0; + _unencodedSize = 0; + _encodedSize = 0; } @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", _maxDynamicTableSize, _unencodedSize, _encodedSize, 100.0 * _encodedSize / _unencodedSize); } - + @Test public void simpleTest() throws Exception { runStories(_maxDynamicTableSize); } - + private void runStories(int maxDynamicTableSize) throws Exception { // Find files @@ -74,62 +71,58 @@ public class HpackPerfTest return name.startsWith("story_"); } }); - + // Parse JSON - Map[] stories = new Map[files.length]; - int i=0; + Map[] stories = new Map[files.length]; + int i = 0; for (String story : files) - stories[i++]=(Map)JSON.parse(new FileReader(new File(data,story))); - - ByteBuffer buffer = BufferUtil.allocate(256*1024); - + { + stories[i++] = (Map)JSON.parse(new FileReader(new File(data, story))); + } + + ByteBuffer buffer = BufferUtil.allocate(256 * 1024); + // Encode all the requests - encodeStories(buffer,stories,"request"); + encodeStories(buffer, stories, "request"); // clear table BufferUtil.clearToFill(buffer); - BufferUtil.flipToFlush(buffer,0); - + BufferUtil.flipToFlush(buffer, 0); + // Encode all the responses - encodeStories(buffer,stories,"response"); - + 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(_maxDynamicTableSize, _maxDynamicTableSize); + // 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"); + Object[] headers = (Object[])((Map)c).get("headers"); // System.err.println(" "+headers); HttpFields fields = new HttpFields(); - for (Object header:headers) + for (Object header : headers) { - 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(); - + fields.add(e.getKey(), e.getValue()); + _unencodedSize += e.getKey().length() + e.getValue().length(); } BufferUtil.clearToFill(buffer); - encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); - BufferUtil.flipToFlush(buffer,0); - _encodedSize+=buffer.remaining(); - + encoder.encode(buffer, new MetaData(HttpVersion.HTTP_2, fields)); + BufferUtil.flipToFlush(buffer, 0); + _encodedSize += buffer.remaining(); } } } - } - - } diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java index 734089330e3..c2a2306fee5 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,13 +18,6 @@ package org.eclipse.jetty.http2.hpack; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.fail; - import java.nio.ByteBuffer; import java.util.concurrent.TimeUnit; @@ -39,106 +32,110 @@ import org.eclipse.jetty.http.PreEncodedHttpField; import org.eclipse.jetty.util.BufferUtil; import org.junit.jupiter.api.Test; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; public class HpackTest { - final static HttpField ServerJetty = new PreEncodedHttpField(HttpHeader.SERVER,"jetty"); - final static HttpField XPowerJetty = new PreEncodedHttpField(HttpHeader.X_POWERED_BY,"jetty"); - final static HttpField Date = new PreEncodedHttpField(HttpHeader.DATE,DateGenerator.formatDate(TimeUnit.NANOSECONDS.toMillis(System.nanoTime()))); - + 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()))); + @Test public void encodeDecodeResponseTest() throws Exception { HpackEncoder encoder = new HpackEncoder(); - HpackDecoder decoder = new HpackDecoder(4096,8192); - ByteBuffer buffer = BufferUtil.allocate(16*1024); - + HpackDecoder decoder = new HpackDecoder(4096, 8192); + ByteBuffer buffer = BufferUtil.allocateDirect(16 * 1024); + HttpFields fields0 = new HttpFields(); - fields0.add(HttpHeader.CONTENT_TYPE,"text/html"); - fields0.add(HttpHeader.CONTENT_LENGTH,"1024"); - fields0.add(new HttpField(HttpHeader.CONTENT_ENCODING,(String)null)); + fields0.add(HttpHeader.CONTENT_TYPE, "text/html"); + fields0.add(HttpHeader.CONTENT_LENGTH, "1024"); + fields0.add(new HttpField(HttpHeader.CONTENT_ENCODING, (String)null)); fields0.add(ServerJetty); fields0.add(XPowerJetty); fields0.add(Date); - fields0.add(HttpHeader.SET_COOKIE,"abcdefghijklmnopqrstuvwxyz"); - fields0.add("custom-key","custom-value"); - Response original0 = new MetaData.Response(HttpVersion.HTTP_2,200,fields0); - + fields0.add(HttpHeader.SET_COOKIE, "abcdefghijklmnopqrstuvwxyz"); + fields0.add("custom-key", "custom-value"); + Response original0 = new MetaData.Response(HttpVersion.HTTP_2, 200, fields0); + BufferUtil.clearToFill(buffer); - encoder.encode(buffer,original0); - BufferUtil.flipToFlush(buffer,0); + encoder.encode(buffer, original0); + BufferUtil.flipToFlush(buffer, 0); Response decoded0 = (Response)decoder.decode(buffer); - original0.getFields().put(new HttpField(HttpHeader.CONTENT_ENCODING,"")); - assertMetadataSame(original0,decoded0); - + original0.getFields().put(new HttpField(HttpHeader.CONTENT_ENCODING, "")); + assertMetadataSame(original0, decoded0); + // Same again? BufferUtil.clearToFill(buffer); - encoder.encode(buffer,original0); - BufferUtil.flipToFlush(buffer,0); + encoder.encode(buffer, original0); + BufferUtil.flipToFlush(buffer, 0); Response decoded0b = (Response)decoder.decode(buffer); - assertMetadataSame(original0,decoded0b); + assertMetadataSame(original0, decoded0b); HttpFields fields1 = new HttpFields(); - fields1.add(HttpHeader.CONTENT_TYPE,"text/plain"); - fields1.add(HttpHeader.CONTENT_LENGTH,"1234"); - fields1.add(HttpHeader.CONTENT_ENCODING," "); + fields1.add(HttpHeader.CONTENT_TYPE, "text/plain"); + fields1.add(HttpHeader.CONTENT_LENGTH, "1234"); + fields1.add(HttpHeader.CONTENT_ENCODING, " "); fields1.add(ServerJetty); fields1.add(XPowerJetty); fields1.add(Date); - fields1.add("Custom-Key","Other-Value"); - Response original1 = new MetaData.Response(HttpVersion.HTTP_2,200,fields1); + fields1.add("Custom-Key", "Other-Value"); + Response original1 = new MetaData.Response(HttpVersion.HTTP_2, 200, fields1); // Same again? BufferUtil.clearToFill(buffer); - encoder.encode(buffer,original1); - BufferUtil.flipToFlush(buffer,0); + encoder.encode(buffer, original1); + BufferUtil.flipToFlush(buffer, 0); Response decoded1 = (Response)decoder.decode(buffer); - assertMetadataSame(original1,decoded1); - assertEquals("custom-key",decoded1.getFields().getField("Custom-Key").getName()); + assertMetadataSame(original1, decoded1); + assertEquals("custom-key", decoded1.getFields().getField("Custom-Key").getName()); } - + @Test public void encodeDecodeTooLargeTest() throws Exception { HpackEncoder encoder = new HpackEncoder(); - HpackDecoder decoder = new HpackDecoder(4096,164); - ByteBuffer buffer = BufferUtil.allocate(16*1024); - + HpackDecoder decoder = new HpackDecoder(4096, 164); + ByteBuffer buffer = BufferUtil.allocateDirect(16 * 1024); + HttpFields fields0 = new HttpFields(); - fields0.add("1234567890","1234567890123456789012345678901234567890"); - fields0.add("Cookie","abcdeffhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR"); - MetaData original0= new MetaData(HttpVersion.HTTP_2,fields0); - + fields0.add("1234567890", "1234567890123456789012345678901234567890"); + fields0.add("Cookie", "abcdeffhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR"); + MetaData original0 = new MetaData(HttpVersion.HTTP_2, fields0); + BufferUtil.clearToFill(buffer); - encoder.encode(buffer,original0); - BufferUtil.flipToFlush(buffer,0); + encoder.encode(buffer, original0); + BufferUtil.flipToFlush(buffer, 0); MetaData decoded0 = (MetaData)decoder.decode(buffer); - assertMetadataSame(original0,decoded0); - + assertMetadataSame(original0, decoded0); + HttpFields fields1 = new HttpFields(); - fields1.add("1234567890","1234567890123456789012345678901234567890"); - fields1.add("Cookie","abcdeffhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR"); - fields1.add("x","y"); - MetaData original1 = new MetaData(HttpVersion.HTTP_2,fields1); + fields1.add("1234567890", "1234567890123456789012345678901234567890"); + fields1.add("Cookie", "abcdeffhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR"); + fields1.add("x", "y"); + MetaData original1 = new MetaData(HttpVersion.HTTP_2, fields1); BufferUtil.clearToFill(buffer); - encoder.encode(buffer,original1); - BufferUtil.flipToFlush(buffer,0); + encoder.encode(buffer, original1); + BufferUtil.flipToFlush(buffer, 0); try { decoder.decode(buffer); fail(); } - catch(HpackException.SessionException e) + catch (HpackException.SessionException e) { - assertThat(e.getMessage(),containsString("Header too large")); + assertThat(e.getMessage(), containsString("Header too large")); } } - @Test public void encodeDecodeNonAscii() throws Exception { @@ -163,62 +160,62 @@ public class HpackTest @Test public void evictReferencedFieldTest() throws Exception { - HpackEncoder encoder = new HpackEncoder(200,200); - HpackDecoder decoder = new HpackDecoder(200,1024); - ByteBuffer buffer = BufferUtil.allocate(16*1024); - + HpackEncoder encoder = new HpackEncoder(200, 200); + HpackDecoder decoder = new HpackDecoder(200, 1024); + ByteBuffer buffer = BufferUtil.allocateDirect(16 * 1024); + HttpFields fields0 = new HttpFields(); - fields0.add("123456789012345678901234567890123456788901234567890","value"); - fields0.add("foo","abcdeffhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR"); - MetaData original0= new MetaData(HttpVersion.HTTP_2,fields0); + fields0.add("123456789012345678901234567890123456788901234567890", "value"); + fields0.add("foo", "abcdeffhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR"); + MetaData original0 = new MetaData(HttpVersion.HTTP_2, fields0); BufferUtil.clearToFill(buffer); - encoder.encode(buffer,original0); - BufferUtil.flipToFlush(buffer,0); + encoder.encode(buffer, original0); + BufferUtil.flipToFlush(buffer, 0); MetaData decoded0 = (MetaData)decoder.decode(buffer); - assertEquals(2,encoder.getHpackContext().size()); - assertEquals(2,decoder.getHpackContext().size()); - assertEquals("123456789012345678901234567890123456788901234567890",encoder.getHpackContext().get(HpackContext.STATIC_TABLE.length+1).getHttpField().getName()); - assertEquals("foo",encoder.getHpackContext().get(HpackContext.STATIC_TABLE.length+0).getHttpField().getName()); - - assertMetadataSame(original0,decoded0); - + assertEquals(2, encoder.getHpackContext().size()); + assertEquals(2, decoder.getHpackContext().size()); + assertEquals("123456789012345678901234567890123456788901234567890", encoder.getHpackContext().get(HpackContext.STATIC_TABLE.length + 1).getHttpField().getName()); + assertEquals("foo", encoder.getHpackContext().get(HpackContext.STATIC_TABLE.length + 0).getHttpField().getName()); + + assertMetadataSame(original0, decoded0); + HttpFields fields1 = new HttpFields(); - fields1.add("123456789012345678901234567890123456788901234567890","other_value"); - fields1.add("x","y"); - MetaData original1 = new MetaData(HttpVersion.HTTP_2,fields1); + fields1.add("123456789012345678901234567890123456788901234567890", "other_value"); + fields1.add("x", "y"); + MetaData original1 = new MetaData(HttpVersion.HTTP_2, fields1); BufferUtil.clearToFill(buffer); - encoder.encode(buffer,original1); - BufferUtil.flipToFlush(buffer,0); + encoder.encode(buffer, original1); + BufferUtil.flipToFlush(buffer, 0); MetaData decoded1 = (MetaData)decoder.decode(buffer); - assertMetadataSame(original1,decoded1); - - assertEquals(2,encoder.getHpackContext().size()); - assertEquals(2,decoder.getHpackContext().size()); - assertEquals("x",encoder.getHpackContext().get(HpackContext.STATIC_TABLE.length+0).getHttpField().getName()); - assertEquals("foo",encoder.getHpackContext().get(HpackContext.STATIC_TABLE.length+1).getHttpField().getName()); + assertMetadataSame(original1, decoded1); + + assertEquals(2, encoder.getHpackContext().size()); + assertEquals(2, decoder.getHpackContext().size()); + assertEquals("x", encoder.getHpackContext().get(HpackContext.STATIC_TABLE.length + 0).getHttpField().getName()); + assertEquals("foo", encoder.getHpackContext().get(HpackContext.STATIC_TABLE.length + 1).getHttpField().getName()); } - + private void assertMetadataSame(MetaData.Response expected, MetaData.Response actual) { assertThat("Response.status", actual.getStatus(), is(expected.getStatus())); assertThat("Response.reason", actual.getReason(), is(expected.getReason())); - assertMetadataSame((MetaData)expected,(MetaData)actual); + assertMetadataSame((MetaData)expected, (MetaData)actual); } private void assertMetadataSame(MetaData expected, MetaData actual) { - assertThat("Metadata.contentLength",actual.getContentLength(),is(expected.getContentLength())); - assertThat("Metadata.version" + ".version", actual.getHttpVersion(),is(expected.getHttpVersion())); - assertHttpFieldsSame("Metadata.fields",expected.getFields(),actual.getFields()); + assertThat("Metadata.contentLength", actual.getContentLength(), is(expected.getContentLength())); + assertThat("Metadata.version" + ".version", actual.getHttpVersion(), is(expected.getHttpVersion())); + assertHttpFieldsSame("Metadata.fields", expected.getFields(), actual.getFields()); } private void assertHttpFieldsSame(String msg, HttpFields expected, HttpFields actual) { assertThat(msg + ".size", actual.size(), is(expected.size())); - + for (HttpField actualField : actual) { if ("DATE".equalsIgnoreCase(actualField.getName())) @@ -227,7 +224,7 @@ public class HpackTest // during testing. continue; } - assertThat(msg + ".contains(" + actualField + ")",expected.contains(actualField),is(true)); + assertThat(msg + ".contains(" + actualField + ")", expected.contains(actualField), is(true)); } } } diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HuffmanTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HuffmanTest.java index bf7a935458c..802427f1866 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HuffmanTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HuffmanTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,9 +18,7 @@ package org.eclipse.jetty.http2.hpack; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; - +import java.nio.BufferOverflowException; import java.nio.ByteBuffer; import java.util.Locale; import java.util.stream.Stream; @@ -32,54 +30,57 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.ValueSource; +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); + {"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}") + @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); + byte[] encoded = TypeUtil.fromHexString(hex); + String decoded = Huffman.decode(ByteBuffer.wrap(encoded)); + assertEquals(expected, decoded, specSection); } - @ParameterizedTest(name="[{index}] spec={0}") + @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)); + 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}) + @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+"'"; + String s = "bad '" + bad + "'"; assertThrows(IllegalArgumentException.class, - () -> Huffman.octetsNeeded(s)); + () -> Huffman.octetsNeeded(s)); - assertThrows(IllegalArgumentException.class, - () -> Huffman.encode(BufferUtil.allocate(32), s)); + assertThrows(BufferOverflowException.class, + () -> Huffman.encode(BufferUtil.allocate(32), s)); } } diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/NBitIntegerTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/NBitIntegerTest.java index b002bf29116..1fe8fd60f2f 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/NBitIntegerTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/NBitIntegerTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,197 +18,187 @@ package org.eclipse.jetty.http2.hpack; -import static org.junit.jupiter.api.Assertions.assertEquals; - 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 + @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(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)); + 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(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"); + 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) + public void testEncode(int n, int i, String expected) { ByteBuffer buf = BufferUtil.allocate(16); - int p=BufferUtil.flipToFill(buf); - if (n<8) + 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)); + 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"); + 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) + + 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)); + buf.position(n == 8 ? 0 : 1); + assertEquals(expected, NBitInteger.decode(buf, n)); } - + @Test public void testEncodeExampleD_1_1() { ByteBuffer buf = BufferUtil.allocate(16); - int p=BufferUtil.flipToFill(buf); + 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); - + NBitInteger.encode(buf, 5, 10); + BufferUtil.flipToFlush(buf, p); + + String r = TypeUtil.toHexString(BufferUtil.toArray(buf)); + + assertEquals("77Ea", r); } - + @Test public void testDecodeExampleD_1_1() { ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString("77EaFF")); buf.position(2); - - assertEquals(10,NBitInteger.decode(buf,5)); + + assertEquals(10, NBitInteger.decode(buf, 5)); } - @Test public void testEncodeExampleD_1_2() { ByteBuffer buf = BufferUtil.allocate(16); - int p=BufferUtil.flipToFill(buf); + 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); - + NBitInteger.encode(buf, 5, 1337); + BufferUtil.flipToFlush(buf, p); + + String r = TypeUtil.toHexString(BufferUtil.toArray(buf)); + + assertEquals("881f9a0a", r); } - + @Test public void testDecodeExampleD_1_2() { ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString("881f9a0aff")); buf.position(2); - - assertEquals(1337,NBitInteger.decode(buf,5)); + + assertEquals(1337, NBitInteger.decode(buf, 5)); } - - + @Test public void testEncodeExampleD_1_3() { ByteBuffer buf = BufferUtil.allocate(16); - int p=BufferUtil.flipToFill(buf); + 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); - + NBitInteger.encode(buf, 8, 42); + BufferUtil.flipToFlush(buf, p); + + String r = TypeUtil.toHexString(BufferUtil.toArray(buf)); + + assertEquals("88Ff2a", r); } - @Test public void testDecodeExampleD_1_3() { ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString("882aFf")); buf.position(1); - - assertEquals(42,NBitInteger.decode(buf,8)); - } - + assertEquals(42, NBitInteger.decode(buf, 8)); + } } diff --git a/jetty-http2/http2-http-client-transport/pom.xml b/jetty-http2/http2-http-client-transport/pom.xml index b25a8a679d1..dffc99a9c8c 100644 --- a/jetty-http2/http2-http-client-transport/pom.xml +++ b/jetty-http2/http2-http-client-transport/pom.xml @@ -1,115 +1,110 @@ - - org.eclipse.jetty.http2 - http2-parent - 9.4.13-SNAPSHOT - + + org.eclipse.jetty.http2 + http2-parent + 9.4.21-SNAPSHOT + - 4.0.0 - http2-http-client-transport - Jetty :: HTTP2 :: HTTP Client Transport + 4.0.0 + http2-http-client-transport + Jetty :: HTTP2 :: HTTP Client Transport - - ${project.groupId}.client.http - + + ${project.groupId}.client.http + - - - jdk8 - - [1.8,1.9) - - - - - maven-dependency-plugin - - - copy - generate-resources - - copy - - - - - org.mortbay.jetty.alpn - alpn-boot - ${alpn.version} - jar - false - ${project.build.directory}/alpn - - - - - - - - maven-surefire-plugin - - -Xbootclasspath/p:${project.build.directory}/alpn/alpn-boot-${alpn.version}.jar - - - - - - - jdk9 - - [1.9,) - - - - org.eclipse.jetty - jetty-alpn-java-client - ${project.version} - - - org.eclipse.jetty - jetty-alpn-java-server - ${project.version} - test - - - - + + + jdk8 + + [1.8,1.9) + + + + + maven-dependency-plugin + + + copy + generate-resources + + copy + + + + + org.mortbay.jetty.alpn + alpn-boot + ${alpn.version} + jar + false + ${project.build.directory}/alpn + + + + + + + + maven-surefire-plugin + + -Xbootclasspath/p:${project.build.directory}/alpn/alpn-boot-${alpn.version}.jar + + + + + + + jdk9 + + [1.9,) + + + + org.eclipse.jetty + jetty-alpn-java-client + ${project.version} + + + org.eclipse.jetty + jetty-alpn-java-server + ${project.version} + test + + + + - - - org.eclipse.jetty - jetty-client - ${project.version} - - - org.eclipse.jetty.http2 - http2-client - ${project.version} - + + + org.eclipse.jetty + jetty-client + ${project.version} + + + org.eclipse.jetty.http2 + http2-client + ${project.version} + - - org.eclipse.jetty.toolchain - jetty-test-helper - test - - - org.eclipse.jetty - jetty-server - ${project.version} - test - - - org.eclipse.jetty.http2 - http2-server - ${project.version} - test - - - junit - junit - test - - + + org.eclipse.jetty.toolchain + jetty-test-helper + test + + + org.eclipse.jetty + jetty-server + ${project.version} + test + + + org.eclipse.jetty.http2 + http2-server + ${project.version} + test + + diff --git a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpChannelOverHTTP2.java b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpChannelOverHTTP2.java index f9cfa6c2949..3373e5a1401 100644 --- a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpChannelOverHTTP2.java +++ b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpChannelOverHTTP2.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -25,6 +25,7 @@ import org.eclipse.jetty.client.HttpReceiver; import org.eclipse.jetty.client.HttpSender; import org.eclipse.jetty.client.api.Result; import org.eclipse.jetty.http2.ErrorCode; +import org.eclipse.jetty.http2.IStream; import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.frames.ResetFrame; @@ -101,6 +102,11 @@ public class HttpChannelOverHTTP2 extends HttpChannel connection.release(this); } + void onStreamClosed(IStream stream) + { + connection.onStreamClosed(stream, this); + } + @Override public void exchangeTerminated(HttpExchange exchange, Result result) { @@ -123,9 +129,9 @@ public class HttpChannelOverHTTP2 extends HttpChannel public String toString() { return String.format("%s[send=%s,recv=%s]", - super.toString(), - sender, - receiver); + super.toString(), + sender, + receiver); } private class ReleaseCallback implements Callback diff --git a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2.java b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2.java index 59996074445..7584d1966e1 100644 --- a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2.java +++ b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpConnectionOverHTTP2.java b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpConnectionOverHTTP2.java index 4d4a3cfebe8..83e808bf373 100644 --- a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpConnectionOverHTTP2.java +++ b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpConnectionOverHTTP2.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -35,17 +35,23 @@ import org.eclipse.jetty.client.HttpRequest; import org.eclipse.jetty.client.SendFailure; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http2.ErrorCode; +import org.eclipse.jetty.http2.IStream; import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.thread.Sweeper; public class HttpConnectionOverHTTP2 extends HttpConnection implements Sweeper.Sweepable { + private static final Logger LOG = Log.getLogger(HttpConnection.class); + private final Set activeChannels = ConcurrentHashMap.newKeySet(); private final Queue idleChannels = new ConcurrentLinkedQueue<>(); private final AtomicBoolean closed = new AtomicBoolean(); private final AtomicInteger sweeps = new AtomicInteger(); private final Session session; + private boolean recycleHttpChannels; public HttpConnectionOverHTTP2(HttpDestination destination, Session session) { @@ -58,6 +64,16 @@ public class HttpConnectionOverHTTP2 extends HttpConnection implements Sweeper.S return session; } + public boolean isRecycleHttpChannels() + { + return recycleHttpChannels; + } + + public void setRecycleHttpChannels(boolean recycleHttpChannels) + { + this.recycleHttpChannels = recycleHttpChannels; + } + @Override protected SendFailure send(HttpExchange exchange) { @@ -87,16 +103,15 @@ public class HttpConnectionOverHTTP2 extends HttpConnection implements Sweeper.S protected void release(HttpChannelOverHTTP2 channel) { - // Only non-push channels are released. + if (LOG.isDebugEnabled()) + LOG.debug("Released {}", channel); if (activeChannels.remove(channel)) { - channel.setStream(null); // Recycle only non-failed channels. if (channel.isFailed()) channel.destroy(); - else + else if (isRecycleHttpChannels()) idleChannels.offer(channel); - getHttpDestination().release(this); } else { @@ -104,6 +119,16 @@ public class HttpConnectionOverHTTP2 extends HttpConnection implements Sweeper.S } } + void onStreamClosed(IStream stream, HttpChannelOverHTTP2 channel) + { + if (LOG.isDebugEnabled()) + LOG.debug("{} closed for {}", stream, channel); + channel.setStream(null); + // Only non-push channels are released. + if (stream.isLocal()) + getHttpDestination().release(this); + } + @Override public boolean onIdleTimeout(long idleTimeout) { @@ -128,9 +153,9 @@ public class HttpConnectionOverHTTP2 extends HttpConnection implements Sweeper.S abort(failure); session.close(ErrorCode.NO_ERROR.code, failure.getMessage(), Callback.NOOP); - + HttpChannel channel = idleChannels.poll(); - while (channel!=null) + while (channel != null) { channel.destroy(); channel = idleChannels.poll(); @@ -154,7 +179,7 @@ public class HttpConnectionOverHTTP2 extends HttpConnection implements Sweeper.S } activeChannels.clear(); HttpChannel channel = idleChannels.poll(); - while (channel!=null) + while (channel != null) { channel.destroy(); channel = idleChannels.poll(); @@ -166,18 +191,16 @@ public class HttpConnectionOverHTTP2 extends HttpConnection implements Sweeper.S { if (!isClosed()) return false; - if (sweeps.incrementAndGet() < 4) - return false; - return true; + return sweeps.incrementAndGet() >= 4; } @Override public String toString() { return String.format("%s@%x(closed=%b)[%s]", - getClass().getSimpleName(), - hashCode(), - isClosed(), - session); + getClass().getSimpleName(), + hashCode(), + isClosed(), + session); } } diff --git a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpDestinationOverHTTP2.java b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpDestinationOverHTTP2.java index a63a028018c..5a030431de9 100644 --- a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpDestinationOverHTTP2.java +++ b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpDestinationOverHTTP2.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpReceiverOverHTTP2.java b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpReceiverOverHTTP2.java index a0f1817a6bb..0d91d5ea4e3 100644 --- a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpReceiverOverHTTP2.java +++ b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpReceiverOverHTTP2.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -38,6 +38,7 @@ import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.ErrorCode; +import org.eclipse.jetty.http2.IStream; import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; @@ -171,8 +172,10 @@ public class HttpReceiverOverHTTP2 extends HttpReceiver implements Stream.Listen @Override public boolean onIdleTimeout(Stream stream, Throwable x) { - responseFailure(x); - return true; + HttpExchange exchange = getHttpExchange(); + if (exchange == null) + return false; + return !exchange.abort(x); } @Override @@ -182,6 +185,12 @@ public class HttpReceiverOverHTTP2 extends HttpReceiver implements Stream.Listen callback.succeeded(); } + @Override + public void onClosed(Stream stream) + { + getHttpChannel().onStreamClosed((IStream)stream); + } + private void notifyContent(HttpExchange exchange, DataFrame frame, Callback callback) { contentNotifier.offer(new DataInfo(exchange, frame, callback)); @@ -204,21 +213,21 @@ public class HttpReceiverOverHTTP2 extends HttpReceiver implements Stream.Listen @Override protected Action process() { - DataInfo dataInfo; + if (dataInfo != null) + { + dataInfo.callback.succeeded(); + if (dataInfo.frame.isEndStream()) + return Action.SUCCEEDED; + } + synchronized (this) { dataInfo = queue.poll(); } if (dataInfo == null) - { - DataInfo prevDataInfo = this.dataInfo; - if (prevDataInfo != null && prevDataInfo.frame.isEndStream()) - return Action.SUCCEEDED; return Action.IDLE; - } - this.dataInfo = dataInfo; ByteBuffer buffer = dataInfo.frame.getData(); if (buffer.hasRemaining()) responseContent(dataInfo.exchange, buffer, this); @@ -235,13 +244,6 @@ public class HttpReceiverOverHTTP2 extends HttpReceiver implements Stream.Listen ((Retainable)callback).retain(); } - @Override - public void succeeded() - { - dataInfo.callback.succeeded(); - super.succeeded(); - } - @Override protected void onCompleteSuccess() { @@ -254,6 +256,14 @@ public class HttpReceiverOverHTTP2 extends HttpReceiver implements Stream.Listen dataInfo.callback.failed(failure); responseFailure(failure); } + + @Override + public boolean reset() + { + queue.clear(); + dataInfo = null; + return super.reset(); + } } private static class DataInfo diff --git a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpSenderOverHTTP2.java b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpSenderOverHTTP2.java index 4950c949d3d..e1078ad0976 100644 --- a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpSenderOverHTTP2.java +++ b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpSenderOverHTTP2.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -56,40 +56,57 @@ public class HttpSenderOverHTTP2 extends HttpSender String path = relativize(request.getPath()); HttpURI uri = HttpURI.createHttpURI(request.getScheme(), request.getHost(), request.getPort(), path, null, request.getQuery(), null); MetaData.Request metaData = new MetaData.Request(request.getMethod(), uri, HttpVersion.HTTP_2, request.getHeaders()); - Supplier trailers = request.getTrailers(); - metaData.setTrailerSupplier(trailers); - HeadersFrame headersFrame = new HeadersFrame(metaData, null, trailers == null && !content.hasContent()); - HttpChannelOverHTTP2 channel = getHttpChannel(); - Promise promise = new Promise() - { - @Override - public void succeeded(Stream stream) - { - channel.setStream(stream); - ((IStream)stream).setAttachment(channel); - stream.setIdleTimeout(request.getIdleTimeout()); + Supplier trailerSupplier = request.getTrailers(); + metaData.setTrailerSupplier(trailerSupplier); - if (content.hasContent() && !expects100Continue(request)) + HeadersFrame headersFrame; + Promise promise; + if (content.hasContent()) + { + headersFrame = new HeadersFrame(metaData, null, false); + promise = new HeadersPromise(request, callback) + { + @Override + public void succeeded(Stream stream) { - boolean advanced = content.advance(); - boolean lastContent = trailers == null && content.isLast(); - if (advanced || lastContent) + super.succeeded(stream); + if (expects100Continue(request)) { - DataFrame dataFrame = new DataFrame(stream.getId(), content.getByteBuffer(), lastContent); - stream.data(dataFrame, callback); - return; + // Don't send the content yet. + callback.succeeded(); + } + else + { + boolean advanced = content.advance(); + boolean lastContent = content.isLast(); + if (advanced || lastContent) + sendContent(stream, content, trailerSupplier, callback); + else + callback.succeeded(); } } - callback.succeeded(); - } - - @Override - public void failed(Throwable failure) + }; + } + else + { + HttpFields trailers = trailerSupplier == null ? null : trailerSupplier.get(); + boolean endStream = trailers == null || trailers.size() == 0; + headersFrame = new HeadersFrame(metaData, null, endStream); + promise = new HeadersPromise(request, callback) { - callback.failed(failure); - } - }; + @Override + public void succeeded(Stream stream) + { + super.succeeded(stream); + if (endStream) + callback.succeeded(); + else + sendTrailers(stream, trailers, callback); + } + }; + } // TODO optimize the send of HEADERS and DATA frames. + HttpChannelOverHTTP2 channel = getHttpChannel(); channel.getSession().newStream(headersFrame, promise, channel.getStreamListener()); } @@ -116,24 +133,67 @@ public class HttpSenderOverHTTP2 extends HttpSender { if (content.isConsumed()) { + // The superclass calls sendContent() one more time after the last content. + // This is necessary for HTTP/1.1 to generate the terminal chunk (with trailers), + // but it's not necessary for HTTP/2 so we just succeed the callback. callback.succeeded(); } else { Stream stream = getHttpChannel().getStream(); - Supplier trailers = exchange.getRequest().getTrailers(); - DataFrame frame = new DataFrame(stream.getId(), content.getByteBuffer(), trailers == null && content.isLast()); - stream.data(frame, callback); + Supplier trailerSupplier = exchange.getRequest().getTrailers(); + sendContent(stream, content, trailerSupplier, callback); } } - @Override - protected void sendTrailers(HttpExchange exchange, Callback callback) + private void sendContent(Stream stream, HttpContent content, Supplier trailerSupplier, Callback callback) { - Supplier trailers = exchange.getRequest().getTrailers(); - MetaData metaData = new MetaData(HttpVersion.HTTP_2, trailers.get()); - Stream stream = getHttpChannel().getStream(); + boolean lastContent = content.isLast(); + HttpFields trailers = null; + boolean endStream = false; + if (lastContent) + { + trailers = trailerSupplier == null ? null : trailerSupplier.get(); + endStream = trailers == null || trailers.size() == 0; + } + DataFrame dataFrame = new DataFrame(stream.getId(), content.getByteBuffer(), endStream); + HttpFields fTrailers = trailers; + stream.data(dataFrame, endStream || !lastContent ? callback : Callback.from(() -> sendTrailers(stream, fTrailers, callback), callback::failed)); + } + + private void sendTrailers(Stream stream, HttpFields trailers, Callback callback) + { + MetaData metaData = new MetaData(HttpVersion.HTTP_2, trailers); HeadersFrame trailersFrame = new HeadersFrame(stream.getId(), metaData, null, true); stream.headers(trailersFrame, callback); } + + private class HeadersPromise implements Promise + { + private final HttpRequest request; + private final Callback callback; + + private HeadersPromise(HttpRequest request, Callback callback) + { + this.request = request; + this.callback = callback; + } + + @Override + public void succeeded(Stream stream) + { + HttpChannelOverHTTP2 channel = getHttpChannel(); + channel.setStream(stream); + ((IStream)stream).setAttachment(channel); + long idleTimeout = request.getIdleTimeout(); + if (idleTimeout >= 0) + stream.setIdleTimeout(idleTimeout); + } + + @Override + public void failed(Throwable x) + { + callback.failed(x); + } + } } diff --git a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/AbstractTest.java b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/AbstractTest.java index 3216456974e..b6cd168abe3 100644 --- a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/AbstractTest.java +++ b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/AbstractTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/DirectHTTP2OverTLSTest.java b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/DirectHTTP2OverTLSTest.java index 4b110edd986..7039e74201e 100644 --- a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/DirectHTTP2OverTLSTest.java +++ b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/DirectHTTP2OverTLSTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,11 +18,8 @@ package org.eclipse.jetty.http2.client.http; -import static org.junit.jupiter.api.Assertions.assertEquals; - import java.io.IOException; import java.util.concurrent.TimeUnit; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -46,9 +43,10 @@ import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.junit.jupiter.api.AfterEach; - import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class DirectHTTP2OverTLSTest { private Server server; @@ -69,7 +67,7 @@ public class DirectHTTP2OverTLSTest HttpConfiguration httpsConfig = new HttpConfiguration(); httpsConfig.addCustomizer(new SecureRequestCustomizer()); ConnectionFactory h2 = new HTTP2ServerConnectionFactory(httpsConfig); - ConnectionFactory ssl = new SslConnectionFactory(newSslContextFactory(), h2.getProtocol()); + ConnectionFactory ssl = new SslConnectionFactory(newServerSslContextFactory(), h2.getProtocol()); connector = new ServerConnector(server, 1, 1, ssl, h2); server.addConnector(connector); server.setHandler(handler); @@ -82,7 +80,8 @@ public class DirectHTTP2OverTLSTest clientThreads.setName("client"); HttpClientTransportOverHTTP2 transport = new HttpClientTransportOverHTTP2(new HTTP2Client()); transport.setUseALPN(false); - client = new HttpClient(transport, newSslContextFactory()); + SslContextFactory sslContextFactory = newClientSslContextFactory(); + client = new HttpClient(transport, sslContextFactory); client.setExecutor(clientThreads); client.start(); } @@ -96,14 +95,27 @@ public class DirectHTTP2OverTLSTest server.stop(); } - private SslContextFactory newSslContextFactory() + private SslContextFactory.Server newServerSslContextFactory() + { + SslContextFactory.Server sslContextFactory = new SslContextFactory.Server(); + configureSslContextFactory(sslContextFactory); + return sslContextFactory; + } + + private SslContextFactory.Client newClientSslContextFactory() + { + SslContextFactory.Client sslContextFactory = new SslContextFactory.Client(); + configureSslContextFactory(sslContextFactory); + sslContextFactory.setEndpointIdentificationAlgorithm(null); + return sslContextFactory; + } + + private void configureSslContextFactory(SslContextFactory sslContextFactory) { - SslContextFactory sslContextFactory = new SslContextFactory(); sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks"); sslContextFactory.setKeyStorePassword("storepwd"); sslContextFactory.setUseCipherSuitesOrder(true); sslContextFactory.setCipherComparator(HTTP2Cipher.COMPARATOR); - return sslContextFactory; } @Test @@ -121,9 +133,9 @@ public class DirectHTTP2OverTLSTest }); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(HttpScheme.HTTPS.asString()) - .timeout(5, TimeUnit.SECONDS) - .send(); + .scheme(HttpScheme.HTTPS.asString()) + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(HttpStatus.OK_200, response.getStatus()); } diff --git a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/EmptyServerHandler.java b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/EmptyServerHandler.java index cd146e572d6..595f77ca933 100644 --- a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/EmptyServerHandler.java +++ b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/EmptyServerHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,7 +19,6 @@ package org.eclipse.jetty.http2.client.http; import java.io.IOException; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; diff --git a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2Test.java b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2Test.java index c159e34c200..9304ae519c8 100644 --- a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2Test.java +++ b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2Test.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,16 +18,6 @@ package org.eclipse.jetty.http2.client.http; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.greaterThanOrEqualTo; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertSame; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; @@ -47,8 +37,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.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -73,6 +61,7 @@ import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.ResetFrame; import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.generator.Generator; +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; @@ -87,6 +76,15 @@ import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class HttpClientTransportOverHTTP2Test extends AbstractTest { @Test @@ -133,10 +131,11 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest } }); - assertThrows(ExecutionException.class, ()->{ + assertThrows(ExecutionException.class, () -> + { client.newRequest("localhost", connector.getLocalPort()) - .onRequestCommit(request -> request.abort(new Exception("explicitly_aborted_by_test"))) - .send(); + .onRequestCommit(request -> request.abort(new Exception("explicitly_aborted_by_test"))) + .send(); }); assertTrue(resetLatch.await(5, TimeUnit.SECONDS)); } @@ -172,10 +171,11 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest } }); - assertThrows(ExecutionException.class, ()->{ + assertThrows(ExecutionException.class, () -> + { client.newRequest("localhost", connector.getLocalPort()) - .onResponseContent((response, buffer) -> response.abort(new Exception("explicitly_aborted_by_test"))) - .send(); + .onResponseContent((response, buffer) -> response.abort(new Exception("explicitly_aborted_by_test"))) + .send(); }); assertTrue(resetLatch.await(5, TimeUnit.SECONDS)); } @@ -186,7 +186,7 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest start(new AbstractHandler() { @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) { baseRequest.setHandled(true); HttpVersion version = HttpVersion.fromString(request.getProtocol()); @@ -195,12 +195,12 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest }); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .onRequestBegin(request -> - { - if (request.getVersion() != HttpVersion.HTTP_2) - request.abort(new Exception("Not a HTTP/2 request")); - }) - .send(); + .onRequestBegin(request -> + { + if (request.getVersion() != HttpVersion.HTTP_2) + request.abort(new Exception("Not an HTTP/2 request")); + }) + .send(); assertEquals(HttpStatus.OK_200, response.getStatus()); } @@ -282,14 +282,14 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest // Prime the connection to allow client and server prefaces to be exchanged. ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .path("/zero") - .timeout(5, TimeUnit.SECONDS) - .send(); + .path("/zero") + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(HttpStatus.OK_200, response.getStatus()); org.eclipse.jetty.client.api.Request request = client.newRequest("localhost", connector.getLocalPort()) - .method(HttpMethod.HEAD) - .path("/one"); + .method(HttpMethod.HEAD) + .path("/one"); request.send(result -> { if (result.isFailed()) @@ -312,7 +312,7 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest start(new AbstractHandler() { @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) { baseRequest.setHandled(true); assertEquals(path, request.getRequestURI()); @@ -321,9 +321,9 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest }); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .path("http://localhost:" + connector.getLocalPort() + path + "?" + query) - .timeout(5, TimeUnit.SECONDS) - .send(); + .path("http://localhost:" + connector.getLocalPort() + path + "?" + query) + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(HttpStatus.OK_200, response.getStatus()); } @@ -336,7 +336,7 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest start(new AbstractHandler() { @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) { baseRequest.setHandled(true); assertEquals(path, request.getRequestURI()); @@ -349,9 +349,9 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest int serverPort = proxyPort + 1; // Any port will do, just not the same as the proxy. ContentResponse response = client.newRequest("localhost", serverPort) - .path(path + "?" + query) - .timeout(5, TimeUnit.SECONDS) - .send(); + .path(path + "?" + query) + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(HttpStatus.OK_200, response.getStatus()); } @@ -381,11 +381,12 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest client.setIdleTimeout(idleTimeout); client.start(); - assertThrows(TimeoutException.class, ()->{ + assertThrows(TimeoutException.class, () -> + { client.newRequest("localhost", connector.getLocalPort()) - // Make sure the connection idle times out, not the stream. - .idleTimeout(2 * idleTimeout, TimeUnit.MILLISECONDS) - .send(); + // Make sure the connection idle times out, not the stream. + .idleTimeout(2 * idleTimeout, TimeUnit.MILLISECONDS) + .send(); }); assertTrue(resetLatch.await(5, TimeUnit.SECONDS)); @@ -411,11 +412,12 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest } }); - assertThrows(TimeoutException.class, ()->{ + assertThrows(TimeoutException.class, () -> + { long idleTimeout = 1000; client.newRequest("localhost", connector.getLocalPort()) - .idleTimeout(idleTimeout, TimeUnit.MILLISECONDS) - .send(); + .idleTimeout(idleTimeout, TimeUnit.MILLISECONDS) + .send(); }); assertTrue(resetLatch.await(5, TimeUnit.SECONDS)); @@ -444,11 +446,11 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest CountDownLatch resultLatch = new CountDownLatch(1); client.newRequest("localhost", server.getLocalPort()) - .send(result -> - { - if (result.getResponse().getStatus() == HttpStatus.OK_200) - resultLatch.countDown(); - }); + .send(result -> + { + if (result.getResponse().getStatus() == HttpStatus.OK_200) + resultLatch.countDown(); + }); ByteBufferPool byteBufferPool = new MappedByteBufferPool(); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); @@ -488,7 +490,9 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest { // Write the frames. for (ByteBuffer buffer : lease.getByteBuffers()) + { output.write(BufferUtil.toArray(buffer)); + } lease.recycle(); } catch (Throwable x) @@ -496,7 +500,7 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest x.printStackTrace(); } } - }, 4096, 8192); + }, 4096, 8192, RateControl.NO_RATE_CONTROL); parser.init(UnaryOperator.identity()); byte[] bytes = new byte[1024]; @@ -553,15 +557,14 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest }); ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .timeout(5, TimeUnit.SECONDS) - .send(); + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(HttpStatus.NO_CONTENT_204, response.getStatus()); // No logic on the client to discard content for no-content status codes. assertArrayEquals(bytes, response.getContent()); } - @Test public void testInvalidResponseHPack() throws Exception { @@ -586,12 +589,12 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest CountDownLatch latch = new CountDownLatch(1); client.newRequest("localhost", connector.getLocalPort()) - .timeout(5, TimeUnit.SECONDS) - .send(result -> - { - if (result.isFailed()) - latch.countDown(); - }); + .timeout(5, TimeUnit.SECONDS) + .send(result -> + { + if (result.isFailed()) + latch.countDown(); + }); assertTrue(latch.await(5, TimeUnit.SECONDS)); } @@ -601,7 +604,7 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest public void testExternalServer() throws Exception { HTTP2Client http2Client = new HTTP2Client(); - SslContextFactory sslContextFactory = new SslContextFactory(); + SslContextFactory sslContextFactory = new SslContextFactory.Client(); HttpClient httpClient = new HttpClient(new HttpClientTransportOverHTTP2(http2Client), sslContextFactory); Executor executor = new QueuedThreadPool(); httpClient.setExecutor(executor); diff --git a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/MaxConcurrentStreamsTest.java b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/MaxConcurrentStreamsTest.java index fe030fa838f..f05b0da7ae2 100644 --- a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/MaxConcurrentStreamsTest.java +++ b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/MaxConcurrentStreamsTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,6 +18,21 @@ package org.eclipse.jetty.http2.client.http; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.IntStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + import org.eclipse.jetty.client.AbstractConnectionPool; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.HttpDestination; @@ -43,25 +58,9 @@ import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.junit.jupiter.api.Test; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Queue; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ForkJoinPool; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.IntStream; - import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; - public class MaxConcurrentStreamsTest extends AbstractTest { private void start(int maxConcurrentStreams, Handler handler) throws Exception @@ -101,21 +100,21 @@ public class MaxConcurrentStreamsTest extends AbstractTest // First request is sent immediately. client.newRequest("localhost", connector.getLocalPort()) - .path("/first") - .send(result -> - { - if (result.isSucceeded()) - latch.countDown(); - }); + .path("/first") + .send(result -> + { + if (result.isSucceeded()) + latch.countDown(); + }); // Second request is queued. client.newRequest("localhost", connector.getLocalPort()) - .path("/second") - .send(result -> - { - if (result.isSucceeded()) - latch.countDown(); - }); + .path("/second") + .send(result -> + { + if (result.isSucceeded()) + latch.countDown(); + }); // When the first request returns, the second must be sent. assertTrue(latch.await(5 * sleep, TimeUnit.MILLISECONDS)); @@ -129,21 +128,21 @@ public class MaxConcurrentStreamsTest extends AbstractTest int iterations = 50; IntStream.range(0, concurrency).parallel().forEach(i -> - IntStream.range(0, iterations).forEach(j -> + IntStream.range(0, iterations).forEach(j -> + { + try { - try - { - ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .path("/" + i + "_" + j) - .timeout(5, TimeUnit.SECONDS) - .send(); - assertEquals(HttpStatus.OK_200, response.getStatus()); - } - catch (Throwable x) - { - throw new RuntimeException(x); - } - }) + ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) + .path("/" + i + "_" + j) + .timeout(5, TimeUnit.SECONDS) + .send(); + assertEquals(HttpStatus.OK_200, response.getStatus()); + } + catch (Throwable x) + { + throw new RuntimeException(x); + } + }) ); } @@ -184,22 +183,22 @@ public class MaxConcurrentStreamsTest extends AbstractTest if (connections.incrementAndGet() == 1) { client.newRequest(host, port) - .path("/2") - .send(result -> + .path("/2") + .send(result -> + { + if (result.isSucceeded()) { - if (result.isSucceeded()) - { - Response response2 = result.getResponse(); - if (response2.getStatus() == HttpStatus.OK_200) - latch.countDown(); - else - failures.add(new HttpResponseException("", response2)); - } + Response response2 = result.getResponse(); + if (response2.getStatus() == HttpStatus.OK_200) + latch.countDown(); else - { - failures.add(result.getFailure()); - } - }); + failures.add(new HttpResponseException("", response2)); + } + else + { + failures.add(result.getFailure()); + } + }); } super.onSettings(session, frame); } @@ -214,9 +213,9 @@ public class MaxConcurrentStreamsTest extends AbstractTest // This request will be queued and establish the connection, // which will trigger the send of the second request. ContentResponse response1 = client.newRequest(host, port) - .path("/1") - .timeout(5, TimeUnit.SECONDS) - .send(); + .path("/1") + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(HttpStatus.OK_200, response1.getStatus()); assertTrue(latch.await(5, TimeUnit.SECONDS), failures.toString()); @@ -247,20 +246,20 @@ public class MaxConcurrentStreamsTest extends AbstractTest for (int i = 0; i < maxStreams; ++i) { client.newRequest("localhost", connector.getLocalPort()) - .path("/" + i) - .send(null); + .path("/" + i) + .send(null); } // Send the request in excess. CountDownLatch latch = new CountDownLatch(1); String path = "/excess"; client.newRequest("localhost", connector.getLocalPort()) - .path(path) - .send(result -> - { - if (result.getResponse().getStatus() == HttpStatus.OK_200) - latch.countDown(); - }); + .path(path) + .send(result -> + { + if (result.getResponse().getStatus() == HttpStatus.OK_200) + latch.countDown(); + }); // The last exchange should remain in the queue. HttpDestinationOverHTTP2 destination = (HttpDestinationOverHTTP2)client.getDestination("http", "localhost", connector.getLocalPort()); @@ -288,9 +287,9 @@ public class MaxConcurrentStreamsTest extends AbstractTest // Send a request that is aborted while queued. client.newRequest("localhost", connector.getLocalPort()) - .path("/aborted") - .onRequestQueued(request -> request.abort(new Exception())) - .send(null); + .path("/aborted") + .onRequestQueued(request -> request.abort(new Exception())) + .send(null); // Must be able to send another request. ContentResponse response = client.newRequest("localhost", connector.getLocalPort()).path("/check").send(); @@ -318,8 +317,8 @@ public class MaxConcurrentStreamsTest extends AbstractTest for (int i = 0; i < maxConcurrent; ++i) { client.newRequest("localhost", connector.getLocalPort()) - .path("/" + i) - .send(result -> latch.countDown()); + .path("/" + i) + .send(result -> latch.countDown()); } // The requests should be processed in parallel, not sequentially. @@ -355,14 +354,14 @@ public class MaxConcurrentStreamsTest extends AbstractTest for (int k = 0; k < iterations; ++k) { client.newRequest("localhost", connector.getLocalPort()) - .path("/" + i + "_" + j + "_" + k) - .send(result -> - { - if (result.isFailed()) - failures.offer(result); - latch.countDown(); - }); - } + .path("/" + i + "_" + j + "_" + k) + .send(result -> + { + if (result.isFailed()) + failures.offer(result); + latch.countDown(); + }); + } }))); assertTrue(latch.await(total * 10, TimeUnit.MILLISECONDS)); @@ -370,7 +369,7 @@ public class MaxConcurrentStreamsTest extends AbstractTest } @Test - public void testTwoConcurrentStreamsFirstTimesOut() throws Exception + public void testTwoStreamsFirstTimesOut() throws Exception { long timeout = 1000; start(1, new EmptyServerHandler() @@ -386,17 +385,17 @@ public class MaxConcurrentStreamsTest extends AbstractTest CountDownLatch latch = new CountDownLatch(1); client.newRequest("localhost", connector.getLocalPort()) - .path("/1") - .timeout(timeout, TimeUnit.MILLISECONDS) - .send(result -> - { - if (result.isFailed()) - latch.countDown(); - }); + .path("/1") + .timeout(timeout, TimeUnit.MILLISECONDS) + .send(result -> + { + if (result.isFailed()) + latch.countDown(); + }); ContentResponse response2 = client.newRequest("localhost", connector.getLocalPort()) - .path("/2") - .send(); + .path("/2") + .send(); assertEquals(HttpStatus.OK_200, response2.getStatus()); assertTrue(latch.await(2 * timeout, TimeUnit.MILLISECONDS)); diff --git a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/PushedResourcesTest.java b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/PushedResourcesTest.java index 228438357ed..6facee32e11 100644 --- a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/PushedResourcesTest.java +++ b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/PushedResourcesTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,15 +18,10 @@ package org.eclipse.jetty.http2.client.http; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.IOException; import java.util.Random; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -50,9 +45,12 @@ import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Promise; - import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class PushedResourcesTest extends AbstractTest { @Test @@ -90,9 +88,9 @@ public class PushedResourcesTest extends AbstractTest HttpRequest request = (HttpRequest)client.newRequest("localhost", connector.getLocalPort()); ContentResponse response = request - .pushListener((mainRequest, pushedRequest) -> null) - .timeout(5, TimeUnit.SECONDS) - .send(); + .pushListener((mainRequest, pushedRequest) -> null) + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(HttpStatus.OK_200, response.getStatus()); assertTrue(latch.await(5, TimeUnit.SECONDS)); @@ -128,11 +126,11 @@ public class PushedResourcesTest extends AbstractTest else { baseRequest.getPushBuilder() - .path(path1) - .push(); + .path(path1) + .push(); baseRequest.getPushBuilder() - .path(path2) - .push(); + .path(path2) + .push(); response.getOutputStream().write(bytes); } } @@ -142,26 +140,26 @@ public class PushedResourcesTest extends AbstractTest CountDownLatch latch2 = new CountDownLatch(1); HttpRequest request = (HttpRequest)client.newRequest("localhost", connector.getLocalPort()); ContentResponse response = request - .pushListener((mainRequest, pushedRequest) -> new BufferingResponseListener() + .pushListener((mainRequest, pushedRequest) -> new BufferingResponseListener() + { + @Override + public void onComplete(Result result) { - @Override - public void onComplete(Result result) + assertTrue(result.isSucceeded()); + if (pushedRequest.getPath().equals(path1)) { - assertTrue(result.isSucceeded()); - if (pushedRequest.getPath().equals(path1)) - { - assertArrayEquals(pushBytes1, getContent()); - latch1.countDown(); - } - else if (pushedRequest.getPath().equals(path2)) - { - assertArrayEquals(pushBytes2, getContent()); - latch2.countDown(); - } + assertArrayEquals(pushBytes1, getContent()); + latch1.countDown(); } - }) - .timeout(5, TimeUnit.SECONDS) - .send(); + else if (pushedRequest.getPath().equals(path2)) + { + assertArrayEquals(pushBytes2, getContent()); + latch2.countDown(); + } + } + }) + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(HttpStatus.OK_200, response.getStatus()); assertArrayEquals(bytes, response.getContent()); @@ -196,20 +194,20 @@ public class PushedResourcesTest extends AbstractTest CountDownLatch latch = new CountDownLatch(1); HttpRequest request = (HttpRequest)client.newRequest("localhost", connector.getLocalPort()); ContentResponse response = request - .pushListener((mainRequest, pushedRequest) -> new BufferingResponseListener() + .pushListener((mainRequest, pushedRequest) -> new BufferingResponseListener() + { + @Override + public void onComplete(Result result) { - @Override - public void onComplete(Result result) - { - assertTrue(result.isSucceeded()); - assertEquals(oldPath, pushedRequest.getPath()); - assertEquals(newPath, result.getRequest().getPath()); - assertArrayEquals(pushBytes, getContent()); - latch.countDown(); - } - }) - .timeout(5, TimeUnit.SECONDS) - .send(); + assertTrue(result.isSucceeded()); + assertEquals(oldPath, pushedRequest.getPath()); + assertEquals(newPath, result.getRequest().getPath()); + assertArrayEquals(pushBytes, getContent()); + latch.countDown(); + } + }) + .timeout(5, TimeUnit.SECONDS) + .send(); assertEquals(HttpStatus.OK_200, response.getStatus()); assertTrue(latch.await(5, TimeUnit.SECONDS)); diff --git a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/RequestTrailersTest.java b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/RequestTrailersTest.java new file mode 100644 index 00000000000..46778f30d9a --- /dev/null +++ b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/RequestTrailersTest.java @@ -0,0 +1,190 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.client.http; + +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jetty.client.HttpRequest; +import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.client.util.DeferredContentProvider; +import org.eclipse.jetty.client.util.StringContentProvider; +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http.MetaData; +import org.eclipse.jetty.http2.api.Stream; +import org.eclipse.jetty.http2.api.server.ServerSessionListener; +import org.eclipse.jetty.http2.frames.DataFrame; +import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.util.Callback; +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 RequestTrailersTest extends AbstractTest +{ + @Test + public void testEmptyTrailersWithoutContent() throws Exception + { + testEmptyTrailers(null); + } + + @Test + public void testEmptyTrailersWithEagerContent() throws Exception + { + testEmptyTrailers("eager_content"); + } + + private void testEmptyTrailers(String content) throws Exception + { + CountDownLatch trailersLatch = new CountDownLatch(1); + start(new ServerSessionListener.Adapter() + { + @Override + public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) + { + MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields()); + HeadersFrame responseFrame = new HeadersFrame(stream.getId(), response, null, true); + stream.headers(responseFrame, Callback.NOOP); + return new Stream.Listener.Adapter() + { + @Override + public void onHeaders(Stream stream, HeadersFrame frame) + { + trailersLatch.countDown(); + } + }; + } + }); + + HttpRequest request = (HttpRequest)client.newRequest("localhost", connector.getLocalPort()); + HttpFields trailers = new HttpFields(); + request.trailers(() -> trailers); + if (content != null) + request.content(new StringContentProvider(content)); + + ContentResponse response = request.send(); + assertEquals(HttpStatus.OK_200, response.getStatus()); + + // The client must not send the trailers. + assertFalse(trailersLatch.await(1, TimeUnit.SECONDS)); + } + + @Test + public void testEmptyTrailersWithDeferredContent() throws Exception + { + start(new ServerSessionListener.Adapter() + { + @Override + public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) + { + return new Stream.Listener.Adapter() + { + @Override + public void onData(Stream stream, DataFrame dataFrame, Callback callback) + { + callback.succeeded(); + // We should not receive an empty HEADERS frame for the + // trailers, but instead a DATA frame with endStream=true. + if (dataFrame.isEndStream()) + { + MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields()); + HeadersFrame responseFrame = new HeadersFrame(stream.getId(), response, null, true); + stream.headers(responseFrame, Callback.NOOP); + } + } + }; + } + }); + + HttpRequest request = (HttpRequest)client.newRequest("localhost", connector.getLocalPort()); + HttpFields trailers = new HttpFields(); + request.trailers(() -> trailers); + DeferredContentProvider content = new DeferredContentProvider(); + request.content(content); + + CountDownLatch latch = new CountDownLatch(1); + request.send(result -> + { + assertTrue(result.isSucceeded()); + assertEquals(HttpStatus.OK_200, result.getResponse().getStatus()); + latch.countDown(); + }); + + // Send deferred content after a while. + Thread.sleep(1000); + content.offer(ByteBuffer.wrap("deferred_content".getBytes(StandardCharsets.UTF_8))); + content.close(); + + assertTrue(latch.await(5, TimeUnit.SECONDS)); + } + + @Test + public void testEmptyTrailersWithEmptyDeferredContent() throws Exception + { + start(new ServerSessionListener.Adapter() + { + @Override + public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) + { + return new Stream.Listener.Adapter() + { + @Override + public void onData(Stream stream, DataFrame dataFrame, Callback callback) + { + callback.succeeded(); + // We should not receive an empty HEADERS frame for the + // trailers, but instead a DATA frame with endStream=true. + if (dataFrame.isEndStream()) + { + MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields()); + HeadersFrame responseFrame = new HeadersFrame(stream.getId(), response, null, true); + stream.headers(responseFrame, Callback.NOOP); + } + } + }; + } + }); + + HttpRequest request = (HttpRequest)client.newRequest("localhost", connector.getLocalPort()); + HttpFields trailers = new HttpFields(); + request.trailers(() -> trailers); + DeferredContentProvider content = new DeferredContentProvider(); + request.content(content); + + CountDownLatch latch = new CountDownLatch(1); + request.send(result -> + { + assertTrue(result.isSucceeded()); + assertEquals(HttpStatus.OK_200, result.getResponse().getStatus()); + latch.countDown(); + }); + + // Send deferred content after a while. + Thread.sleep(1000); + content.close(); + + assertTrue(latch.await(5, TimeUnit.SECONDS)); + } +} diff --git a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/ResponseTrailerTest.java b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/ResponseTrailerTest.java new file mode 100644 index 00000000000..11727ee7425 --- /dev/null +++ b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/ResponseTrailerTest.java @@ -0,0 +1,127 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.client.http; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpURI; +import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http.MetaData; +import org.eclipse.jetty.http2.api.Session; +import org.eclipse.jetty.http2.api.Stream; +import org.eclipse.jetty.http2.client.HTTP2Client; +import org.eclipse.jetty.http2.frames.DataFrame; +import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Response; +import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.FuturePromise; +import org.eclipse.jetty.util.Promise; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class ResponseTrailerTest extends AbstractTest +{ + @Test + public void testEmptyTrailersWithoutContent() throws Exception + { + testEmptyTrailers(null); + } + + @Test + public void testEmptyTrailersWithContent() throws Exception + { + testEmptyTrailers("data"); + } + + public void testEmptyTrailers(String data) throws Exception + { + start(new EmptyServerHandler() + { + @Override + protected void service(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException + { + // Send empty response trailers. + Response jettyResponse = jettyRequest.getResponse(); + jettyResponse.setTrailers(HttpFields::new); + if (data != null) + response.getOutputStream().write(data.getBytes(StandardCharsets.US_ASCII)); + } + }); + + HTTP2Client http2Client = new HTTP2Client(); + http2Client.start(); + try + { + String host = "localhost"; + int port = connector.getLocalPort(); + InetSocketAddress address = new InetSocketAddress(host, port); + FuturePromise sessionPromise = new FuturePromise<>(); + http2Client.connect(address, new Session.Listener.Adapter(), sessionPromise); + Session session = sessionPromise.get(5, TimeUnit.SECONDS); + + HttpURI uri = new HttpURI("http://" + host + ":" + port + "/"); + MetaData.Request request = new MetaData.Request(HttpMethod.GET.asString(), uri, HttpVersion.HTTP_2, new HttpFields()); + HeadersFrame frame = new HeadersFrame(request, null, true); + BlockingQueue headers = new LinkedBlockingQueue<>(); + CountDownLatch latch = new CountDownLatch(1); + session.newStream(frame, new Promise.Adapter<>(), new Stream.Listener.Adapter() + { + @Override + public void onHeaders(Stream stream, HeadersFrame frame) + { + headers.offer(frame); + if (frame.isEndStream()) + latch.countDown(); + } + + @Override + public void onData(Stream stream, DataFrame frame, Callback callback) + { + super.onData(stream, frame, callback); + if (frame.isEndStream()) + latch.countDown(); + } + }); + + assertTrue(latch.await(5, TimeUnit.SECONDS)); + assertEquals(1, headers.size()); + frame = headers.poll(); + assertNotNull(frame); + assertTrue(frame.getMetaData().isResponse()); + } + finally + { + http2Client.stop(); + } + } +} diff --git a/jetty-http2/http2-http-client-transport/src/test/resources/jetty-logging.properties b/jetty-http2/http2-http-client-transport/src/test/resources/jetty-logging.properties index 287d28319e0..34929219c9d 100644 --- a/jetty-http2/http2-http-client-transport/src/test/resources/jetty-logging.properties +++ b/jetty-http2/http2-http-client-transport/src/test/resources/jetty-logging.properties @@ -1,4 +1,5 @@ org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog +#org.eclipse.jetty.LEVEL=DEBUG #org.eclipse.jetty.client.LEVEL=DEBUG org.eclipse.jetty.http2.hpack.LEVEL=INFO #org.eclipse.jetty.http2.LEVEL=DEBUG diff --git a/jetty-http2/http2-server/pom.xml b/jetty-http2/http2-server/pom.xml index 64dcaa4f2f1..63b726088a1 100644 --- a/jetty-http2/http2-server/pom.xml +++ b/jetty-http2/http2-server/pom.xml @@ -1,10 +1,9 @@ - + org.eclipse.jetty.http2 http2-parent - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 diff --git a/jetty-http2/http2-server/src/main/config/etc/jetty-http2.xml b/jetty-http2/http2-server/src/main/config/etc/jetty-http2.xml index 2de7f348d0a..56777719fdf 100644 --- a/jetty-http2/http2-server/src/main/config/etc/jetty-http2.xml +++ b/jetty-http2/http2-server/src/main/config/etc/jetty-http2.xml @@ -1,9 +1,6 @@ - - + - - - + diff --git a/jetty-http2/http2-server/src/main/config/etc/jetty-http2c.xml b/jetty-http2/http2-server/src/main/config/etc/jetty-http2c.xml index 4e8610cc1ef..37cb745fe0e 100644 --- a/jetty-http2/http2-server/src/main/config/etc/jetty-http2c.xml +++ b/jetty-http2/http2-server/src/main/config/etc/jetty-http2c.xml @@ -1,9 +1,6 @@ - - + - - - + diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java index 46d3e46960e..7b5319efbc5 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,6 +19,7 @@ package org.eclipse.jetty.http2.server; import java.io.IOException; +import java.time.Duration; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -34,7 +35,9 @@ import org.eclipse.jetty.http2.api.server.ServerSessionListener; 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.parser.RateControl; import org.eclipse.jetty.http2.parser.ServerParser; +import org.eclipse.jetty.http2.parser.WindowRateControl; import org.eclipse.jetty.io.Connection; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.server.AbstractConnectionFactory; @@ -43,7 +46,6 @@ import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.annotation.Name; -import org.eclipse.jetty.util.component.ContainerLifeCycle; import org.eclipse.jetty.util.component.Dumpable; import org.eclipse.jetty.util.component.LifeCycle; @@ -59,20 +61,23 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne private int maxHeaderBlockFragment = 0; private int maxFrameLength = Frame.DEFAULT_MAX_LENGTH; private int maxSettingsKeys = SettingsFrame.DEFAULT_MAX_KEYS; + private RateControl rateControl = new WindowRateControl(20, Duration.ofSeconds(1)); private FlowControlStrategy.Factory flowControlStrategyFactory = () -> new BufferingFlowControlStrategy(0.5F); private long streamIdleTimeout; public AbstractHTTP2ServerConnectionFactory(@Name("config") HttpConfiguration httpConfiguration) { - this(httpConfiguration,"h2"); + this(httpConfiguration, "h2"); } protected AbstractHTTP2ServerConnectionFactory(@Name("config") HttpConfiguration httpConfiguration, @Name("protocols") String... protocols) { super(protocols); - for (String p:protocols) + for (String p : protocols) + { if (!HTTP2ServerConnection.isSupportedProtocol(p)) - throw new IllegalArgumentException("Unsupported HTTP2 Protocol variant: "+p); + throw new IllegalArgumentException("Unsupported HTTP2 Protocol variant: " + p); + } addBean(sessionContainer); this.httpConfiguration = Objects.requireNonNull(httpConfiguration); addBean(httpConfiguration); @@ -177,6 +182,16 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne this.maxSettingsKeys = maxSettingsKeys; } + public RateControl getRateControl() + { + return rateControl; + } + + public void setRateControl(RateControl rateControl) + { + this.rateControl = rateControl; + } + /** * @return -1 * @deprecated feature removed, no replacement @@ -189,8 +204,8 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne /** * @param threads ignored - * @deprecated feature removed, no replacement * @throws UnsupportedOperationException when invoked + * @deprecated feature removed, no replacement */ @Deprecated public void setReservedThreads(int threads) @@ -236,21 +251,21 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne session.setInitialSessionRecvWindow(getInitialSessionRecvWindow()); session.setWriteThreshold(getHttpConfiguration().getOutputBufferSize()); - ServerParser parser = newServerParser(connector, session); + ServerParser parser = newServerParser(connector, session, getRateControl()); parser.setMaxFrameLength(getMaxFrameLength()); parser.setMaxSettingsKeys(getMaxSettingsKeys()); HTTP2Connection connection = new HTTP2ServerConnection(connector.getByteBufferPool(), connector.getExecutor(), - endPoint, httpConfiguration, parser, session, getInputBufferSize(), listener); + endPoint, httpConfiguration, parser, session, getInputBufferSize(), listener); connection.addListener(sessionContainer); return configure(connection, connector, endPoint); } protected abstract ServerSessionListener newSessionListener(Connector connector, EndPoint endPoint); - protected ServerParser newServerParser(Connector connector, ServerParser.Listener listener) + protected ServerParser newServerParser(Connector connector, ServerParser.Listener listener, RateControl rateControl) { - return new ServerParser(connector.getByteBufferPool(), listener, getMaxDynamicTableSize(), getHttpConfiguration().getRequestHeaderSize()); + return new ServerParser(connector.getByteBufferPool(), listener, getMaxDynamicTableSize(), getHttpConfiguration().getRequestHeaderSize(), rateControl); } @ManagedObject("The container of HTTP/2 sessions") @@ -288,14 +303,13 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne @Override public String dump() { - return ContainerLifeCycle.dump(this); + return Dumpable.dump(this); } @Override public void dump(Appendable out, String indent) throws IOException { - ContainerLifeCycle.dumpObject(out, this); - ContainerLifeCycle.dump(out, indent, sessions); + Dumpable.dumpObjects(out, indent, this, sessions); } @Override diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2CServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2CServerConnectionFactory.java index e495a11457d..4ed23cf2fea 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2CServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2CServerConnectionFactory.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -31,17 +31,16 @@ import org.eclipse.jetty.util.annotation.Name; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; - -/* ------------------------------------------------------------ */ -/** HTTP2 Clear Text Connection factory. +/** + * HTTP2 Clear Text Connection factory. *

        This extension of HTTP2ServerConnection Factory sets the * protocol name to "h2c" as used by the clear text upgrade mechanism * for HTTP2 and marks all TLS ciphers as unacceptable. *

        *

        If used in combination with a {@link HttpConnectionFactory} as the * default protocol, this factory can support the non-standard direct - * update mechanism, where a HTTP1 request of the form "PRI * HTTP/2.0" - * is used to trigger a switch to a HTTP2 connection. This approach + * update mechanism, where an HTTP1 request of the form "PRI * HTTP/2.0" + * is used to trigger a switch to an HTTP2 connection. This approach * allows a single port to accept either HTTP/1 or HTTP/2 direct * connections. */ @@ -51,15 +50,17 @@ public class HTTP2CServerConnectionFactory extends HTTP2ServerConnectionFactory public HTTP2CServerConnectionFactory(@Name("config") HttpConfiguration httpConfiguration) { - this(httpConfiguration,"h2c"); + this(httpConfiguration, "h2c"); } - + public HTTP2CServerConnectionFactory(@Name("config") HttpConfiguration httpConfiguration, @Name("protocols") String... protocols) { - super(httpConfiguration,protocols); - for (String p:protocols) + super(httpConfiguration, protocols); + for (String p : protocols) + { if (!HTTP2ServerConnection.isSupportedProtocol(p)) - throw new IllegalArgumentException("Unsupported HTTP2 Protocol variant: "+p); + throw new IllegalArgumentException("Unsupported HTTP2 Protocol variant: " + p); + } } @Override diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnection.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnection.java index 6eea1873892..f8dfdbf7d36 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnection.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnection.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -23,6 +23,7 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.util.ArrayDeque; import java.util.ArrayList; +import java.util.Base64; import java.util.Collection; import java.util.List; import java.util.Objects; @@ -55,7 +56,6 @@ import org.eclipse.jetty.io.Connection; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.HttpConfiguration; -import org.eclipse.jetty.util.B64Code; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.CountingCallback; @@ -64,12 +64,12 @@ import org.eclipse.jetty.util.TypeUtil; public class HTTP2ServerConnection extends HTTP2Connection implements Connection.UpgradeTo { /** - * @param protocol A HTTP2 protocol variant + * @param protocol An HTTP2 protocol variant * @return True if the protocol version is supported */ public static boolean isSupportedProtocol(String protocol) { - switch(protocol) + switch (protocol) { case "h2": case "h2-17": @@ -86,7 +86,7 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection return false; } } - + private final Queue channels = new ArrayDeque<>(); private final List upgradeFrames = new ArrayList<>(); private final AtomicLong totalRequests = new AtomicLong(); @@ -143,7 +143,9 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection { notifyAccept(getSession()); for (Frame frame : upgradeFrames) + { getSession().onFrame(frame); + } super.onOpen(); produce(); } @@ -231,11 +233,11 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection ISession session = getSession(); // Compute whether all requests are idle. boolean result = session.getStreams().stream() - .map(stream -> (IStream)stream) - .map(stream -> (HttpChannelOverHTTP2)stream.getAttachment()) - .filter(Objects::nonNull) - .map(HttpChannelOverHTTP2::isRequestIdle) - .reduce(true, Boolean::logicalAnd); + .map(stream -> (IStream)stream) + .map(stream -> (HttpChannelOverHTTP2)stream.getAttachment()) + .filter(Objects::nonNull) + .map(HttpChannelOverHTTP2::isRequestIdle) + .reduce(true, Boolean::logicalAnd); if (LOG.isDebugEnabled()) LOG.debug("{} idle timeout on {}: {}", result ? "Processed" : "Ignored", session, failure); return result; @@ -255,7 +257,9 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection { CountingCallback counter = new CountingCallback(callback, streams.size()); for (Stream stream : streams) + { onStreamFailure((IStream)stream, failure, counter); + } } } @@ -333,10 +337,10 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection if (settingsField == null) throw new BadMessageException("Missing " + HttpHeader.HTTP2_SETTINGS + " header"); String value = settingsField.getValue(); - final byte[] settings = B64Code.decodeRFC4648URL(value == null ? "" : value); + final byte[] settings = Base64.getUrlDecoder().decode(value == null ? "" : value); if (LOG.isDebugEnabled()) - LOG.debug("{} settings {}",this,TypeUtil.toHexString(settings)); + LOG.debug("{} settings {}", this, TypeUtil.toHexString(settings)); SettingsFrame settingsFrame = SettingsBodyParser.parseBody(BufferUtil.toBuffer(settings)); if (settingsFrame == null) diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java index 3feb1f12fad..22689d7af76 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -38,6 +38,7 @@ import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.NegotiatingServerConnection.CipherDiscriminator; import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.annotation.Name; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -53,7 +54,7 @@ public class HTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnectionF public HTTP2ServerConnectionFactory(@Name("config") HttpConfiguration httpConfiguration, @Name("protocols") String... protocols) { - super(httpConfiguration,protocols); + super(httpConfiguration, protocols); } @Override @@ -68,7 +69,7 @@ public class HTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnectionF // Implement 9.2.2 for draft 14 boolean acceptable = "h2-14".equals(protocol) || !(HTTP2Cipher.isBlackListProtocol(tlsProtocol) && HTTP2Cipher.isBlackListCipher(tlsCipher)); if (LOG.isDebugEnabled()) - LOG.debug("proto={} tls={} cipher={} 9.2.2-acceptable={}",protocol,tlsProtocol,tlsCipher,acceptable); + LOG.debug("proto={} tls={} cipher={} 9.2.2-acceptable={}", protocol, tlsProtocol, tlsCipher, acceptable); return acceptable; } @@ -116,7 +117,7 @@ public class HTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnectionF public void onClose(Session session, GoAwayFrame frame, Callback callback) { String reason = frame.tryConvertPayload(); - if (reason != null && !reason.isEmpty()) + if (!StringUtil.isEmpty(reason)) reason = " (" + reason + ")"; getConnection().onSessionFailure(new EofException(String.format("Close %s/%s", ErrorCode.toString(frame.getError(), null), reason)), callback); } diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java index c89c72ed9ca..9e657a9b464 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -32,6 +32,7 @@ import org.eclipse.jetty.http2.api.server.ServerSessionListener; import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.PushPromiseFrame; +import org.eclipse.jetty.http2.frames.ResetFrame; import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.frames.WindowUpdateFrame; import org.eclipse.jetty.http2.generator.Generator; @@ -139,6 +140,17 @@ public class HTTP2ServerSession extends HTTP2Session implements ServerParser.Lis } } + @Override + protected void onResetForUnknownStream(ResetFrame frame) + { + int streamId = frame.getStreamId(); + boolean closed = isClientStream(streamId) ? isRemoteStreamClosed(streamId) : isLocalStreamClosed(streamId); + if (closed) + notifyReset(this, frame); + else + onConnectionFailure(ErrorCode.PROTOCOL_ERROR.code, "unexpected_rst_stream_frame"); + } + @Override public void onPushPromise(PushPromiseFrame frame) { diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java index 3e76a2c703f..73919eb6500 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -127,16 +127,16 @@ public class HttpChannelOverHTTP2 extends HttpChannel implements Closeable, Writ } _delayedUntilContent = getHttpConfiguration().isDelayDispatchUntilContent() && - !endStream && !_expect100Continue; + !endStream && !_expect100Continue; if (LOG.isDebugEnabled()) { Stream stream = getStream(); LOG.debug("HTTP2 Request #{}/{}, delayed={}:{}{} {} {}{}{}", - stream.getId(), Integer.toHexString(stream.getSession().hashCode()), - _delayedUntilContent, System.lineSeparator(), - request.getMethod(), request.getURI(), request.getHttpVersion(), - System.lineSeparator(), fields); + stream.getId(), Integer.toHexString(stream.getSession().hashCode()), + _delayedUntilContent, System.lineSeparator(), + request.getMethod(), request.getURI(), request.getHttpVersion(), + System.lineSeparator(), fields); } return _delayedUntilContent ? null : this; @@ -166,9 +166,9 @@ public class HttpChannelOverHTTP2 extends HttpChannel implements Closeable, Writ { Stream stream = getStream(); LOG.debug("HTTP2 PUSH Request #{}/{}:{}{} {} {}{}{}", - stream.getId(), Integer.toHexString(stream.getSession().hashCode()), System.lineSeparator(), - request.getMethod(), request.getURI(), request.getHttpVersion(), - System.lineSeparator(), request.getFields()); + stream.getId(), Integer.toHexString(stream.getSession().hashCode()), System.lineSeparator(), + request.getMethod(), request.getURI(), request.getHttpVersion(), + System.lineSeparator(), request.getFields()); } return this; @@ -208,8 +208,8 @@ public class HttpChannelOverHTTP2 extends HttpChannel implements Closeable, Writ { Stream stream = getStream(); LOG.debug("HTTP2 Commit Response #{}/{}:{}{} {} {}{}{}", - stream.getId(), Integer.toHexString(stream.getSession().hashCode()), System.lineSeparator(), info.getHttpVersion(), info.getStatus(), info.getReason(), - System.lineSeparator(), info.getFields()); + stream.getId(), Integer.toHexString(stream.getSession().hashCode()), System.lineSeparator(), info.getHttpVersion(), info.getStatus(), info.getReason(), + System.lineSeparator(), info.getFields()); } } @@ -252,19 +252,19 @@ public class HttpChannelOverHTTP2 extends HttpChannel implements Closeable, Writ boolean endStream = frame.isEndStream(); if (endStream) { - boolean handle_content = onContentComplete(); - boolean handle_request = onRequestComplete(); - handle |= handle_content | handle_request; + boolean handleContent = onContentComplete(); + boolean handleRequest = onRequestComplete(); + handle |= handleContent | handleRequest; } if (LOG.isDebugEnabled()) { LOG.debug("HTTP2 Request #{}/{}: {} bytes of {} content, handle: {}", - stream.getId(), - Integer.toHexString(stream.getSession().hashCode()), - length, - endStream ? "last" : "some", - handle); + stream.getId(), + Integer.toHexString(stream.getSession().hashCode()), + length, + endStream ? "last" : "some", + handle); } boolean wasDelayed = _delayedUntilContent; @@ -282,8 +282,8 @@ public class HttpChannelOverHTTP2 extends HttpChannel implements Closeable, Writ { Stream stream = getStream(); LOG.debug("HTTP2 Request #{}/{}, trailers:{}{}", - stream.getId(), Integer.toHexString(stream.getSession().hashCode()), - System.lineSeparator(), trailers); + stream.getId(), Integer.toHexString(stream.getSession().hashCode()), + System.lineSeparator(), trailers); } boolean handle = onRequestComplete(); diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java index 5087f04435e..11cd845cce0 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -119,9 +119,17 @@ public class HttpTransportOverHTTP2 implements HttpTransport { if (lastContent) { - Supplier trailers = info.getTrailerSupplier(); - if (transportCallback.start(new SendTrailers(getCallback(), trailers), false)) - sendDataFrame(content, true, trailers == null, transportCallback); + HttpFields trailers = retrieveTrailers(); + if (trailers != null) + { + if (transportCallback.start(new SendTrailers(getCallback(), trailers), false)) + sendDataFrame(content, true, false, transportCallback); + } + else + { + if (transportCallback.start(getCallback(), false)) + sendDataFrame(content, true, true, transportCallback); + } } else { @@ -137,9 +145,17 @@ public class HttpTransportOverHTTP2 implements HttpTransport { if (lastContent) { - Supplier trailers = info.getTrailerSupplier(); - if (transportCallback.start(new SendTrailers(callback, trailers), true)) - sendHeadersFrame(info, trailers == null, transportCallback); + HttpFields trailers = retrieveTrailers(); + if (trailers != null) + { + if (transportCallback.start(new SendTrailers(callback, trailers), true)) + sendHeadersFrame(info, false, transportCallback); + } + else + { + if (transportCallback.start(callback, true)) + sendHeadersFrame(info, true, transportCallback); + } } else { @@ -160,16 +176,24 @@ public class HttpTransportOverHTTP2 implements HttpTransport { if (lastContent) { - Supplier trailers = metaData.getTrailerSupplier(); - SendTrailers sendTrailers = new SendTrailers(callback, trailers); - if (hasContent || trailers == null) + HttpFields trailers = retrieveTrailers(); + if (trailers != null) { - if (transportCallback.start(sendTrailers, false)) - sendDataFrame(content, true, trailers == null, transportCallback); + SendTrailers sendTrailers = new SendTrailers(callback, trailers); + if (hasContent) + { + if (transportCallback.start(sendTrailers, false)) + sendDataFrame(content, true, false, transportCallback); + } + else + { + sendTrailers.succeeded(); + } } else { - sendTrailers.succeeded(); + if (transportCallback.start(callback, false)) + sendDataFrame(content, true, true, transportCallback); } } else @@ -185,6 +209,17 @@ public class HttpTransportOverHTTP2 implements HttpTransport } } + private HttpFields retrieveTrailers() + { + Supplier supplier = metaData.getTrailerSupplier(); + if (supplier == null) + return null; + HttpFields trailers = supplier.get(); + if (trailers == null) + return null; + return trailers.size() == 0 ? null : trailers; + } + @Override public boolean isPushSupported() { @@ -226,9 +261,9 @@ public class HttpTransportOverHTTP2 implements HttpTransport if (LOG.isDebugEnabled()) { LOG.debug("HTTP2 Response #{}/{}:{}{} {}{}{}", - stream.getId(), Integer.toHexString(stream.getSession().hashCode()), - System.lineSeparator(), HttpVersion.HTTP_2, info.getStatus(), - System.lineSeparator(), info.getFields()); + stream.getId(), Integer.toHexString(stream.getSession().hashCode()), + System.lineSeparator(), HttpVersion.HTTP_2, info.getStatus(), + System.lineSeparator(), info.getFields()); } HeadersFrame frame = new HeadersFrame(stream.getId(), info, null, endStream); @@ -240,8 +275,8 @@ public class HttpTransportOverHTTP2 implements HttpTransport if (LOG.isDebugEnabled()) { LOG.debug("HTTP2 Response #{}/{}: {} content bytes{}", - stream.getId(), Integer.toHexString(stream.getSession().hashCode()), - content.remaining(), lastContent ? " (last chunk)" : ""); + stream.getId(), Integer.toHexString(stream.getSession().hashCode()), + content.remaining(), lastContent ? " (last chunk)" : ""); } DataFrame frame = new DataFrame(stream.getId(), content, endStream); stream.data(frame, callback); @@ -252,7 +287,7 @@ public class HttpTransportOverHTTP2 implements HttpTransport if (LOG.isDebugEnabled()) { LOG.debug("HTTP2 Response #{}/{}: trailers", - stream.getId(), Integer.toHexString(stream.getSession().hashCode())); + stream.getId(), Integer.toHexString(stream.getSession().hashCode())); } HeadersFrame frame = new HeadersFrame(stream.getId(), metaData, null, true); @@ -294,9 +329,9 @@ public class HttpTransportOverHTTP2 implements HttpTransport IStream stream = this.stream; if (LOG.isDebugEnabled()) LOG.debug("HTTP2 Response #{}/{} aborted", stream == null ? -1 : stream.getId(), - stream == null ? -1 : Integer.toHexString(stream.getSession().hashCode())); + stream == null ? -1 : Integer.toHexString(stream.getSession().hashCode())); if (stream != null) - stream.reset(new ResetFrame(stream.getId(), ErrorCode.INTERNAL_ERROR.code), Callback.NOOP); + stream.reset(new ResetFrame(stream.getId(), ErrorCode.CANCEL_STREAM_ERROR.code), Callback.NOOP); } private class TransportCallback implements Callback @@ -346,9 +381,9 @@ public class HttpTransportOverHTTP2 implements HttpTransport } if (LOG.isDebugEnabled()) LOG.debug("HTTP2 Response #{}/{} {} {}", - stream.getId(), Integer.toHexString(stream.getSession().hashCode()), - commit ? "commit" : "flush", - callback == null ? "failure" : "success"); + stream.getId(), Integer.toHexString(stream.getSession().hashCode()), + commit ? "commit" : "flush", + callback == null ? "failure" : "success"); if (callback != null) callback.succeeded(); } @@ -357,35 +392,20 @@ public class HttpTransportOverHTTP2 implements HttpTransport public void failed(Throwable failure) { boolean commit; - Callback callback = null; - synchronized (this) - { - commit = this.commit; - // Only fail pending writes, as we - // may need to write an error page. - if (state == State.WRITING) - { - this.state = State.FAILED; - callback = this.callback; - this.callback = null; - this.failure = failure; - } - } - if (LOG.isDebugEnabled()) - LOG.debug(String.format("HTTP2 Response #%d/%h %s %s", stream.getId(), stream.getSession(), commit ? "commit" : "flush", callback == null ? "ignored" : "failed"), failure); - if (callback != null) - callback.failed(failure); - } - - @Override - public InvocationType getInvocationType() - { Callback callback; synchronized (this) { + commit = this.commit; + this.state = State.FAILED; callback = this.callback; + this.callback = null; + this.failure = failure; } - return callback != null ? callback.getInvocationType() : Callback.super.getInvocationType(); + if (LOG.isDebugEnabled()) + LOG.debug(String.format("HTTP2 Response #%d/%h %s %s", stream.getId(), stream.getSession(), + commit ? "commit" : "flush", callback == null ? "ignored" : "failed"), failure); + if (callback != null) + callback.failed(failure); } private boolean onIdleTimeout(Throwable failure) @@ -406,11 +426,22 @@ public class HttpTransportOverHTTP2 implements HttpTransport } } if (LOG.isDebugEnabled()) - LOG.debug(String.format("HTTP2 Response #%d/%h idle timeout", stream.getId(), stream.getSession()), failure); + LOG.debug(String.format("HTTP2 Response #%d/%h idle timeout %s", stream.getId(), stream.getSession(), result ? "expired" : "ignored"), failure); if (result) callback.failed(failure); return result; } + + @Override + public InvocationType getInvocationType() + { + Callback callback; + synchronized (this) + { + callback = this.callback; + } + return callback != null ? callback.getInvocationType() : Callback.super.getInvocationType(); + } } private enum State @@ -420,9 +451,9 @@ public class HttpTransportOverHTTP2 implements HttpTransport private class SendTrailers extends Callback.Nested { - private final Supplier trailers; + private final HttpFields trailers; - private SendTrailers(Callback callback, Supplier trailers) + private SendTrailers(Callback callback, HttpFields trailers) { super(callback); this.trailers = trailers; @@ -431,15 +462,8 @@ public class HttpTransportOverHTTP2 implements HttpTransport @Override public void succeeded() { - if (trailers != null) - { - if (transportCallback.start(getCallback(), false)) - sendTrailersFrame(new MetaData(HttpVersion.HTTP_2, trailers.get()), transportCallback); - } - else - { - super.succeeded(); - } + if (transportCallback.start(getCallback(), false)) + sendTrailersFrame(new MetaData(HttpVersion.HTTP_2, trailers), transportCallback); } } } diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/RawHTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/RawHTTP2ServerConnectionFactory.java index 7a1c65293b3..c1d1a92dba9 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/RawHTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/RawHTTP2ServerConnectionFactory.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/AbstractServerTest.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/AbstractServerTest.java index 26423c54a7f..15c694254fa 100644 --- a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/AbstractServerTest.java +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/AbstractServerTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -23,7 +23,6 @@ import java.io.InputStream; import java.net.Socket; import java.net.SocketTimeoutException; import java.nio.ByteBuffer; - import javax.servlet.http.HttpServlet; import org.eclipse.jetty.http.HostPortHttpField; @@ -63,7 +62,7 @@ public class AbstractServerTest protected void startServer(ServerSessionListener listener) throws Exception { - prepareServer(new RawHTTP2ServerConnectionFactory(new HttpConfiguration(),listener)); + prepareServer(new RawHTTP2ServerConnectionFactory(new HttpConfiguration(), listener)); server.start(); } @@ -90,7 +89,7 @@ public class AbstractServerTest @AfterEach public void dispose() throws Exception { - if (server!=null) + if (server != null) server.stop(); } diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/CloseTest.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/CloseTest.java index 69caa8949a8..963591f41c1 100644 --- a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/CloseTest.java +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/CloseTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,9 +18,6 @@ package org.eclipse.jetty.http2.server; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.IOException; import java.io.OutputStream; import java.net.Socket; @@ -48,9 +45,11 @@ import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.RuntimeIOException; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; - import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class CloseTest extends AbstractServerTest { @Test diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/H2SpecServer.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/H2SpecServer.java index de99425b90b..97d0a86fa2d 100644 --- a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/H2SpecServer.java +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/H2SpecServer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2CServer.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2CServer.java index c1a183c7126..6a9527da0de 100644 --- a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2CServer.java +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2CServer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,20 +19,16 @@ package org.eclipse.jetty.http2.server; import java.io.IOException; -import java.net.Socket; import java.util.Date; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.eclipse.jetty.io.Connection; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConnectionFactory; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.server.SocketCustomizationListener; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.util.thread.QueuedThreadPool; @@ -42,20 +38,19 @@ public class HTTP2CServer extends Server { HttpConfiguration config = new HttpConfiguration(); // HTTP + HTTP/2 connector - + HttpConnectionFactory http1 = new HttpConnectionFactory(config); HTTP2CServerConnectionFactory http2c = new HTTP2CServerConnectionFactory(config); - ServerConnector connector = new ServerConnector(this,http1,http2c); + ServerConnector connector = new ServerConnector(this, http1, http2c); connector.setPort(port); addConnector(connector); ((QueuedThreadPool)getThreadPool()).setName("server"); setHandler(new SimpleHandler()); - } - public static void main(String... args ) throws Exception + public static void main(String... args) throws Exception { HTTP2CServer server = new HTTP2CServer(8080); server.start(); @@ -67,15 +62,15 @@ public class HTTP2CServer extends Server public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { baseRequest.setHandled(true); - String code=request.getParameter("code"); - if (code!=null) + String code = request.getParameter("code"); + if (code != null) response.setStatus(Integer.parseInt(code)); - response.setHeader("Custom","Value"); + response.setHeader("Custom", "Value"); response.setContentType("text/plain"); - String content = "Hello from Jetty using "+request.getProtocol() +"\n"; - content+="uri="+request.getRequestURI()+"\n"; - content+="date="+new Date()+"\n"; + String content = "Hello from Jetty using " + request.getProtocol() + "\n"; + content += "uri=" + request.getRequestURI() + "\n"; + content += "date=" + new Date() + "\n"; response.setContentLength(content.length()); response.getOutputStream().print(content); } diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2CServerTest.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2CServerTest.java index 649ea7048cb..48552abebac 100644 --- a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2CServerTest.java +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2CServerTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,12 +18,6 @@ package org.eclipse.jetty.http2.server; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; @@ -65,6 +59,12 @@ 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.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class HTTP2CServerTest extends AbstractServerTest { @BeforeEach @@ -120,8 +120,8 @@ public class HTTP2CServerTest extends AbstractServerTest try (Socket client = new Socket("localhost", connector.getLocalPort())) { OutputStream output = client.getOutputStream(); - output.write(("" + - "GET /one HTTP/1.1\r\n" + + output.write(( + "GET /one HTTP/1.1\r\n" + "Host: localhost\r\n" + "Connection: something, else, upgrade, HTTP2-Settings\r\n" + "Upgrade: h2c\r\n" + @@ -188,7 +188,7 @@ public class HTTP2CServerTest extends AbstractServerTest assertThat(content, containsString("Hello from Jetty using HTTP/1.1")); assertThat(content, containsString("uri=/one")); - // Send a HTTP/2 request. + // Send an HTTP/2 request. headersRef.set(null); dataRef.set(null); latchRef.set(new CountDownLatch(2)); @@ -198,7 +198,9 @@ public class HTTP2CServerTest extends AbstractServerTest MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP, new HostPortHttpField("localhost:" + connector.getLocalPort()), "/two", HttpVersion.HTTP_2, new HttpFields()); generator.control(lease, new HeadersFrame(3, metaData, null, true)); for (ByteBuffer buffer : lease.getByteBuffers()) + { output.write(BufferUtil.toArray(buffer)); + } output.flush(); parseResponse(client, parser); @@ -300,7 +302,7 @@ public class HTTP2CServerTest extends AbstractServerTest @Override public Connection newConnection(Connector connector, EndPoint endPoint) { - HttpConnection connection = new HttpConnection(getHttpConfiguration(), connector, endPoint,getHttpCompliance(),isRecordHttpComplianceViolations()) + HttpConnection connection = new HttpConnection(getHttpConfiguration(), connector, endPoint, getHttpCompliance(), isRecordHttpComplianceViolations()) { @Override public void onFillable() @@ -317,7 +319,7 @@ public class HTTP2CServerTest extends AbstractServerTest connector.setDefaultProtocol(connectionFactory.getProtocol()); connector.start(); - // Now send a HTTP/2 direct request, which + // Now send an HTTP/2 direct request, which // will have the PRI * HTTP/2.0 preface. byteBufferPool = new MappedByteBufferPool(); @@ -330,9 +332,11 @@ public class HTTP2CServerTest extends AbstractServerTest { OutputStream output = client.getOutputStream(); for (ByteBuffer buffer : lease.getByteBuffers()) + { output.write(BufferUtil.toArray(buffer)); + } - // We sent a HTTP/2 preface, but the server has no "h2c" connection + // We sent an HTTP/2 preface, but the server has no "h2c" connection // factory so it does not know how to handle this request. InputStream input = client.getInputStream(); diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java index a8334ca42fe..53bba437cd9 100644 --- a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,12 +18,6 @@ package org.eclipse.jetty.http2.server; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -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.assertTrue; - import java.io.IOException; import java.io.InterruptedIOException; import java.io.OutputStream; @@ -40,7 +34,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; @@ -73,15 +66,20 @@ import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.log.StacklessLogging; - import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +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.assertTrue; + public class HTTP2ServerTest extends AbstractServerTest { @Test public void testNoPrefaceBytes() throws Exception { - startServer(new HttpServlet(){}); + startServer(new HttpServlet() {}); // No preface bytes. MetaData.Request metaData = newRequest("GET", new HttpFields()); @@ -242,7 +240,7 @@ public class HTTP2ServerTest extends AbstractServerTest @Test public void testBadPingWrongPayload() throws Exception { - startServer(new HttpServlet(){}); + startServer(new HttpServlet() {}); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); generator.control(lease, new PrefaceFrame()); @@ -280,7 +278,7 @@ public class HTTP2ServerTest extends AbstractServerTest @Test public void testBadPingWrongStreamId() throws Exception { - startServer(new HttpServlet(){}); + startServer(new HttpServlet() {}); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); generator.control(lease, new PrefaceFrame()); @@ -344,7 +342,7 @@ public class HTTP2ServerTest extends AbstractServerTest @Override protected ChannelEndPoint newEndPoint(SocketChannel channel, ManagedSelector selectSet, SelectionKey key) throws IOException { - return new SocketChannelEndPoint(channel,selectSet,key,getScheduler()) + return new SocketChannelEndPoint(channel, selectSet, key, getScheduler()) { @Override public void write(Callback callback, ByteBuffer... buffers) throws IllegalStateException @@ -369,7 +367,9 @@ public class HTTP2ServerTest extends AbstractServerTest { OutputStream output = client.getOutputStream(); for (ByteBuffer buffer : lease.getByteBuffers()) + { output.write(BufferUtil.toArray(buffer)); + } // The server will close the connection abruptly since it // cannot write and therefore cannot even send the GO_AWAY. @@ -405,7 +405,9 @@ public class HTTP2ServerTest extends AbstractServerTest { OutputStream output = client.getOutputStream(); for (ByteBuffer buffer : lease.getByteBuffers()) + { output.write(BufferUtil.toArray(buffer)); + } output.flush(); Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter(), 4096, 8192); @@ -529,10 +531,10 @@ public class HTTP2ServerTest extends AbstractServerTest continuationFrameHeader.put(4, (byte)0); // Add a last, empty, CONTINUATION frame. ByteBuffer last = ByteBuffer.wrap(new byte[]{ - 0, 0, 0, // Length - (byte)FrameType.CONTINUATION.getType(), - (byte)Flags.END_HEADERS, - 0, 0, 0, 1 // Stream ID + 0, 0, 0, // Length + (byte)FrameType.CONTINUATION.getType(), + (byte)Flags.END_HEADERS, + 0, 0, 0, 1 // Stream ID }); lease.append(last, false); return lease; @@ -573,7 +575,9 @@ public class HTTP2ServerTest extends AbstractServerTest { OutputStream output = client.getOutputStream(); for (ByteBuffer buffer : lease.getByteBuffers()) + { output.write(BufferUtil.toArray(buffer)); + } output.flush(); assertTrue(serverLatch.await(5, TimeUnit.SECONDS)); diff --git a/jetty-http2/pom.xml b/jetty-http2/pom.xml index 1c711777008..c28be91ec37 100644 --- a/jetty-http2/pom.xml +++ b/jetty-http2/pom.xml @@ -3,7 +3,7 @@ jetty-project org.eclipse.jetty - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 diff --git a/jetty-infinispan/infinispan-common/pom.xml b/jetty-infinispan/infinispan-common/pom.xml new file mode 100644 index 00000000000..408015ecaa2 --- /dev/null +++ b/jetty-infinispan/infinispan-common/pom.xml @@ -0,0 +1,69 @@ + + + org.eclipse.jetty + infinispan-parent + 9.4.21-SNAPSHOT + + 4.0.0 + infinispan-common + Jetty :: Infinispan Session Manager Common + http://www.eclipse.org/jetty + + ${project.groupId}.infinispan.common + + + + install + + + org.apache.maven.plugins + maven-assembly-plugin + + + package + + single + + + + config + + + + + + + + + + org.infinispan + infinispan-core + ${infinispan.version} + true + + + org.infinispan.protostream + protostream + 4.2.2.Final + true + provided + + + org.eclipse.jetty + jetty-server + ${project.version} + + + org.infinispan + infinispan-client-hotrod + ${infinispan.version} + provided + + + org.infinispan + infinispan-remote-query-client + ${infinispan.version} + provided + + + diff --git a/jetty-infinispan/infinispan-common/src/main/config/etc/sessions/infinispan/infinispan-common.xml b/jetty-infinispan/infinispan-common/src/main/config/etc/sessions/infinispan/infinispan-common.xml new file mode 100644 index 00000000000..6745e570497 --- /dev/null +++ b/jetty-infinispan/infinispan-common/src/main/config/etc/sessions/infinispan/infinispan-common.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jetty-infinispan/infinispan-common/src/main/config/modules/sessions/infinispan/infinispan-common.mod b/jetty-infinispan/infinispan-common/src/main/config/modules/sessions/infinispan/infinispan-common.mod new file mode 100644 index 00000000000..3c588cc1b5c --- /dev/null +++ b/jetty-infinispan/infinispan-common/src/main/config/modules/sessions/infinispan/infinispan-common.mod @@ -0,0 +1,20 @@ +[description] +Common to all infinispan modules + +[tags] +session + +[depend] +sessions + +[lib] +lib/infinispan-common-${jetty.version}.jar +lib/infinispan/*.jar + +[ini] +infinispan.version?=9.4.8.Final + +[license] +Infinispan is an open source project hosted on Github and released under the Apache 2.0 license. +http://infinispan.org/ +http://www.apache.org/licenses/LICENSE-2.0.html diff --git a/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionData.java b/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionData.java new file mode 100644 index 00000000000..a5f73eb9e4c --- /dev/null +++ b/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionData.java @@ -0,0 +1,69 @@ +package org.eclipse.jetty.session.infinispan; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.util.Map; + +import org.eclipse.jetty.server.session.SessionData; +import org.eclipse.jetty.util.ClassLoadingObjectInputStream; + +/** + * InfinispanSessionData + * + * Specialization of SessionData to hold the attributes as a serialized byte + * array. This is necessary because to deserialize the attributes correctly, we + * need to know which classloader to use, which is normally provided as the + * thread context classloader. However, infinispan marshalling uses a thread + * pool and thus these threads have no knowledge of the correct classloader to + * use. + */ +public class InfinispanSessionData extends SessionData +{ + protected byte[] _serializedAttributes; + + public InfinispanSessionData(String id, String cpath, String vhost, long created, long accessed, long lastAccessed, long maxInactiveMs) + { + super(id, cpath, vhost, created, accessed, lastAccessed, maxInactiveMs); + } + + public InfinispanSessionData(String id, String cpath, String vhost, long created, long accessed, long lastAccessed, long maxInactiveMs, + Map attributes) + { + super(id, cpath, vhost, created, accessed, lastAccessed, maxInactiveMs, attributes); + } + + public byte[] getSerializedAttributes() + { + return _serializedAttributes; + } + + public void setSerializedAttributes(byte[] serializedAttributes) + { + _serializedAttributes = serializedAttributes; + } + + public void deserializeAttributes() throws ClassNotFoundException, IOException + { + if (_serializedAttributes == null) + return; + + try (ByteArrayInputStream bais = new ByteArrayInputStream(_serializedAttributes); + ClassLoadingObjectInputStream ois = new ClassLoadingObjectInputStream(bais)) + { + SessionData.deserializeAttributes(this, ois); + _serializedAttributes = null; + } + } + + public void serializeAttributes() throws IOException + { + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos)) + { + SessionData.serializeAttributes(this, oos); + _serializedAttributes = baos.toByteArray(); + } + } +} \ No newline at end of file diff --git a/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionDataStore.java b/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionDataStore.java new file mode 100644 index 00000000000..eb1e0b06ab9 --- /dev/null +++ b/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionDataStore.java @@ -0,0 +1,331 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.session.infinispan; + +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; + +import org.eclipse.jetty.server.session.AbstractSessionDataStore; +import org.eclipse.jetty.server.session.SessionData; +import org.eclipse.jetty.server.session.UnreadableSessionDataException; +import org.eclipse.jetty.util.annotation.ManagedAttribute; +import org.eclipse.jetty.util.annotation.ManagedObject; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.infinispan.commons.api.BasicCache; + +/** + * InfinispanSessionDataStore + */ +@ManagedObject +public class InfinispanSessionDataStore extends AbstractSessionDataStore +{ + private static final Logger LOG = Log.getLogger("org.eclipse.jetty.server.session"); + + /** + * Clustered cache of sessions + */ + private BasicCache _cache; + + private int _infinispanIdleTimeoutSec; + + private QueryManager _queryManager; + + private boolean _passivating; + + /** + * Get the clustered cache instance. + * + * @return the cache + */ + public BasicCache getCache() + { + return _cache; + } + + /** + * Set the clustered cache instance. + * + * @param cache the cache + */ + public void setCache(BasicCache cache) + { + this._cache = cache; + } + + public QueryManager getQueryManager() + { + return _queryManager; + } + + public void setQueryManager(QueryManager queryManager) + { + _queryManager = queryManager; + } + + /** + * @see org.eclipse.jetty.server.session.SessionDataStore#load(String) + */ + @Override + protected void doStart() throws Exception + { + super.doStart(); + if (_cache == null) + throw new IllegalStateException("No cache"); + + try + { + _passivating = false; + Class remoteClass = InfinispanSessionDataStore.class.getClassLoader().loadClass("org.infinispan.client.hotrod.RemoteCache"); + if (remoteClass.isAssignableFrom(_cache.getClass())) + _passivating = true; + } + catch (ClassNotFoundException e) + { + //expected if not running with remote cache + LOG.info("Hotrod classes not found, assuming infinispan in embedded mode"); + } + } + + @Override + public SessionData doLoad(String id) throws Exception + { + try + { + if (LOG.isDebugEnabled()) + LOG.debug("Loading session {} from infinispan", id); + + InfinispanSessionData sd = (InfinispanSessionData)_cache.get(getCacheKey(id)); + if (isPassivating() && sd != null) + { + if (LOG.isDebugEnabled()) + LOG.debug("Deserializing session attributes for {}", id); + sd.deserializeAttributes(); + } + + return sd; + } + catch (Exception e) + { + throw new UnreadableSessionDataException(id, _context, e); + } + } + + @Override + public boolean delete(String id) throws Exception + { + if (LOG.isDebugEnabled()) + LOG.debug("Deleting session with id {} from infinispan", id); + return (_cache.remove(getCacheKey(id)) != null); + } + + @Override + public Set doGetExpired(Set candidates) + { + + long now = System.currentTimeMillis(); + + Set expired = new HashSet<>(); + + /* + * 1. Select sessions managed by this node for our context that have expired + */ + if (candidates != null) + { + for (String candidate : candidates) + { + if (LOG.isDebugEnabled()) + LOG.debug("Checking expiry for candidate {}", candidate); + try + { + SessionData sd = load(candidate); + + //if the session no longer exists + if (sd == null) + { + expired.add(candidate); + if (LOG.isDebugEnabled()) + LOG.debug("Session {} does not exist in infinispan", candidate); + } + else + { + if (_context.getWorkerName().equals(sd.getLastNode())) + { + //we are its manager, add it to the expired set if it is expired now + if ((sd.getExpiry() > 0) && sd.getExpiry() <= now) + { + expired.add(candidate); + if (LOG.isDebugEnabled()) + LOG.debug("Session {} managed by {} is expired", candidate, _context.getWorkerName()); + } + } + else + { + //if we are not the session's manager, only expire it iff: + // this is our first expiryCheck and the session expired a long time ago + //or + //the session expired at least one graceperiod ago + if (_lastExpiryCheckTime <= 0) + { + if ((sd.getExpiry() > 0) && sd.getExpiry() < (now - (1000L * (3 * _gracePeriodSec)))) + expired.add(candidate); + } + else + { + if ((sd.getExpiry() > 0) && sd.getExpiry() < (now - (1000L * _gracePeriodSec))) + expired.add(candidate); + } + } + } + } + catch (Exception e) + { + LOG.warn("Error checking if candidate {} is expired", candidate, e); + } + } + } + + + /* + * 2. Select sessions for any node or context that have expired + * at least 1 graceperiod since the last expiry check. If we haven't done previous expiry checks, then check + * those that have expired at least 3 graceperiod ago. + */ + if (_queryManager != null) + { + long upperBound = now; + if (_lastExpiryCheckTime <= 0) + upperBound = (now - (3 * (1000L * _gracePeriodSec))); + else + upperBound = _lastExpiryCheckTime - (1000L * _gracePeriodSec); + + if (LOG.isDebugEnabled()) + LOG.debug("{}- Pass 2: Searching for sessions expired before {}", _context.getWorkerName(), upperBound); + + for (String sessionId : _queryManager.queryExpiredSessions(upperBound)) + { + expired.add(sessionId); + if (LOG.isDebugEnabled()) + LOG.debug("{}- Found expired sessionId=", _context.getWorkerName(), sessionId); + } + } + + return expired; + } + + @Override + public void doStore(String id, SessionData data, long lastSaveTime) throws Exception + { + //Put an idle timeout on the cache entry if the session is not immortal - + //if no requests arrive at any node before this timeout occurs, or no node + //scavenges the session before this timeout occurs, the session will be removed. + //NOTE: that no session listeners can be called for this. + if (data.getMaxInactiveMs() > 0 && getInfinispanIdleTimeoutSec() > 0) + _cache.put(getCacheKey(id), data, -1, TimeUnit.MILLISECONDS, getInfinispanIdleTimeoutSec(), TimeUnit.SECONDS); + else + _cache.put(getCacheKey(id), data); + + if (LOG.isDebugEnabled()) + LOG.debug("Session {} saved to infinispan, expires {} ", id, data.getExpiry()); + } + + public String getCacheKey(String id) + { + return _context.getCanonicalContextPath() + "_" + _context.getVhost() + "_" + id; + } + + @ManagedAttribute(value = "does store serialize sessions", readonly = true) + @Override + public boolean isPassivating() + { + return _passivating; + } + + @Override + public boolean exists(String id) throws Exception + { + // TODO find a better way to do this that does not pull into memory the + // whole session object + final AtomicBoolean reference = new AtomicBoolean(); + final AtomicReference exception = new AtomicReference<>(); + + Runnable load = new Runnable() + { + @Override + public void run() + { + try + { + SessionData sd = load(id); + if (sd == null) + { + reference.set(false); + return; + } + + if (sd.getExpiry() <= 0) + reference.set(true); //never expires + else + reference.set(sd.getExpiry() > System.currentTimeMillis()); //not expired yet + } + catch (Exception e) + { + exception.set(e); + } + } + }; + + //ensure the load runs in the context classloader scope + _context.run(load); + + if (exception.get() != null) + throw exception.get(); + + return reference.get(); + } + + @Override + public SessionData newSessionData(String id, long created, long accessed, long lastAccessed, long maxInactiveMs) + { + return new InfinispanSessionData(id, _context.getCanonicalContextPath(), _context.getVhost(), created, accessed, lastAccessed, maxInactiveMs); + } + + /** + * @param sec the infinispan-specific idle timeout in sec or 0 if not set + */ + public void setInfinispanIdleTimeoutSec(int sec) + { + _infinispanIdleTimeoutSec = sec; + } + + @ManagedAttribute(value = "infinispan idle timeout sec", readonly = true) + public int getInfinispanIdleTimeoutSec() + { + return _infinispanIdleTimeoutSec; + } + + @Override + public String toString() + { + return String.format("%s[cache=%s,idleTimeoutSec=%d]", super.toString(), (_cache == null ? "" : _cache.getName()), _infinispanIdleTimeoutSec); + } +} diff --git a/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionDataStoreFactory.java b/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionDataStoreFactory.java similarity index 77% rename from jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionDataStoreFactory.java rename to jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionDataStoreFactory.java index 969e4ffd855..faf275c17cb 100644 --- a/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionDataStoreFactory.java +++ b/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionDataStoreFactory.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,25 +16,23 @@ // ======================================================================== // - package org.eclipse.jetty.session.infinispan; import org.eclipse.jetty.server.session.AbstractSessionDataStoreFactory; -import org.eclipse.jetty.server.session.SessionHandler; +import org.eclipse.jetty.server.session.SessionData; import org.eclipse.jetty.server.session.SessionDataStore; +import org.eclipse.jetty.server.session.SessionHandler; import org.infinispan.commons.api.BasicCache; /** * InfinispanSessionDataStoreFactory - * - * */ public class InfinispanSessionDataStoreFactory extends AbstractSessionDataStoreFactory { int _infinispanIdleTimeoutSec; - BasicCache _cache; + BasicCache _cache; + protected QueryManager _queryManager; - /** * @return the infinispanIdleTimeoutSec */ @@ -51,41 +49,48 @@ public class InfinispanSessionDataStoreFactory extends AbstractSessionDataStoreF _infinispanIdleTimeoutSec = infinispanIdleTimeoutSec; } - /** + /** * @see org.eclipse.jetty.server.session.SessionDataStoreFactory#getSessionDataStore(org.eclipse.jetty.server.session.SessionHandler) */ @Override - public SessionDataStore getSessionDataStore (SessionHandler handler) throws Exception + public SessionDataStore getSessionDataStore(SessionHandler handler) throws Exception { InfinispanSessionDataStore store = new InfinispanSessionDataStore(); store.setGracePeriodSec(getGracePeriodSec()); store.setInfinispanIdleTimeoutSec(getInfinispanIdleTimeoutSec()); store.setCache(getCache()); store.setSavePeriodSec(getSavePeriodSec()); + store.setQueryManager(getQueryManager()); return store; } - + /** * Get the clustered cache instance. - * + * * @return the cache */ - public BasicCache getCache() + public BasicCache getCache() { return _cache; } - - /** * Set the clustered cache instance. - * + * * @param cache the cache */ - public void setCache (BasicCache cache) + public void setCache(BasicCache cache) { this._cache = cache; } + public QueryManager getQueryManager() + { + return _queryManager; + } + public void setQueryManager(QueryManager queryManager) + { + _queryManager = queryManager; + } } diff --git a/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionLegacyConverter.java b/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionLegacyConverter.java new file mode 100644 index 00000000000..b54263417fa --- /dev/null +++ b/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionLegacyConverter.java @@ -0,0 +1,224 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.session.infinispan; + +import java.util.List; +import java.util.Properties; +import java.util.stream.Collectors; + +import org.eclipse.jetty.server.session.SessionData; +import org.infinispan.client.hotrod.RemoteCache; +import org.infinispan.client.hotrod.RemoteCacheManager; +import org.infinispan.client.hotrod.configuration.ConfigurationBuilder; +import org.infinispan.client.hotrod.marshall.ProtoStreamMarshaller; +import org.infinispan.protostream.FileDescriptorSource; +import org.infinispan.protostream.SerializationContext; + +/** + * InfinispanSessionLegacyConverter + * + * Converts sessions saved in the old serialization + * format into the new protobuf-based serialization. + * + * Use the -Dverbose=true system property to + * print out more information about conversion failures. + */ +public class InfinispanSessionLegacyConverter +{ + RemoteCacheManager _protoManager; + RemoteCache _protoCache; + RemoteCacheManager _legacyManager; + RemoteCache _legacyCache; + boolean _verbose = false; + + public InfinispanSessionLegacyConverter(String cacheName) + throws Exception + { + //legacy serialization + _legacyManager = new RemoteCacheManager(); + _legacyCache = _legacyManager.getCache(cacheName); + + //new protobuf based + String host = System.getProperty("host", "127.0.0.1"); + _verbose = Boolean.getBoolean("verbose"); + + Properties properties = new Properties(); + ConfigurationBuilder clientBuilder = new ConfigurationBuilder(); + clientBuilder.withProperties(properties).addServer().host(host).marshaller(new ProtoStreamMarshaller()); + _protoManager = new RemoteCacheManager(clientBuilder.build()); + FileDescriptorSource fds = new FileDescriptorSource(); + fds.addProtoFiles("/session.proto"); + SerializationContext serCtx = ProtoStreamMarshaller.getSerializationContext(_protoManager); + serCtx.registerProtoFiles(fds); + serCtx.registerMarshaller(new SessionDataMarshaller()); + _protoCache = _protoManager.getCache(cacheName); + } + + /** + * Convert all sessions to protobuf format sessions. + */ + public void convert() + { + long conversions = 0; + List keys = null; + + //Get all sessions stored in the legacy format + try + { + keys = _legacyCache.keySet().stream().collect(Collectors.toList()); + } + catch (Exception e) + { + System.err.println("Error listing legacy sessions, assuming previously converted. Run again using 'check' argument to verify conversion"); + if (_verbose) + e.printStackTrace(); + System.exit(1); + } + + for (String s : keys) + { + SessionData data = null; + try + { + data = _legacyCache.get(s); + } + catch (Exception e) + { + System.err.println("Read of session " + s + " failed. Assuming session already converted and skipping."); + if (_verbose) + e.printStackTrace(); + continue; + } + + if (data != null) + { + try + { + _legacyCache.remove(s); + } + catch (Exception e) + { + System.err.println("Remove legacy session failed for " + s + " skipping conversion."); + if (_verbose) + e.printStackTrace(); + continue; + } + + try + { + InfinispanSessionData isd = new InfinispanSessionData(data.getId(), data.getContextPath(), data.getVhost(), data.getCreated(), + data.getAccessed(), data.getLastAccessed(), data.getMaxInactiveMs()); + isd.putAllAttributes(data.getAllAttributes()); + isd.setExpiry(data.getExpiry()); + isd.setCookieSet(data.getCookieSet()); + isd.setLastSaved(data.getLastSaved()); + isd.setLastNode(data.getLastNode()); + // now write it out to the protobuf format + _protoCache.put(s, isd); + System.err.println("Converted " + s); + conversions++; + } + catch (Exception e) + { + if (_verbose) + e.printStackTrace(); + System.err.println("Conversion failed for " + s + " re-instating legacy session."); + try + { + _legacyCache.put(s, data); + } + catch (Exception x) + { + System.err.println("FAILED REINSTATING SESSION " + s + ". ABORTING."); + x.printStackTrace(); + System.exit(1); + } + } + } + else + System.err.println("Unreadable legacy session " + s); + } + + System.err.println("Total sessions converted: " + conversions); + } + + /** + * Retrieve the sessions using protobuf format and print them out to + * confirm they're ok. + */ + public void checkConverted() + { + List keys = null; + try + { + keys = _protoCache.keySet().stream().collect(Collectors.toList()); + } + catch (Exception e) + { + System.err.println("Unable to read converted sessions, assuming still in legacy format. Run again without 'check' option to convert."); + e.printStackTrace(); + System.exit(1); + } + + for (String s : keys) + { + InfinispanSessionData converted = _protoCache.get(s); + if (converted != null) + { + System.err.println("OK: " + converted); + converted.getKeys().stream().forEach((ss) -> System.err.println(ss + ":" + converted.getAttribute(ss))); + } + else + System.err.println("Failed: " + s); + } + + System.err.println("Total converted sessions: " + keys.size()); + } + + public static final void usage() + { + System.err.println("Usage: InfinispanSessionLegacyConverter [-Dhost=127.0.0.1] [-Dverbose=true] [check]"); + } + + public static final void main(String... args) + { + if (args == null || args.length < 1) + { + usage(); + System.exit(1); + } + + try + { + InfinispanSessionLegacyConverter converter = new InfinispanSessionLegacyConverter(args[0]); + + if (args.length == 1) + converter.convert(); + else if (args[1].equals("check")) + converter.checkConverted(); + else + usage(); + } + catch (Exception e) + { + System.err.println("Conversion failure"); + e.printStackTrace(); + } + } +} diff --git a/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/NullQueryManagerFactory.java b/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/NullQueryManagerFactory.java new file mode 100644 index 00000000000..764ac2405bf --- /dev/null +++ b/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/NullQueryManagerFactory.java @@ -0,0 +1,36 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.session.infinispan; + +import org.eclipse.jetty.server.session.SessionData; +import org.infinispan.commons.api.BasicCache; + +/** + * NullQueryManagerFactory + * + * Trivial impl of the QueryManagerFactory that does not support doing queries. + */ +public class NullQueryManagerFactory implements QueryManagerFactory +{ + @Override + public QueryManager getQueryManager(BasicCache cache) + { + return null; + } +} diff --git a/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/AnyLiteral.java b/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/QueryManager.java similarity index 69% rename from jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/AnyLiteral.java rename to jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/QueryManager.java index 83eb00c8c6c..4250553aec2 100644 --- a/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/AnyLiteral.java +++ b/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/QueryManager.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,13 +16,13 @@ // ======================================================================== // -package org.eclipse.jetty.cdi.core; +package org.eclipse.jetty.session.infinispan; -import javax.enterprise.inject.Any; -import javax.enterprise.util.AnnotationLiteral; +import java.util.Set; -@SuppressWarnings("serial") -public class AnyLiteral extends AnnotationLiteral +public interface QueryManager { - public static final AnyLiteral INSTANCE = new AnyLiteral(); + Set queryExpiredSessions(); + + Set queryExpiredSessions(long currentTime); } diff --git a/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/QueryManagerFactory.java b/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/QueryManagerFactory.java new file mode 100644 index 00000000000..589bcd960ca --- /dev/null +++ b/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/QueryManagerFactory.java @@ -0,0 +1,27 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.session.infinispan; + +import org.eclipse.jetty.server.session.SessionData; +import org.infinispan.commons.api.BasicCache; + +public interface QueryManagerFactory +{ + QueryManager getQueryManager(BasicCache cache); +} diff --git a/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/SessionDataMarshaller.java b/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/SessionDataMarshaller.java new file mode 100644 index 00000000000..7a16fcf1265 --- /dev/null +++ b/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/SessionDataMarshaller.java @@ -0,0 +1,106 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.session.infinispan; + +import java.io.IOException; + +import org.infinispan.protostream.MessageMarshaller; + +/** + * SessionDataMarshaller + * + * A marshaller for converting a SessionData object into protobuf format which + * gives greater control over serialization/deserialization. We use that extra + * control to ensure that session attributes can be deserialized using either + * the container class loader or the webapp classloader, as appropriate. + */ +public class SessionDataMarshaller implements MessageMarshaller +{ + /** + * The version of the serializer. + */ + private static final int VERSION = 0; + + @Override + public Class getJavaClass() + { + return InfinispanSessionData.class; + } + + @Override + public String getTypeName() + { + return "org_eclipse_jetty_session_infinispan.InfinispanSessionData"; + } + + @Override + public InfinispanSessionData readFrom(ProtoStreamReader in) throws IOException + { + int version = in.readInt("version");// version of serialized session + String id = in.readString("id"); // session id + String cpath = in.readString("contextPath"); // context path + String vhost = in.readString("vhost"); // first vhost + + long accessed = in.readLong("accessed");// accessTime + long lastAccessed = in.readLong("lastAccessed"); // lastAccessTime + long created = in.readLong("created"); // time created + long cookieSet = in.readLong("cookieSet");// time cookie was set + String lastNode = in.readString("lastNode"); // name of last node + // managing + + long expiry = in.readLong("expiry"); + long maxInactiveMs = in.readLong("maxInactiveMs"); + + InfinispanSessionData sd = new InfinispanSessionData(id, cpath, vhost, created, accessed, lastAccessed, maxInactiveMs); + sd.setCookieSet(cookieSet); + sd.setLastNode(lastNode); + sd.setExpiry(expiry); + + if (version == 0) + { + byte[] attributeArray = in.readBytes("attributes"); + sd.setSerializedAttributes(attributeArray); + return sd; + } + else + throw new IOException("Unrecognized infinispan session version " + version); + } + + @Override + public void writeTo(ProtoStreamWriter out, InfinispanSessionData sdata) throws IOException + { + out.writeInt("version", VERSION); + out.writeString("id", sdata.getId()); // session id + out.writeString("contextPath", sdata.getContextPath()); // context path + out.writeString("vhost", sdata.getVhost()); // first vhost + + out.writeLong("accessed", sdata.getAccessed());// accessTime + out.writeLong("lastAccessed", sdata.getLastAccessed()); // lastAccessTime + out.writeLong("created", sdata.getCreated()); // time created + out.writeLong("cookieSet", sdata.getCookieSet());// time cookie was set + out.writeString("lastNode", sdata.getLastNode()); // name of last node + // managing + + out.writeLong("expiry", sdata.getExpiry()); + out.writeLong("maxInactiveMs", sdata.getMaxInactiveMs()); + + sdata.serializeAttributes(); + out.writeBytes("attributes", sdata.getSerializedAttributes()); + } +} diff --git a/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/WebAppMarshaller.java b/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/WebAppMarshaller.java similarity index 85% rename from jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/WebAppMarshaller.java rename to jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/WebAppMarshaller.java index 741b2d0a074..be10dcbab0a 100644 --- a/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/WebAppMarshaller.java +++ b/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/WebAppMarshaller.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -21,46 +21,44 @@ package org.eclipse.jetty.session.infinispan; import org.infinispan.commons.marshall.jboss.AbstractJBossMarshaller; import org.jboss.marshalling.ContextClassResolver; - /** * WebAppMarshaller * * An implementation of the AbstractJBossMarshaller code that is just * enough to provide a ContextClassResolver that will use the Thread Context Classloader - * in order to deserialize session attribute classes. - * + * in order to deserialize session attribute classes. + * * This is necessary because the standard infinispan marshaller (GenericJBossMarshaller) uses the * classloader of the loader that loaded itself. When using the infinispan module in Jetty, all of * the infinispan classes will be on the container classpath. That means that the GenericJBossMarshaller * returns the container classloader which is unable to load any webapp classes. This class ensures * that it is always the webapp's classloader that will be used. - * + * * In order to use this class, you should put a hotrod-client.properties file into the * ${jetty.base}/resources directory that contains this line: - * + * * infinispan.client.hotrod.marshaller=org.eclipse.jetty.session.infinispan.WebAppMarshaller - * + * * You will also need to add the following lines to a context xml file for your webapp to * permit the webapp's classloader to see the org.eclipse.jetty.session.infinispan classes for * the deserialization to work correctly: - * - * <Call name="prependServerClass"> - * <Arg>-org.eclipse.jetty.session.infinispan.</Arg> - * </Call> * + * <Call name="prependServerClass"> + * <Arg>-org.eclipse.jetty.session.infinispan.</Arg> + * </Call> */ -public class WebAppMarshaller extends AbstractJBossMarshaller +@Deprecated +public class WebAppMarshaller extends AbstractJBossMarshaller { /** * WebAppContextClassResolver * * Provides the Thread Context Classloader to use for deserializing. - * */ public static class WebAppContextClassResolver extends ContextClassResolver { - public WebAppContextClassResolver () + public WebAppContextClassResolver() { super(); } @@ -72,13 +70,9 @@ public class WebAppMarshaller extends AbstractJBossMarshaller } } - - - public WebAppMarshaller () + public WebAppMarshaller() { super(); - baseCfg.setClassResolver(new WebAppContextClassResolver()); + baseCfg.setClassResolver(new WebAppContextClassResolver()); } - - } diff --git a/jetty-infinispan/infinispan-common/src/main/resources/session.proto b/jetty-infinispan/infinispan-common/src/main/resources/session.proto new file mode 100644 index 00000000000..ecadbaaf66c --- /dev/null +++ b/jetty-infinispan/infinispan-common/src/main/resources/session.proto @@ -0,0 +1,19 @@ +package org_eclipse_jetty_session_infinispan; + +message InfinispanSessionData +{ + required int32 version = 1; + required string id = 2; + required string contextPath = 3; + required string vhost = 4; + + required sint64 accessed = 5; + required sint64 lastAccessed = 6; + required sint64 created = 7; + required sint64 cookieSet = 8; + required string lastNode = 9; + + required sint64 expiry = 10; + required sint64 maxInactiveMs = 11; + required bytes attributes = 12; +} \ No newline at end of file diff --git a/jetty-infinispan/infinispan-embedded-query/pom.xml b/jetty-infinispan/infinispan-embedded-query/pom.xml new file mode 100644 index 00000000000..61e81cef992 --- /dev/null +++ b/jetty-infinispan/infinispan-embedded-query/pom.xml @@ -0,0 +1,118 @@ + + + org.eclipse.jetty + infinispan-parent + 9.4.21-SNAPSHOT + + 4.0.0 + infinispan-embedded-query + Jetty :: Infinispan Session Manager Embedded with Querying + http://www.eclipse.org/jetty + + ${project.groupId}.infinispan.embedded.query + + + install + + + org.apache.maven.plugins + maven-dependency-plugin + + + build-deps-file + generate-resources + + list + + + false + ${project.build.directory}/deps.txt + true + org.eclipse.jetty,javax.servlet,org.slf4j + true + runtime + + + + + + org.apache.maven.plugins + maven-antrun-plugin + + + process-deps + process-resources + + run + + + + + + + + + + process-mod + process-resources + + run + + + + + + + + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + package + + single + + + + src/main/assembly/config.xml + + + + + + + + + + org.eclipse.jetty + infinispan-common + ${project.version} + + + org.infinispan + infinispan-core + + + org.infinispan + infinispan-commons + + + + + org.infinispan + infinispan-query + ${infinispan.version} + + + org.eclipse.jetty.toolchain + jetty-test-helper + test + + + diff --git a/jetty-infinispan/infinispan-embedded-query/src/main/assembly/config.xml b/jetty-infinispan/infinispan-embedded-query/src/main/assembly/config.xml new file mode 100644 index 00000000000..d9db9a74ef2 --- /dev/null +++ b/jetty-infinispan/infinispan-embedded-query/src/main/assembly/config.xml @@ -0,0 +1,27 @@ + + + config + false + + jar + + + + src/main/config-template + + + ** + + + **/infinispan-embedded-query-libs.mod + + + + target + modules/sessions/infinispan/embedded + + infinispan-embedded-query-libs.mod + + + + diff --git a/jetty-infinispan/infinispan-embedded-query/src/main/config-template/etc/sessions/infinispan/infinispan-embedded-query.xml b/jetty-infinispan/infinispan-embedded-query/src/main/config-template/etc/sessions/infinispan/infinispan-embedded-query.xml new file mode 100644 index 00000000000..d295643b4c2 --- /dev/null +++ b/jetty-infinispan/infinispan-embedded-query/src/main/config-template/etc/sessions/infinispan/infinispan-embedded-query.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + expiry + + + + + + + + + + + + + + + + /etc/infinispan.xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + jetty-query-sessions + + + + + + + + + + diff --git a/jetty-infinispan/infinispan-embedded-query/src/main/config-template/modules/infinispan-embedded-query.mod b/jetty-infinispan/infinispan-embedded-query/src/main/config-template/modules/infinispan-embedded-query.mod new file mode 100644 index 00000000000..60607ab4f5f --- /dev/null +++ b/jetty-infinispan/infinispan-embedded-query/src/main/config-template/modules/infinispan-embedded-query.mod @@ -0,0 +1,20 @@ +[description] +Enables querying with the Infinispan cache + +[tags] +session + +[provides] +infinispan-embedded + +[depends] +sessions/infinispan/embedded/infinispan-embedded-query-libs + +[lib] +lib/infinispan/*.jar +lib/infinispan-embedded-query-${jetty.version}.jar + +[xml] +etc/sessions/infinispan/infinispan-embedded-query.xml +etc/sessions/infinispan/infinispan-common.xml + diff --git a/jetty-infinispan/infinispan-embedded-query/src/main/config-template/modules/sessions/infinispan/embedded/infinispan-embedded-query-libs.mod b/jetty-infinispan/infinispan-embedded-query/src/main/config-template/modules/sessions/infinispan/embedded/infinispan-embedded-query-libs.mod new file mode 100644 index 00000000000..05f4038a0d2 --- /dev/null +++ b/jetty-infinispan/infinispan-embedded-query/src/main/config-template/modules/sessions/infinispan/embedded/infinispan-embedded-query-libs.mod @@ -0,0 +1,14 @@ +[description] +The Infinispan query libraries + +[tags] +3rdparty +infinispan + + +[license] +Infinispan is an open source project hosted on Github and released under the Apache 2.0 license. +http://infinispan.org/ +http://www.apache.org/licenses/LICENSE-2.0.html + + diff --git a/jetty-infinispan/infinispan-embedded-query/src/main/java/org/eclipse/jetty/session/infinispan/EmbeddedQueryManager.java b/jetty-infinispan/infinispan-embedded-query/src/main/java/org/eclipse/jetty/session/infinispan/EmbeddedQueryManager.java new file mode 100644 index 00000000000..621d003d185 --- /dev/null +++ b/jetty-infinispan/infinispan-embedded-query/src/main/java/org/eclipse/jetty/session/infinispan/EmbeddedQueryManager.java @@ -0,0 +1,42 @@ +package org.eclipse.jetty.session.infinispan; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.eclipse.jetty.server.session.SessionData; +import org.infinispan.Cache; +import org.infinispan.query.Search; +import org.infinispan.query.dsl.Query; +import org.infinispan.query.dsl.QueryFactory; + +public class EmbeddedQueryManager implements QueryManager +{ + private Cache _cache; + + public EmbeddedQueryManager(Cache cache) + { + _cache = cache; + } + + @Override + public Set queryExpiredSessions(long time) + { + QueryFactory qf = Search.getQueryFactory(_cache); + Query q = qf.from(SessionData.class).select("id").having("expiry").lte(time).build(); + + List list = q.list(); + Set ids = new HashSet<>(); + for (Object[] sl : list) + { + ids.add((String)sl[0]); + } + return ids; + } + + @Override + public Set queryExpiredSessions() + { + return queryExpiredSessions(System.currentTimeMillis()); + } +} diff --git a/jetty-infinispan/infinispan-embedded-query/src/main/java/org/eclipse/jetty/session/infinispan/EmbeddedQueryManagerFactory.java b/jetty-infinispan/infinispan-embedded-query/src/main/java/org/eclipse/jetty/session/infinispan/EmbeddedQueryManagerFactory.java new file mode 100644 index 00000000000..77820bc0dd1 --- /dev/null +++ b/jetty-infinispan/infinispan-embedded-query/src/main/java/org/eclipse/jetty/session/infinispan/EmbeddedQueryManagerFactory.java @@ -0,0 +1,18 @@ +package org.eclipse.jetty.session.infinispan; + +import org.eclipse.jetty.server.session.SessionData; +import org.infinispan.Cache; +import org.infinispan.commons.api.BasicCache; + +public class EmbeddedQueryManagerFactory implements QueryManagerFactory +{ + + @Override + public QueryManager getQueryManager(BasicCache cache) + { + if (!(cache instanceof Cache)) + throw new IllegalArgumentException("Argument was not of type Cache"); + + return new EmbeddedQueryManager((Cache)cache); + } +} diff --git a/jetty-infinispan/infinispan-embedded-query/src/test/java/org/eclipse/jetty/server/session/infinispan/EmbeddedQueryManagerTest.java b/jetty-infinispan/infinispan-embedded-query/src/test/java/org/eclipse/jetty/server/session/infinispan/EmbeddedQueryManagerTest.java new file mode 100644 index 00000000000..a0599054ea8 --- /dev/null +++ b/jetty-infinispan/infinispan-embedded-query/src/test/java/org/eclipse/jetty/server/session/infinispan/EmbeddedQueryManagerTest.java @@ -0,0 +1,109 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.server.session.infinispan; + +import java.lang.annotation.ElementType; +import java.util.HashSet; +import java.util.Properties; +import java.util.Random; +import java.util.Set; + +import org.eclipse.jetty.server.session.SessionData; +import org.eclipse.jetty.session.infinispan.EmbeddedQueryManager; +import org.eclipse.jetty.session.infinispan.QueryManager; +import org.eclipse.jetty.toolchain.test.MavenTestingUtils; +import org.hibernate.search.cfg.Environment; +import org.hibernate.search.cfg.SearchMapping; +import org.infinispan.Cache; +import org.infinispan.configuration.cache.Configuration; +import org.infinispan.configuration.cache.ConfigurationBuilder; +import org.infinispan.configuration.cache.Index; +import org.infinispan.configuration.global.GlobalConfigurationBuilder; +import org.infinispan.manager.DefaultCacheManager; +import org.infinispan.manager.EmbeddedCacheManager; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class EmbeddedQueryManagerTest +{ + public static final String DEFAULT_CACHE_NAME = "session_test_cache"; + + @Test + public void test() throws Exception + { + + String _name = DEFAULT_CACHE_NAME + System.currentTimeMillis(); + EmbeddedCacheManager _manager; + + _manager = new DefaultCacheManager(new GlobalConfigurationBuilder().globalJmxStatistics().allowDuplicateDomains(true).build()); + + //TODO verify that this is being indexed properly, if you change expiry to something that is not a valid field it still passes the tests + SearchMapping mapping = new SearchMapping(); + mapping.entity(SessionData.class).indexed().providedId().property("expiry", ElementType.FIELD).field(); + Properties properties = new Properties(); + properties.put(Environment.MODEL_MAPPING, mapping); + properties.put("hibernate.search.default.indexBase", MavenTestingUtils.getTargetTestingDir().getAbsolutePath()); + + Configuration dcc = _manager.getDefaultCacheConfiguration(); + ConfigurationBuilder b = new ConfigurationBuilder(); + if (dcc != null) + b = b.read(dcc); + + b.indexing().index(Index.ALL).addIndexedEntity(SessionData.class).withProperties(properties); + Configuration c = b.build(); + + _manager.defineConfiguration(_name, c); + Cache _cache = _manager.getCache(_name); + + //put some sessions into the cache + int numSessions = 10; + long currentTime = 500; + int maxExpiryTime = 1000; + Set expiredSessions = new HashSet<>(); + Random r = new Random(); + + for (int i = 0; i < numSessions; i++) + { + //create new sessiondata with random expiry time + long expiryTime = r.nextInt(maxExpiryTime); + SessionData sd = new SessionData("sd" + i, "", "", 0, 0, 0, 0); + sd.setExpiry(expiryTime); + + //if this entry has expired add it to expiry list + if (expiryTime <= currentTime) + expiredSessions.add("sd" + i); + + //add to cache + _cache.put("sd" + i, sd); + } + + //run the query + QueryManager qm = new EmbeddedQueryManager(_cache); + Set queryResult = qm.queryExpiredSessions(currentTime); + + // Check that the result is correct + assertEquals(expiredSessions.size(), queryResult.size()); + for (String s : expiredSessions) + { + assertTrue(queryResult.contains(s)); + } + } +} diff --git a/jetty-infinispan/infinispan-embedded/pom.xml b/jetty-infinispan/infinispan-embedded/pom.xml new file mode 100644 index 00000000000..26c6a2ad58b --- /dev/null +++ b/jetty-infinispan/infinispan-embedded/pom.xml @@ -0,0 +1,105 @@ + + + org.eclipse.jetty + infinispan-parent + 9.4.21-SNAPSHOT + + 4.0.0 + infinispan-embedded + pom + Jetty :: Infinispan Session Manager Embedded + http://www.eclipse.org/jetty + + ${project.groupId}.infinispan.embedded + + + install + + + org.apache.maven.plugins + maven-dependency-plugin + + + build-deps-file + generate-resources + + list + + + false + ${project.build.directory}/deps.txt + true + org.eclipse.jetty,javax.servlet,org.slf4j + true + runtime + + + + + + org.apache.maven.plugins + maven-antrun-plugin + + + process-deps + process-resources + + run + + + + + + + + + + process-mod + process-resources + + run + + + + + + + + + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + package + + single + + + + src/main/assembly/config.xml + + + + + + + + + + org.eclipse.jetty + infinispan-common + ${project.version} + + + org.infinispan + infinispan-core + ${infinispan.version} + + + diff --git a/jetty-infinispan/infinispan-embedded/src/main/assembly/config.xml b/jetty-infinispan/infinispan-embedded/src/main/assembly/config.xml new file mode 100644 index 00000000000..491f84e6116 --- /dev/null +++ b/jetty-infinispan/infinispan-embedded/src/main/assembly/config.xml @@ -0,0 +1,27 @@ + + + config + false + + jar + + + + src/main/config-templates + + + ** + + + **/infinispan-embedded-libs.mod + + + + target + modules/sessions/infinispan/embedded + + infinispan-embedded-libs.mod + + + + diff --git a/jetty-infinispan/infinispan-embedded/src/main/config-templates/etc/sessions/infinispan/infinispan-embedded.xml b/jetty-infinispan/infinispan-embedded/src/main/config-templates/etc/sessions/infinispan/infinispan-embedded.xml new file mode 100644 index 00000000000..f3cf9069b47 --- /dev/null +++ b/jetty-infinispan/infinispan-embedded/src/main/config-templates/etc/sessions/infinispan/infinispan-embedded.xml @@ -0,0 +1,16 @@ + + + + + + + + + /etc/infinispan.xml + + + + + + + diff --git a/jetty-infinispan/infinispan-embedded/src/main/config-templates/modules/infinispan-embedded.mod b/jetty-infinispan/infinispan-embedded/src/main/config-templates/modules/infinispan-embedded.mod new file mode 100644 index 00000000000..8d5d0cfa25c --- /dev/null +++ b/jetty-infinispan/infinispan-embedded/src/main/config-templates/modules/infinispan-embedded.mod @@ -0,0 +1,10 @@ +[description] +Setup infinispan embedded without querying + +[tags] +session + +[xml] +etc/sessions/infinispan/infinispan-embedded.xml +etc/sessions/infinispan/infinispan-common.xml + diff --git a/jetty-infinispan/infinispan-embedded/src/main/config-templates/modules/session-store-infinispan-embedded.mod b/jetty-infinispan/infinispan-embedded/src/main/config-templates/modules/session-store-infinispan-embedded.mod new file mode 100644 index 00000000000..1d2e9da7b87 --- /dev/null +++ b/jetty-infinispan/infinispan-embedded/src/main/config-templates/modules/session-store-infinispan-embedded.mod @@ -0,0 +1,24 @@ +[description] +Enables session data store in a local Infinispan cache + +[tags] +session + +[provides] +session-store + +[depend] +sessions/infinispan/infinispan-common +infinispan-embedded +sessions/infinispan/embedded/infinispan-embedded-libs + +[files] +basehome:modules/sessions/infinispan/embedded/infinispan.xml|etc/infinispan.xml + +[ini] +infinispan.version?=9.4.8.Final + +[ini-template] +#jetty.session.infinispan.idleTimeout.seconds=0 +#jetty.session.gracePeriod.seconds=3600 +#jetty.session.savePeriod.seconds=0 diff --git a/jetty-infinispan/infinispan-embedded/src/main/config-templates/modules/sessions/infinispan/embedded/infinispan-embedded-libs.mod b/jetty-infinispan/infinispan-embedded/src/main/config-templates/modules/sessions/infinispan/embedded/infinispan-embedded-libs.mod new file mode 100644 index 00000000000..c8c02f8cae2 --- /dev/null +++ b/jetty-infinispan/infinispan-embedded/src/main/config-templates/modules/sessions/infinispan/embedded/infinispan-embedded-libs.mod @@ -0,0 +1,16 @@ +[description] +The Infinispan embedded libraries + +[tags] +3rdparty +infinispan + +[depends] +sessions/infinispan/embedded/infinispan-embedded-serverclasses + +[license] +Infinispan is an open source project hosted on Github and released under the Apache 2.0 license. +http://infinispan.org/ +http://www.apache.org/licenses/LICENSE-2.0.html + + diff --git a/jetty-infinispan/infinispan-embedded/src/main/config-templates/modules/sessions/infinispan/embedded/infinispan-embedded-serverclasses.mod b/jetty-infinispan/infinispan-embedded/src/main/config-templates/modules/sessions/infinispan/embedded/infinispan-embedded-serverclasses.mod new file mode 100644 index 00000000000..b36937e1c6c --- /dev/null +++ b/jetty-infinispan/infinispan-embedded/src/main/config-templates/modules/sessions/infinispan/embedded/infinispan-embedded-serverclasses.mod @@ -0,0 +1,12 @@ +[description] +Hides Infinispan classes from webapp. + +[tags] +session +3rdparty +infinispan + + +[ini] +## Hide the infinispan libraries from deployed webapps +jetty.webapp.addServerClasses+=,${jetty.base.uri}/lib/infinispan/ diff --git a/jetty-infinispan/src/main/config/modules/session-store-infinispan-embedded/infinispan-embedded.xml b/jetty-infinispan/infinispan-embedded/src/main/config-templates/modules/sessions/infinispan/embedded/infinispan.xml similarity index 90% rename from jetty-infinispan/src/main/config/modules/session-store-infinispan-embedded/infinispan-embedded.xml rename to jetty-infinispan/infinispan-embedded/src/main/config-templates/modules/sessions/infinispan/embedded/infinispan.xml index 5adc356b1f6..07d8ca214cb 100644 --- a/jetty-infinispan/src/main/config/modules/session-store-infinispan-embedded/infinispan-embedded.xml +++ b/jetty-infinispan/infinispan-embedded/src/main/config-templates/modules/sessions/infinispan/embedded/infinispan.xml @@ -2,4 +2,4 @@ - + \ No newline at end of file diff --git a/jetty-infinispan/infinispan-remote-query/pom.xml b/jetty-infinispan/infinispan-remote-query/pom.xml new file mode 100644 index 00000000000..f36cc86d8b0 --- /dev/null +++ b/jetty-infinispan/infinispan-remote-query/pom.xml @@ -0,0 +1,153 @@ + + + org.eclipse.jetty + infinispan-parent + 9.4.21-SNAPSHOT + + 4.0.0 + infinispan-remote-query + Jetty :: Infinispan Session Manager Remote + http://www.eclipse.org/jetty + + ${project.groupId}.infinispan.remote.query + + + install + + + org.apache.maven.plugins + maven-dependency-plugin + + + build-deps-file + generate-resources + + list + + + false + ${project.build.directory}/deps.txt + true + org.eclipse.jetty,javax.servlet + true + runtime + + + + + + org.apache.maven.plugins + maven-antrun-plugin + + + process-deps + process-resources + + run + + + + + + + + + + + process-mod + process-resources + + run + + + + + + + + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + package + + single + + + + src/main/assembly/config.xml + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + true + + + + + + + org.eclipse.jetty + infinispan-common + ${project.version} + + + org.infinispan + infinispan-core + + + org.infinispan + infinispan-commons + + + + + org.infinispan + infinispan-query + ${infinispan.version} + + + org.infinispan + infinispan-client-hotrod + ${infinispan.version} + + + org.infinispan + infinispan-remote-query-client + ${infinispan.version} + + + + + remote + + + hotrod.enabled + true + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + false + + + + + + + diff --git a/jetty-infinispan/infinispan-remote-query/src/main/assembly/config.xml b/jetty-infinispan/infinispan-remote-query/src/main/assembly/config.xml new file mode 100644 index 00000000000..270dcfad382 --- /dev/null +++ b/jetty-infinispan/infinispan-remote-query/src/main/assembly/config.xml @@ -0,0 +1,27 @@ + + + config + false + + jar + + + + src/main/config-template + + + ** + + + **/infinispan-remote-query-libs.mod + + + + target + modules/sessions/infinispan/remote + + infinispan-remote-query-libs.mod + + + + diff --git a/jetty-infinispan/infinispan-remote-query/src/main/config-template/etc/sessions/infinispan/infinispan-remote-query.xml b/jetty-infinispan/infinispan-remote-query/src/main/config-template/etc/sessions/infinispan/infinispan-remote-query.xml new file mode 100644 index 00000000000..5df051b455a --- /dev/null +++ b/jetty-infinispan/infinispan-remote-query/src/main/config-template/etc/sessions/infinispan/infinispan-remote-query.xml @@ -0,0 +1,101 @@ + + + + + + + + + + org.eclipse.jetty.server.session.SessionData + + + + expiry + + + + + + + + + + + + + /resources/hotrod-client.properties + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /session.proto + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jetty-infinispan/infinispan-remote-query/src/main/config-template/modules/infinispan-remote-query.mod b/jetty-infinispan/infinispan-remote-query/src/main/config-template/modules/infinispan-remote-query.mod new file mode 100644 index 00000000000..7cb7c40ec30 --- /dev/null +++ b/jetty-infinispan/infinispan-remote-query/src/main/config-template/modules/infinispan-remote-query.mod @@ -0,0 +1,22 @@ +[description] +Enables querying with a remote Infinispan cache + +[tags] +session + +[provides] +infinispan-remote + +[depends] +sessions/infinispan/remote/infinispan-remote-query-libs + +[files] +basehome:modules/sessions/infinispan/remote/other_proto_marshallers.xml|etc/other_proto_marshallers.xml + +[lib] +lib/infinispan-remote-query-${jetty.version}.jar + +[xml] +etc/sessions/infinispan/infinispan-remote-query.xml +etc/other_proto_marshallers.xml +etc/sessions/infinispan/infinispan-common.xml diff --git a/jetty-infinispan/infinispan-remote-query/src/main/config-template/modules/sessions/infinispan/remote/infinispan-remote-query-libs.mod b/jetty-infinispan/infinispan-remote-query/src/main/config-template/modules/sessions/infinispan/remote/infinispan-remote-query-libs.mod new file mode 100644 index 00000000000..50cb76896f8 --- /dev/null +++ b/jetty-infinispan/infinispan-remote-query/src/main/config-template/modules/sessions/infinispan/remote/infinispan-remote-query-libs.mod @@ -0,0 +1,13 @@ +[description] +The Infinispan remote query libraries + +[tags] +3rdparty +infinispan + +[license] +Infinispan is an open source project hosted on Github and released under the Apache 2.0 license. +http://infinispan.org/ +http://www.apache.org/licenses/LICENSE-2.0.html + + diff --git a/jetty-infinispan/infinispan-remote-query/src/main/config-template/modules/sessions/infinispan/remote/other_proto_marshallers.xml b/jetty-infinispan/infinispan-remote-query/src/main/config-template/modules/sessions/infinispan/remote/other_proto_marshallers.xml new file mode 100644 index 00000000000..312ac64549c --- /dev/null +++ b/jetty-infinispan/infinispan-remote-query/src/main/config-template/modules/sessions/infinispan/remote/other_proto_marshallers.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + diff --git a/jetty-infinispan/infinispan-remote-query/src/main/java/org/eclipse/jetty/session/infinispan/RemoteQueryManager.java b/jetty-infinispan/infinispan-remote-query/src/main/java/org/eclipse/jetty/session/infinispan/RemoteQueryManager.java new file mode 100644 index 00000000000..5cf40613a41 --- /dev/null +++ b/jetty-infinispan/infinispan-remote-query/src/main/java/org/eclipse/jetty/session/infinispan/RemoteQueryManager.java @@ -0,0 +1,67 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.session.infinispan; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.eclipse.jetty.server.session.SessionData; +import org.infinispan.client.hotrod.RemoteCache; +import org.infinispan.client.hotrod.Search; +import org.infinispan.query.dsl.Query; +import org.infinispan.query.dsl.QueryFactory; + +/** + * RemoteQueryManager + * + * A QueryManager impl that supports doing queries against remote infinispan server. + */ +public class RemoteQueryManager implements QueryManager +{ + private RemoteCache _cache; + + public RemoteQueryManager(RemoteCache cache) + { + _cache = cache; + } + + @Override + public Set queryExpiredSessions(long time) + { + // TODO can the QueryFactory be created only once + QueryFactory qf = Search.getQueryFactory(_cache); + Query q = qf.from(InfinispanSessionData.class).select("id").having("expiry").lte(time).build(); + + List list = q.list(); + Set ids = new HashSet<>(); + for (Object[] sl : list) + { + ids.add((String)sl[0]); + } + + return ids; + } + + @Override + public Set queryExpiredSessions() + { + return queryExpiredSessions(System.currentTimeMillis()); + } +} diff --git a/jetty-infinispan/infinispan-remote-query/src/main/java/org/eclipse/jetty/session/infinispan/RemoteQueryManagerFactory.java b/jetty-infinispan/infinispan-remote-query/src/main/java/org/eclipse/jetty/session/infinispan/RemoteQueryManagerFactory.java new file mode 100644 index 00000000000..cf4a53fa3e3 --- /dev/null +++ b/jetty-infinispan/infinispan-remote-query/src/main/java/org/eclipse/jetty/session/infinispan/RemoteQueryManagerFactory.java @@ -0,0 +1,37 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.session.infinispan; + +import org.eclipse.jetty.server.session.SessionData; +import org.infinispan.client.hotrod.RemoteCache; +import org.infinispan.commons.api.BasicCache; + +public class RemoteQueryManagerFactory implements QueryManagerFactory +{ + + @Override + public QueryManager getQueryManager(BasicCache cache) + { + System.err.println(cache.getClass().getName()); + if (!RemoteCache.class.isAssignableFrom(cache.getClass())) + throw new IllegalArgumentException("Argument is not of type RemoteCache"); + + return new RemoteQueryManager((RemoteCache)cache); + } +} diff --git a/jetty-infinispan/infinispan-remote-query/src/test/java/org/eclipse/jetty/server/session/infinispan/RemoteQueryManagerTest.java b/jetty-infinispan/infinispan-remote-query/src/test/java/org/eclipse/jetty/server/session/infinispan/RemoteQueryManagerTest.java new file mode 100644 index 00000000000..a99da415c5d --- /dev/null +++ b/jetty-infinispan/infinispan-remote-query/src/test/java/org/eclipse/jetty/server/session/infinispan/RemoteQueryManagerTest.java @@ -0,0 +1,124 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.server.session.infinispan; + +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.lang.annotation.ElementType; +import java.util.HashSet; +import java.util.Properties; +import java.util.Random; +import java.util.Set; + +import org.eclipse.jetty.server.session.SessionData; +import org.eclipse.jetty.session.infinispan.QueryManager; +import org.eclipse.jetty.session.infinispan.RemoteQueryManager; +import org.eclipse.jetty.session.infinispan.SessionDataMarshaller; +import org.eclipse.jetty.util.IO; +import org.hibernate.search.cfg.Environment; +import org.hibernate.search.cfg.SearchMapping; +import org.infinispan.client.hotrod.RemoteCache; +import org.infinispan.client.hotrod.RemoteCacheManager; +import org.infinispan.client.hotrod.configuration.ConfigurationBuilder; +import org.infinispan.client.hotrod.marshall.ProtoStreamMarshaller; +import org.infinispan.protostream.FileDescriptorSource; +import org.infinispan.protostream.SerializationContext; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class RemoteQueryManagerTest +{ + public static final String DEFAULT_CACHE_NAME = "remote-session-test"; + + @Test + public void test() throws Exception + { + SearchMapping mapping = new SearchMapping(); + mapping.entity(SessionData.class).indexed().providedId().property("expiry", ElementType.FIELD).field(); + + Properties properties = new Properties(); + properties.put(Environment.MODEL_MAPPING, mapping); + + ConfigurationBuilder clientBuilder = new ConfigurationBuilder(); + clientBuilder.withProperties(properties).addServer().host("127.0.0.1").marshaller(new ProtoStreamMarshaller()); + + RemoteCacheManager remoteCacheManager = new RemoteCacheManager(clientBuilder.build()); + + FileDescriptorSource fds = new FileDescriptorSource(); + fds.addProtoFiles("/session.proto"); + + SerializationContext serCtx = ProtoStreamMarshaller.getSerializationContext(remoteCacheManager); + serCtx.registerProtoFiles(fds); + serCtx.registerMarshaller(new SessionDataMarshaller()); + + RemoteCache _cache = remoteCacheManager.getCache(DEFAULT_CACHE_NAME); + + ByteArrayOutputStream baos; + try (InputStream is = RemoteQueryManagerTest.class.getClassLoader().getResourceAsStream("session.proto")) + { + if (is == null) + throw new IllegalStateException("inputstream is null"); + + baos = new ByteArrayOutputStream(); + IO.copy(is, baos); + } + + String content = baos.toString("UTF-8"); + remoteCacheManager.getCache("___protobuf_metadata").put("session.proto", content); + + //put some sessions into the remote cache + int numSessions = 10; + long currentTime = 500; + int maxExpiryTime = 1000; + Set expiredSessions = new HashSet<>(); + Random r = new Random(); + + for (int i = 0; i < numSessions; i++) + { + String id = "sd" + i; + //create new sessiondata with random expiry time + long expiryTime = r.nextInt(maxExpiryTime); + SessionData sd = new SessionData(id, "", "", 0, 0, 0, 0); + sd.setLastNode("lastNode"); + sd.setExpiry(expiryTime); + + //if this entry has expired add it to expiry list + if (expiryTime <= currentTime) + expiredSessions.add(id); + + //add to cache + _cache.put(id, sd); + assertNotNull(_cache.get(id)); + } + + //run the query + QueryManager qm = new RemoteQueryManager(_cache); + Set queryResult = qm.queryExpiredSessions(currentTime); + + // Check that the result is correct + assertEquals(expiredSessions.size(), queryResult.size()); + for (String s : expiredSessions) + { + assertTrue(queryResult.contains(s)); + } + } +} diff --git a/jetty-infinispan/infinispan-remote/pom.xml b/jetty-infinispan/infinispan-remote/pom.xml new file mode 100644 index 00000000000..482dd92b4c9 --- /dev/null +++ b/jetty-infinispan/infinispan-remote/pom.xml @@ -0,0 +1,119 @@ + + + org.eclipse.jetty + infinispan-parent + 9.4.21-SNAPSHOT + + 4.0.0 + infinispan-remote + pom + Jetty :: Infinispan Session Manager Remote + http://www.eclipse.org/jetty + + ${project.groupId}.infinispan.remote + + + install + + + org.apache.maven.plugins + maven-dependency-plugin + + + build-deps-file + generate-resources + + list + + + false + ${project.build.directory}/deps.txt + true + org.eclipse.jetty,javax.servlet + true + provided + + + + + + org.apache.maven.plugins + maven-antrun-plugin + + + process-deps + process-resources + + run + + + + + + + + + + + process-mod + process-resources + + run + + + + + + + + + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + package + + single + + + + src/main/assembly/config.xml + + + + + + + + + + org.eclipse.jetty + infinispan-common + ${project.version} + + + org.infinispan + infinispan-client-hotrod + ${infinispan.version} + provided + + + org.infinispan + infinispan-remote-query-client + ${infinispan.version} + provided + + + org.infinispan.protostream + protostream + 4.2.2.Final + provided + + + diff --git a/jetty-infinispan/infinispan-remote/src/main/assembly/config.xml b/jetty-infinispan/infinispan-remote/src/main/assembly/config.xml new file mode 100644 index 00000000000..802f815d6aa --- /dev/null +++ b/jetty-infinispan/infinispan-remote/src/main/assembly/config.xml @@ -0,0 +1,27 @@ + + + config + false + + jar + + + + src/main/config-template + + + ** + + + **/infinispan-remote-libs.mod + + + + target + modules/sessions/infinispan/remote + + infinispan-remote-libs.mod + + + + diff --git a/jetty-infinispan/infinispan-remote/src/main/config-template/etc/sessions/infinispan/infinispan-remote.xml b/jetty-infinispan/infinispan-remote/src/main/config-template/etc/sessions/infinispan/infinispan-remote.xml new file mode 100644 index 00000000000..fa10e9b2387 --- /dev/null +++ b/jetty-infinispan/infinispan-remote/src/main/config-template/etc/sessions/infinispan/infinispan-remote.xml @@ -0,0 +1,83 @@ + + + + + + + + + + + + /resources/hotrod-client.properties + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /session.proto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jetty-infinispan/infinispan-remote/src/main/config-template/modules/infinispan-remote.mod b/jetty-infinispan/infinispan-remote/src/main/config-template/modules/infinispan-remote.mod new file mode 100644 index 00000000000..d55aa9c760a --- /dev/null +++ b/jetty-infinispan/infinispan-remote/src/main/config-template/modules/infinispan-remote.mod @@ -0,0 +1,9 @@ +[description] +Default setup for the remote infinispan cache without queries + +[tags] +session + +[xml] +etc/sessions/infinispan/infinispan-remote.xml +etc/sessions/infinispan/infinispan-common.xml diff --git a/jetty-infinispan/src/main/config/modules/session-store-infinispan-remote-910.mod b/jetty-infinispan/infinispan-remote/src/main/config-template/modules/session-store-infinispan-remote.mod similarity index 56% rename from jetty-infinispan/src/main/config/modules/session-store-infinispan-remote-910.mod rename to jetty-infinispan/infinispan-remote/src/main/config-template/modules/session-store-infinispan-remote.mod index 93903bd41a3..95e033d10c6 100644 --- a/jetty-infinispan/src/main/config/modules/session-store-infinispan-remote-910.mod +++ b/jetty-infinispan/infinispan-remote/src/main/config-template/modules/session-store-infinispan-remote.mod @@ -1,5 +1,3 @@ -DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html - [description] Enables session data store in a remote Infinispan cache @@ -8,30 +6,27 @@ session [provides] session-store -session-store-infinispan-remote [depend] -sessions +sessions/infinispan/infinispan-common +infinispan-remote +sessions/infinispan/remote/infinispan-remote-libs [files] -maven://org.infinispan/infinispan-remote/9.1.0.Final|lib/infinispan/infinispan-remote-9.1.0.Final.jar -basehome:modules/session-store-infinispan-remote/ +basehome:modules/sessions/infinispan/remote/resources/hotrod-client.properties|resources/hotrod-client.properties -[xml] -etc/sessions/infinispan/remote.xml +[ini] +infinispan.version?=9.4.8.Final -[lib] -lib/jetty-infinispan-${jetty.version}.jar -lib/infinispan/*.jar [license] Infinispan is an open source project hosted on Github and released under the Apache 2.0 license. http://infinispan.org/ http://www.apache.org/licenses/LICENSE-2.0.html - [ini-template] #jetty.session.infinispan.remoteCacheName=sessions #jetty.session.infinispan.idleTimeout.seconds=0 #jetty.session.gracePeriod.seconds=3600 #jetty.session.savePeriod.seconds=0 + diff --git a/jetty-infinispan/infinispan-remote/src/main/config-template/modules/sessions/infinispan/remote/infinispan-remote-libs.mod b/jetty-infinispan/infinispan-remote/src/main/config-template/modules/sessions/infinispan/remote/infinispan-remote-libs.mod new file mode 100644 index 00000000000..28820b94fd4 --- /dev/null +++ b/jetty-infinispan/infinispan-remote/src/main/config-template/modules/sessions/infinispan/remote/infinispan-remote-libs.mod @@ -0,0 +1,16 @@ +[description] +The Infinispan remote libs + +[tags] +3rdparty +infinispan + +[depends] +sessions/infinispan/remote/infinispan-remote-serverclasses + +[license] +Infinispan is an open source project hosted on Github and released under the Apache 2.0 license. +http://infinispan.org/ +http://www.apache.org/licenses/LICENSE-2.0.html + + diff --git a/jetty-infinispan/infinispan-remote/src/main/config-template/modules/sessions/infinispan/remote/infinispan-remote-serverclasses.mod b/jetty-infinispan/infinispan-remote/src/main/config-template/modules/sessions/infinispan/remote/infinispan-remote-serverclasses.mod new file mode 100644 index 00000000000..b36937e1c6c --- /dev/null +++ b/jetty-infinispan/infinispan-remote/src/main/config-template/modules/sessions/infinispan/remote/infinispan-remote-serverclasses.mod @@ -0,0 +1,12 @@ +[description] +Hides Infinispan classes from webapp. + +[tags] +session +3rdparty +infinispan + + +[ini] +## Hide the infinispan libraries from deployed webapps +jetty.webapp.addServerClasses+=,${jetty.base.uri}/lib/infinispan/ diff --git a/jetty-infinispan/infinispan-remote/src/main/config-template/modules/sessions/infinispan/remote/resources/hotrod-client.properties b/jetty-infinispan/infinispan-remote/src/main/config-template/modules/sessions/infinispan/remote/resources/hotrod-client.properties new file mode 100644 index 00000000000..bb774cd9c52 --- /dev/null +++ b/jetty-infinispan/infinispan-remote/src/main/config-template/modules/sessions/infinispan/remote/resources/hotrod-client.properties @@ -0,0 +1 @@ +#infinispan.client.hotrod.server_list diff --git a/jetty-infinispan/pom.xml b/jetty-infinispan/pom.xml index 6ad0e56f451..b680358f0fb 100644 --- a/jetty-infinispan/pom.xml +++ b/jetty-infinispan/pom.xml @@ -1,49 +1,26 @@ + org.eclipse.jetty jetty-project - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT + 4.0.0 - jetty-infinispan - Jetty :: Infinispan Session Managers - http://www.eclipse.org/jetty + org.eclipse.jetty + infinispan-parent + pom + Jetty :: Infinispan + ${project.groupId}.infinispan - 7.1.1.Final - - install - - - org.apache.maven.plugins - maven-assembly-plugin - - - package - - single - - - - config - - - - - - - - - - org.infinispan - infinispan-core - ${infinispan.version} - - - org.eclipse.jetty - jetty-server - ${project.version} - - + + infinispan-common + infinispan-embedded + infinispan-remote + infinispan-embedded-query + infinispan-remote-query + + diff --git a/jetty-infinispan/src/main/config/etc/sessions/infinispan/default.xml b/jetty-infinispan/src/main/config/etc/sessions/infinispan/default.xml deleted file mode 100644 index efc565e2fad..00000000000 --- a/jetty-infinispan/src/main/config/etc/sessions/infinispan/default.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - /etc/infinispan-embedded.xml - - - - - - - - - - - - - - - - - - diff --git a/jetty-infinispan/src/main/config/etc/sessions/infinispan/remote.xml b/jetty-infinispan/src/main/config/etc/sessions/infinispan/remote.xml deleted file mode 100644 index 5f2bb705404..00000000000 --- a/jetty-infinispan/src/main/config/etc/sessions/infinispan/remote.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/jetty-infinispan/src/main/config/modules/session-store-infinispan-embedded-910.mod b/jetty-infinispan/src/main/config/modules/session-store-infinispan-embedded-910.mod deleted file mode 100644 index e7c8f425f8a..00000000000 --- a/jetty-infinispan/src/main/config/modules/session-store-infinispan-embedded-910.mod +++ /dev/null @@ -1,35 +0,0 @@ -DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html - -[description] -Enables session data store in a local Infinispan cache - -[tags] -session - -[provides] -session-store -session-store-infinispan-embedded - -[depend] -sessions - -[files] -maven://org.infinispan/infinispan-embedded/9.1.0.Final|lib/infinispan/infinispan-embedded-9.1.0.Final.jar -basehome:modules/session-store-infinispan-embedded/infinispan-embedded.xml|etc/infinispan-embedded.xml - - -[xml] -etc/sessions/infinispan/default.xml - -[lib] -lib/jetty-infinispan-${jetty.version}.jar -lib/infinispan/*.jar - -[license] -Infinispan is an open source project hosted on Github and released under the Apache 2.0 license. -http://infinispan.org/ -http://www.apache.org/licenses/LICENSE-2.0.html - -[ini-template] -#jetty.session.gracePeriod.seconds=3600 -#jetty.session.savePeriod.seconds=0 diff --git a/jetty-infinispan/src/main/config/modules/session-store-infinispan-embedded.mod b/jetty-infinispan/src/main/config/modules/session-store-infinispan-embedded.mod deleted file mode 100644 index 21dc1e65c9b..00000000000 --- a/jetty-infinispan/src/main/config/modules/session-store-infinispan-embedded.mod +++ /dev/null @@ -1,35 +0,0 @@ -DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html - -[description] -Enables session data store in a local Infinispan cache - -[tags] -session - -[provides] -session-store -session-store-infnispan-embedded - -[depend] -sessions - -[files] -maven://org.infinispan/infinispan-embedded/7.1.1.Final|lib/infinispan/infinispan-embedded-7.1.1.Final.jar -basehome:modules/session-store-infinispan-embedded/infinispan-embedded.xml|etc/infinispan-embedded.xml - - -[xml] -etc/sessions/infinispan/default.xml - -[lib] -lib/jetty-infinispan-${jetty.version}.jar -lib/infinispan/*.jar - -[license] -Infinispan is an open source project hosted on Github and released under the Apache 2.0 license. -http://infinispan.org/ -http://www.apache.org/licenses/LICENSE-2.0.html - -[ini-template] -#jetty.session.gracePeriod.seconds=3600 -#jetty.session.savePeriod.seconds=0 diff --git a/jetty-infinispan/src/main/config/modules/session-store-infinispan-remote.mod b/jetty-infinispan/src/main/config/modules/session-store-infinispan-remote.mod deleted file mode 100644 index 844b47323cb..00000000000 --- a/jetty-infinispan/src/main/config/modules/session-store-infinispan-remote.mod +++ /dev/null @@ -1,36 +0,0 @@ -DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html - -[description] -Enables session data store in a remote Infinispan cache - -[tags] -session - -[provides] -session-store - -[depend] -sessions - -[files] -maven://org.infinispan/infinispan-remote/7.1.1.Final|lib/infinispan/infinispan-remote-7.1.1.Final.jar -basehome:modules/session-store-infinispan-remote/ - -[xml] -etc/sessions/infinispan/remote.xml - -[lib] -lib/jetty-infinispan-${jetty.version}.jar -lib/infinispan/*.jar - -[license] -Infinispan is an open source project hosted on Github and released under the Apache 2.0 license. -http://infinispan.org/ -http://www.apache.org/licenses/LICENSE-2.0.html - - -[ini-template] -#jetty.session.infinispan.remoteCacheName=sessions -#jetty.session.infinispan.idleTimeout.seconds=0 -#jetty.session.gracePeriod.seconds=3600 -#jetty.session.savePeriod.seconds=0 \ No newline at end of file diff --git a/jetty-infinispan/src/main/config/modules/session-store-infinispan-remote/resources/hotrod-client.properties b/jetty-infinispan/src/main/config/modules/session-store-infinispan-remote/resources/hotrod-client.properties deleted file mode 100644 index 5b9016fc1e9..00000000000 --- a/jetty-infinispan/src/main/config/modules/session-store-infinispan-remote/resources/hotrod-client.properties +++ /dev/null @@ -1 +0,0 @@ -infinispan.client.hotrod.marshaller=org.eclipse.jetty.session.infinispan.WebAppMarshaller \ No newline at end of file diff --git a/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionDataStore.java b/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionDataStore.java deleted file mode 100644 index 5d649b76bfd..00000000000 --- a/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionDataStore.java +++ /dev/null @@ -1,329 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.session.infinispan; - -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; - -import org.eclipse.jetty.server.session.AbstractSessionDataStore; -import org.eclipse.jetty.server.session.SessionData; -import org.eclipse.jetty.server.session.UnreadableSessionDataException; -import org.eclipse.jetty.util.annotation.ManagedAttribute; -import org.eclipse.jetty.util.annotation.ManagedObject; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.infinispan.commons.api.BasicCache; - -/** - * InfinispanSessionDataStore - * - * - */ -@ManagedObject -public class InfinispanSessionDataStore extends AbstractSessionDataStore -{ - private final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session"); - - - - /** - * Clustered cache of sessions - */ - private BasicCache _cache; - - - private int _infinispanIdleTimeoutSec; - - - /** - * Get the clustered cache instance. - * - * @return the cache - */ - public BasicCache getCache() - { - return _cache; - } - - - - /** - * Set the clustered cache instance. - * - * @param cache the cache - */ - public void setCache (BasicCache cache) - { - this._cache = cache; - } - - - - /** - * @see org.eclipse.jetty.server.session.SessionDataStore#load(String) - */ - @Override - public SessionData load(String id) throws Exception - { - final AtomicReference reference = new AtomicReference<>(); - final AtomicReference exception = new AtomicReference<>(); - - Runnable load = new Runnable() - { - @Override - public void run () - { - try - { - - if (LOG.isDebugEnabled()) - LOG.debug("Loading session {} from infinispan", id); - - SessionData sd = (SessionData)_cache.get(getCacheKey(id)); - reference.set(sd); - } - catch (Exception e) - { - exception.set(new UnreadableSessionDataException(id, _context, e)); - } - } - }; - - //ensure the load runs in the context classloader scope - _context.run(load); - - if (exception.get() != null) - throw exception.get(); - - return reference.get(); - } - - /** - * @see org.eclipse.jetty.server.session.SessionDataStore#delete(String) - */ - @Override - public boolean delete(String id) throws Exception - { - if (LOG.isDebugEnabled()) - LOG.debug("Deleting session with id {} from infinispan", id); - return (_cache.remove(getCacheKey(id)) != null); - } - - /** - * @see org.eclipse.jetty.server.session.SessionDataStore#getExpired(Set) - */ - @Override - public Set doGetExpired(Set candidates) - { - if (candidates == null || candidates.isEmpty()) - return candidates; - - long now = System.currentTimeMillis(); - - Set expired = new HashSet<>(); - - //TODO if there is NOT an idle timeout set on entries in infinispan, need to check other sessions - //that are not currently in the SessionDataStore (eg they've been passivated) - for (String candidate:candidates) - { - if (LOG.isDebugEnabled()) - LOG.debug("Checking expiry for candidate {}", candidate); - try - { - SessionData sd = load(candidate); - - //if the session no longer exists - if (sd == null) - { - expired.add(candidate); - if (LOG.isDebugEnabled()) - LOG.debug("Session {} does not exist in infinispan", candidate); - } - else - { - if (_context.getWorkerName().equals(sd.getLastNode())) - { - //we are its manager, add it to the expired set if it is expired now - if ((sd.getExpiry() > 0 ) && sd.getExpiry() <= now) - { - expired.add(candidate); - if (LOG.isDebugEnabled()) - LOG.debug("Session {} managed by {} is expired", candidate, _context.getWorkerName()); - } - } - else - { - //if we are not the session's manager, only expire it iff: - // this is our first expiryCheck and the session expired a long time ago - //or - //the session expired at least one graceperiod ago - if (_lastExpiryCheckTime <=0) - { - if ((sd.getExpiry() > 0 ) && sd.getExpiry() < (now - (1000L * (3 * _gracePeriodSec)))) - expired.add(candidate); - } - else - { - if ((sd.getExpiry() > 0 ) && sd.getExpiry() < (now - (1000L * _gracePeriodSec))) - expired.add(candidate); - } - } - } - } - catch (Exception e) - { - LOG.warn("Error checking if candidate {} is expired", candidate, e); - } - } - - return expired; - } - - /** - * @see org.eclipse.jetty.server.session.AbstractSessionDataStore#doStore(String, SessionData, long) - */ - @Override - public void doStore(String id, SessionData data, long lastSaveTime) throws Exception - { - //Put an idle timeout on the cache entry if the session is not immortal - - //if no requests arrive at any node before this timeout occurs, or no node - //scavenges the session before this timeout occurs, the session will be removed. - //NOTE: that no session listeners can be called for this. - if (data.getMaxInactiveMs() > 0 && getInfinispanIdleTimeoutSec() > 0) - _cache.put(getCacheKey(id), data, -1, TimeUnit.MILLISECONDS, getInfinispanIdleTimeoutSec(), TimeUnit.SECONDS); - else - _cache.put(getCacheKey(id), data); - - if (LOG.isDebugEnabled()) - LOG.debug("Session {} saved to infinispan, expires {} ", id, data.getExpiry()); - } - - - public String getCacheKey (String id) - { - return _context.getCanonicalContextPath()+"_"+_context.getVhost()+"_"+id; - } - - - - /** - * @see org.eclipse.jetty.server.session.SessionDataStore#isPassivating() - */ - @ManagedAttribute(value="does store serialize sessions", readonly=true) - @Override - public boolean isPassivating() - { - //TODO run in the _context to ensure classloader is set - try - { - Class remoteClass = Thread.currentThread().getContextClassLoader().loadClass("org.infinispan.client.hotrod.RemoteCache"); - if (remoteClass.isAssignableFrom(_cache.getClass())) - { - return true; - } - return false; - } - catch (ClassNotFoundException e) - { - return false; - } - } - - - - /** - * @see org.eclipse.jetty.server.session.SessionDataStore#exists(java.lang.String) - */ - @Override - public boolean exists(String id) throws Exception - { - // TODO find a better way to do this that does not pull into memory the - // whole session object - final AtomicBoolean reference = new AtomicBoolean(); - final AtomicReference exception = new AtomicReference<>(); - - Runnable load = new Runnable() - { - @Override - public void run () - { - try - { - SessionData sd = load(id); - if (sd == null) - { - reference.set(false); - return; - } - - if (sd.getExpiry() <= 0) - reference.set(true); //never expires - else - reference.set(sd.getExpiry() > System.currentTimeMillis()); //not expired yet - } - catch (Exception e) - { - exception.set(e); - } - } - }; - - //ensure the load runs in the context classloader scope - _context.run(load); - - if (exception.get() != null) - throw exception.get(); - - return reference.get(); - } - - - - /** - * @param sec the infinispan-specific idle timeout in sec or 0 if not set - */ - public void setInfinispanIdleTimeoutSec (int sec) - { - _infinispanIdleTimeoutSec = sec; - } - - - @ManagedAttribute(value="infinispan idle timeout sec", readonly=true) - public int getInfinispanIdleTimeoutSec () - { - return _infinispanIdleTimeoutSec; - } - - - - /** - * @see org.eclipse.jetty.server.session.AbstractSessionDataStore#toString() - */ - @Override - public String toString() - { - return String.format("%s[cache=%s,idleTimeoutSec=%d]",super.toString(), (_cache==null?"":_cache.getName()),_infinispanIdleTimeoutSec); - } - - -} diff --git a/jetty-io/pom.xml b/jetty-io/pom.xml index 88a36122609..f6d80bc1c3d 100644 --- a/jetty-io/pom.xml +++ b/jetty-io/pom.xml @@ -1,8 +1,9 @@ - + + jetty-project org.eclipse.jetty - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 jetty-io diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractByteBufferPool.java new file mode 100644 index 00000000000..71c0fec0c55 --- /dev/null +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractByteBufferPool.java @@ -0,0 +1,110 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.io; + +import java.nio.ByteBuffer; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Consumer; + +import org.eclipse.jetty.util.annotation.ManagedAttribute; +import org.eclipse.jetty.util.annotation.ManagedObject; +import org.eclipse.jetty.util.annotation.ManagedOperation; + +@ManagedObject +abstract class AbstractByteBufferPool implements ByteBufferPool +{ + private final int _factor; + private final int _maxQueueLength; + private final long _maxHeapMemory; + private final AtomicLong _heapMemory = new AtomicLong(); + private final long _maxDirectMemory; + private final AtomicLong _directMemory = new AtomicLong(); + + protected AbstractByteBufferPool(int factor, int maxQueueLength, long maxHeapMemory, long maxDirectMemory) + { + _factor = factor <= 0 ? 1024 : factor; + _maxQueueLength = maxQueueLength; + _maxHeapMemory = maxHeapMemory; + _maxDirectMemory = maxDirectMemory; + } + + protected int getCapacityFactor() + { + return _factor; + } + + protected int getMaxQueueLength() + { + return _maxQueueLength; + } + + protected void decrementMemory(ByteBuffer buffer) + { + updateMemory(buffer, false); + } + + protected void incrementMemory(ByteBuffer buffer) + { + updateMemory(buffer, true); + } + + private void updateMemory(ByteBuffer buffer, boolean addOrSub) + { + AtomicLong memory = buffer.isDirect() ? _directMemory : _heapMemory; + int capacity = buffer.capacity(); + memory.addAndGet(addOrSub ? capacity : -capacity); + } + + protected void releaseExcessMemory(boolean direct, Consumer clearFn) + { + long maxMemory = direct ? _maxDirectMemory : _maxHeapMemory; + if (maxMemory > 0) + { + while (getMemory(direct) > maxMemory) + { + clearFn.accept(direct); + } + } + } + + @ManagedAttribute("The bytes retained by direct ByteBuffers") + public long getDirectMemory() + { + return getMemory(true); + } + + @ManagedAttribute("The bytes retained by heap ByteBuffers") + public long getHeapMemory() + { + return getMemory(false); + } + + public long getMemory(boolean direct) + { + AtomicLong memory = direct ? _directMemory : _heapMemory; + return memory.get(); + } + + @ManagedOperation(value = "Clears this ByteBufferPool", impact = "ACTION") + public void clear() + { + _heapMemory.set(0); + _directMemory.set(0); + } +} diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractConnection.java b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractConnection.java index 7c6e1b99680..8ba86c5c03a 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractConnection.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractConnection.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -41,11 +41,11 @@ public abstract class AbstractConnection implements Connection private static final Logger LOG = Log.getLogger(AbstractConnection.class); private final List _listeners = new CopyOnWriteArrayList<>(); - private final long _created=System.currentTimeMillis(); + private final long _created = System.currentTimeMillis(); private final EndPoint _endPoint; private final Executor _executor; private final Callback _readCallback; - private int _inputBufferSize=2048; + private int _inputBufferSize = 2048; protected AbstractConnection(EndPoint endp, Executor executor) { @@ -96,28 +96,27 @@ public abstract class AbstractConnection implements Connection LOG.warn(e); } }; - - switch(Invocable.getInvocationType(callback)) + + switch (Invocable.getInvocationType(callback)) { case BLOCKING: try { - getExecutor().execute(failCallback); + getExecutor().execute(failCallback); } - catch(RejectedExecutionException e) + catch (RejectedExecutionException e) { LOG.debug(e); callback.failed(x); } break; - + case NON_BLOCKING: failCallback.run(); break; - + case EITHER: Invocable.invokeNonBlocking(failCallback); - } } @@ -125,12 +124,13 @@ public abstract class AbstractConnection implements Connection *

        Utility method to be called to register read interest.

        *

        After a call to this method, {@link #onFillable()} or {@link #onFillInterestedFailed(Throwable)} * will be called back as appropriate.

        + * * @see #onFillable() */ public void fillInterested() { if (LOG.isDebugEnabled()) - LOG.debug("fillInterested {}",this); + LOG.debug("fillInterested {}", this); getEndPoint().fillInterested(_readCallback); } @@ -151,12 +151,14 @@ public abstract class AbstractConnection implements Connection /** *

        Callback method invoked when the endpoint is ready to be read.

        + * * @see #fillInterested() */ public abstract void onFillable(); /** *

        Callback method invoked when the endpoint failed to be ready to be read.

        + * * @param cause the exception that caused the failure */ protected void onFillInterestedFailed(Throwable cause) @@ -199,7 +201,9 @@ public abstract class AbstractConnection implements Connection LOG.debug("onOpen {}", this); for (Listener listener : _listeners) + { onOpened(listener); + } } private void onOpened(Listener listener) @@ -218,10 +222,12 @@ public abstract class AbstractConnection implements Connection public void onClose() { if (LOG.isDebugEnabled()) - LOG.debug("onClose {}",this); + LOG.debug("onClose {}", this); for (Listener listener : _listeners) + { onClosed(listener); + } } private void onClosed(Listener listener) @@ -287,7 +293,7 @@ public abstract class AbstractConnection implements Connection @Override public final String toString() { - return String.format("%s@%h::%s",getClass().getSimpleName(),this,getEndPoint()); + return String.format("%s@%h::%s", getClass().getSimpleName(), this, getEndPoint()); } public String toConnectionString() @@ -314,8 +320,7 @@ public abstract class AbstractConnection implements Connection @Override public String toString() { - return String.format("AC.ReadCB@%h{%s}", AbstractConnection.this,AbstractConnection.this); + return String.format("AC.ReadCB@%h{%s}", AbstractConnection.this, AbstractConnection.this); } } - } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractEndPoint.java index 105bbd74584..c7ca0333cd5 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractEndPoint.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -34,7 +34,7 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint private static final Logger LOG = Log.getLogger(AbstractEndPoint.class); private final AtomicReference _state = new AtomicReference<>(State.OPEN); - private final long _created=System.currentTimeMillis(); + private final long _created = System.currentTimeMillis(); private volatile Connection _connection; private final FillInterest _fillInterest = new FillInterest() @@ -63,14 +63,14 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint protected final void shutdownInput() { if (LOG.isDebugEnabled()) - LOG.debug("shutdownInput {}",this); - while(true) + LOG.debug("shutdownInput {}", this); + while (true) { State s = _state.get(); - switch(s) + switch (s) { case OPEN: - if (!_state.compareAndSet(s,State.ISHUTTING)) + if (!_state.compareAndSet(s, State.ISHUTTING)) continue; try { @@ -78,11 +78,11 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint } finally { - if(!_state.compareAndSet(State.ISHUTTING,State.ISHUT)) + if (!_state.compareAndSet(State.ISHUTTING, State.ISHUT)) { // If somebody else switched to CLOSED while we were ishutting, // then we do the close for them - if (_state.get()==State.CLOSED) + if (_state.get() == State.CLOSED) doOnClose(null); else throw new IllegalStateException(); @@ -95,13 +95,13 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint return; case OSHUTTING: - if (!_state.compareAndSet(s,State.CLOSED)) + if (!_state.compareAndSet(s, State.CLOSED)) continue; // The thread doing the OSHUT will close return; case OSHUT: - if (!_state.compareAndSet(s,State.CLOSED)) + if (!_state.compareAndSet(s, State.CLOSED)) continue; // Already OSHUT so we close doOnClose(null); @@ -117,14 +117,14 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint public final void shutdownOutput() { if (LOG.isDebugEnabled()) - LOG.debug("shutdownOutput {}",this); - while(true) + LOG.debug("shutdownOutput {}", this); + while (true) { State s = _state.get(); - switch(s) + switch (s) { case OPEN: - if (!_state.compareAndSet(s,State.OSHUTTING)) + if (!_state.compareAndSet(s, State.OSHUTTING)) continue; try { @@ -132,11 +132,11 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint } finally { - if(!_state.compareAndSet(State.OSHUTTING,State.OSHUT)) + if (!_state.compareAndSet(State.OSHUTTING, State.OSHUT)) { // If somebody else switched to CLOSED while we were oshutting, // then we do the close for them - if (_state.get()==State.CLOSED) + if (_state.get() == State.CLOSED) doOnClose(null); else throw new IllegalStateException(); @@ -145,13 +145,13 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint return; case ISHUTTING: - if (!_state.compareAndSet(s,State.CLOSED)) + if (!_state.compareAndSet(s, State.CLOSED)) continue; // The thread doing the ISHUT will close return; case ISHUT: - if (!_state.compareAndSet(s,State.CLOSED)) + if (!_state.compareAndSet(s, State.CLOSED)) continue; // Already ISHUT so we close doOnClose(null); @@ -171,30 +171,30 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint public final void close() { if (LOG.isDebugEnabled()) - LOG.debug("close {}",this); + LOG.debug("close {}", this); close(null); } protected final void close(Throwable failure) { if (LOG.isDebugEnabled()) - LOG.debug("close({}) {}",failure,this); - while(true) + LOG.debug("close({}) {}", failure, this); + while (true) { State s = _state.get(); - switch(s) + switch (s) { case OPEN: case ISHUT: // Already ishut case OSHUT: // Already oshut - if (!_state.compareAndSet(s,State.CLOSED)) + if (!_state.compareAndSet(s, State.CLOSED)) continue; doOnClose(failure); return; case ISHUTTING: // Somebody else ishutting case OSHUTTING: // Somebody else oshutting - if (!_state.compareAndSet(s,State.CLOSED)) + if (!_state.compareAndSet(s, State.CLOSED)) continue; // The thread doing the IO SHUT will call doOnClose return; @@ -242,7 +242,7 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint @Override public boolean isOutputShutdown() { - switch(_state.get()) + switch (_state.get()) { case CLOSED: case OSHUT: @@ -252,10 +252,11 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint return false; } } + @Override public boolean isInputShutdown() { - switch(_state.get()) + switch (_state.get()) { case CLOSED: case ISHUT: @@ -269,7 +270,7 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint @Override public boolean isOpen() { - switch(_state.get()) + switch (_state.get()) { case CLOSED: return false; @@ -280,8 +281,8 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint public void checkFlush() throws IOException { - State s=_state.get(); - switch(s) + State s = _state.get(); + switch (s) { case OSHUT: case OSHUTTING: @@ -294,8 +295,8 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint public void checkFill() throws IOException { - State s=_state.get(); - switch(s) + State s = _state.get(); + switch (s) { case ISHUT: case ISHUTTING: @@ -341,8 +342,8 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint public void onOpen() { if (LOG.isDebugEnabled()) - LOG.debug("onOpen {}",this); - if (_state.get()!=State.OPEN) + LOG.debug("onOpen {}", this); + if (_state.get() != State.OPEN) throw new IllegalStateException(); } @@ -389,7 +390,7 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint return _fillInterest; } - protected WriteFlusher getWriteFlusher() + public WriteFlusher getWriteFlusher() { return _writeFlusher; } @@ -401,8 +402,8 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint if (connection != null && !connection.onIdleExpired()) return; - boolean output_shutdown=isOutputShutdown(); - boolean input_shutdown=isInputShutdown(); + boolean outputShutdown = isOutputShutdown(); + boolean inputShutdown = isInputShutdown(); boolean fillFailed = _fillInterest.onFail(timeout); boolean writeFailed = _writeFlusher.onFail(timeout); @@ -413,29 +414,30 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint // for a dispatched servlet or suspended request to extend beyond the connections idle // time. So if this test would always close an idle endpoint that is not handled, then // we would need a mode to ignore timeouts for some HTTP states - if (isOpen() && (output_shutdown || input_shutdown) && !(fillFailed || writeFailed)) + if (isOpen() && (outputShutdown || inputShutdown) && !(fillFailed || writeFailed)) close(); else - LOG.debug("Ignored idle endpoint {}",this); + LOG.debug("Ignored idle endpoint {}", this); } @Override public void upgrade(Connection newConnection) { - Connection old_connection = getConnection(); + Connection oldConnection = getConnection(); if (LOG.isDebugEnabled()) - LOG.debug("{} upgrading from {} to {}", this, old_connection, newConnection); + LOG.debug("{} upgrading from {} to {}", this, oldConnection, newConnection); - ByteBuffer prefilled = (old_connection instanceof Connection.UpgradeFrom) - ?((Connection.UpgradeFrom)old_connection).onUpgradeFrom():null; - old_connection.onClose(); - old_connection.getEndPoint().setConnection(newConnection); + ByteBuffer buffer = (oldConnection instanceof Connection.UpgradeFrom) + ? ((Connection.UpgradeFrom)oldConnection).onUpgradeFrom() + : null; + oldConnection.onClose(); + oldConnection.getEndPoint().setConnection(newConnection); if (newConnection instanceof Connection.UpgradeTo) - ((Connection.UpgradeTo)newConnection).onUpgradeTo(prefilled); - else if (BufferUtil.hasContent(prefilled)) - throw new IllegalStateException(); + ((Connection.UpgradeTo)newConnection).onUpgradeTo(buffer); + else if (BufferUtil.hasContent(buffer)) + throw new IllegalStateException("Cannot upgrade: " + newConnection + " does not implement " + Connection.UpgradeTo.class.getName()); newConnection.onOpen(); } @@ -443,31 +445,31 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint @Override public String toString() { - return String.format("%s->%s",toEndPointString(),toConnectionString()); + return String.format("%s->%s", toEndPointString(), toConnectionString()); } - + public String toEndPointString() { - Class c=getClass(); - String name=c.getSimpleName(); - while (name.length()==0 && c.getSuperclass()!=null) + Class c = getClass(); + String name = c.getSimpleName(); + while (name.length() == 0 && c.getSuperclass() != null) { - c=c.getSuperclass(); - name=c.getSimpleName(); + c = c.getSuperclass(); + name = c.getSimpleName(); } return String.format("%s@%h{%s<->%s,%s,fill=%s,flush=%s,to=%d/%d}", - name, - this, - getRemoteAddress(), - getLocalAddress(), - _state.get(), - _fillInterest.toStateString(), - _writeFlusher.toStateString(), - getIdleFor(), - getIdleTimeout()); + name, + this, + getRemoteAddress(), + getLocalAddress(), + _state.get(), + _fillInterest.toStateString(), + _writeFlusher.toStateString(), + getIdleFor(), + getIdleTimeout()); } - + public String toConnectionString() { Connection connection = getConnection(); @@ -475,9 +477,8 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint return ""; if (connection instanceof AbstractConnection) return ((AbstractConnection)connection).toConnectionString(); - return String.format("%s@%x",connection.getClass().getSimpleName(),connection.hashCode()); + return String.format("%s@%x", connection.getClass().getSimpleName(), connection.hashCode()); } - private enum State { diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java index 2d22aa0b3dd..f283c132e5c 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,96 +19,205 @@ package org.eclipse.jetty.io; import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.Objects; +import java.util.function.IntFunction; -public class ArrayByteBufferPool implements ByteBufferPool +import org.eclipse.jetty.util.annotation.ManagedAttribute; +import org.eclipse.jetty.util.annotation.ManagedObject; + +/** + *

        A ByteBuffer pool where ByteBuffers are held in queues that are held in array elements.

        + *

        Given a capacity {@code factor} of 1024, the first array element holds a queue of ByteBuffers + * each of capacity 1024, the second array element holds a queue of ByteBuffers each of capacity + * 2048, and so on.

        + */ +@ManagedObject +public class ArrayByteBufferPool extends AbstractByteBufferPool { - private final int _min; - private final int _maxQueue; + private final int _minCapacity; private final ByteBufferPool.Bucket[] _direct; private final ByteBufferPool.Bucket[] _indirect; - private final int _inc; + /** + * Creates a new ArrayByteBufferPool with a default configuration. + */ public ArrayByteBufferPool() { - this(-1,-1,-1,-1); + this(-1, -1, -1); } - public ArrayByteBufferPool(int minSize, int increment, int maxSize) + /** + * Creates a new ArrayByteBufferPool with the given configuration. + * + * @param minCapacity the minimum ByteBuffer capacity + * @param factor the capacity factor + * @param maxCapacity the maximum ByteBuffer capacity + */ + public ArrayByteBufferPool(int minCapacity, int factor, int maxCapacity) { - this(minSize,increment,maxSize,-1); + this(minCapacity, factor, maxCapacity, -1, -1, -1); } - - public ArrayByteBufferPool(int minSize, int increment, int maxSize, int maxQueue) + + /** + * Creates a new ArrayByteBufferPool with the given configuration. + * + * @param minCapacity the minimum ByteBuffer capacity + * @param factor the capacity factor + * @param maxCapacity the maximum ByteBuffer capacity + * @param maxQueueLength the maximum ByteBuffer queue length + */ + public ArrayByteBufferPool(int minCapacity, int factor, int maxCapacity, int maxQueueLength) { - if (minSize<=0) - minSize=0; - if (increment<=0) - increment=1024; - if (maxSize<=0) - maxSize=64*1024; - if (minSize>=increment) - throw new IllegalArgumentException("minSize >= increment"); - if ((maxSize%increment)!=0 || increment>=maxSize) - throw new IllegalArgumentException("increment must be a divisor of maxSize"); - _min=minSize; - _inc=increment; + this(minCapacity, factor, maxCapacity, maxQueueLength, -1, -1); + } - _direct=new ByteBufferPool.Bucket[maxSize/increment]; - _indirect=new ByteBufferPool.Bucket[maxSize/increment]; - _maxQueue=maxQueue; + /** + * Creates a new ArrayByteBufferPool with the given configuration. + * + * @param minCapacity the minimum ByteBuffer capacity + * @param factor the capacity factor + * @param maxCapacity the maximum ByteBuffer capacity + * @param maxQueueLength the maximum ByteBuffer queue length + * @param maxHeapMemory the max heap memory in bytes + * @param maxDirectMemory the max direct memory in bytes + */ + public ArrayByteBufferPool(int minCapacity, int factor, int maxCapacity, int maxQueueLength, long maxHeapMemory, long maxDirectMemory) + { + super(factor, maxQueueLength, maxHeapMemory, maxDirectMemory); - int size=0; - for (int i=0;i<_direct.length;i++) - { - size+=_inc; - _direct[i]=new ByteBufferPool.Bucket(this,size,_maxQueue); - _indirect[i]=new ByteBufferPool.Bucket(this,size,_maxQueue); - } + factor = getCapacityFactor(); + if (minCapacity <= 0) + minCapacity = 0; + if (maxCapacity <= 0) + maxCapacity = 64 * 1024; + if ((maxCapacity % factor) != 0 || factor >= maxCapacity) + throw new IllegalArgumentException("The capacity factor must be a divisor of maxCapacity"); + _minCapacity = minCapacity; + + int length = maxCapacity / factor; + _direct = new ByteBufferPool.Bucket[length]; + _indirect = new ByteBufferPool.Bucket[length]; } @Override public ByteBuffer acquire(int size, boolean direct) { - ByteBufferPool.Bucket bucket = bucketFor(size,direct); - if (bucket==null) - return newByteBuffer(size,direct); - - return bucket.acquire(direct); - + int capacity = size < _minCapacity ? size : (bucketFor(size) + 1) * getCapacityFactor(); + ByteBufferPool.Bucket bucket = bucketFor(size, direct, null); + if (bucket == null) + return newByteBuffer(capacity, direct); + ByteBuffer buffer = bucket.acquire(); + if (buffer == null) + return newByteBuffer(capacity, direct); + decrementMemory(buffer); + return buffer; } @Override public void release(ByteBuffer buffer) { - if (buffer!=null) - { - ByteBufferPool.Bucket bucket = bucketFor(buffer.capacity(),buffer.isDirect()); - if (bucket!=null) - bucket.release(buffer); + if (buffer == null) + return; + boolean direct = buffer.isDirect(); + ByteBufferPool.Bucket bucket = bucketFor(buffer.capacity(), direct, this::newBucket); + if (bucket != null) + { + bucket.release(buffer); + incrementMemory(buffer); + releaseExcessMemory(direct, this::clearOldestBucket); } } + private Bucket newBucket(int key) + { + return new Bucket(this, key * getCapacityFactor(), getMaxQueueLength()); + } + + @Override public void clear() { - for (int i=0;i<_direct.length;i++) + super.clear(); + for (int i = 0; i < _direct.length; ++i) { - _direct[i].clear(); - _indirect[i].clear(); + Bucket bucket = _direct[i]; + if (bucket != null) + bucket.clear(); + _direct[i] = null; + bucket = _indirect[i]; + if (bucket != null) + bucket.clear(); + _indirect[i] = null; } } - private ByteBufferPool.Bucket bucketFor(int size,boolean direct) + private void clearOldestBucket(boolean direct) { - if (size<=_min) + long oldest = Long.MAX_VALUE; + int index = -1; + Bucket[] buckets = bucketsFor(direct); + for (int i = 0; i < buckets.length; ++i) + { + Bucket bucket = buckets[i]; + if (bucket == null) + continue; + long lastUpdate = bucket.getLastUpdate(); + if (lastUpdate < oldest) + { + oldest = lastUpdate; + index = i; + } + } + if (index >= 0) + { + Bucket bucket = buckets[index]; + buckets[index] = null; + // The same bucket may be concurrently + // removed, so we need this null guard. + if (bucket != null) + bucket.clear(this::decrementMemory); + } + } + + private int bucketFor(int capacity) + { + return (capacity - 1) / getCapacityFactor(); + } + + private ByteBufferPool.Bucket bucketFor(int capacity, boolean direct, IntFunction newBucket) + { + if (capacity < _minCapacity) return null; - int b=(size-1)/_inc; - if (b>=_direct.length) + int b = bucketFor(capacity); + if (b >= _direct.length) return null; - ByteBufferPool.Bucket bucket = direct?_direct[b]:_indirect[b]; - + Bucket[] buckets = bucketsFor(direct); + Bucket bucket = buckets[b]; + if (bucket == null && newBucket != null) + buckets[b] = bucket = newBucket.apply(b + 1); return bucket; } + @ManagedAttribute("The number of pooled direct ByteBuffers") + public long getDirectByteBufferCount() + { + return getByteBufferCount(true); + } + + @ManagedAttribute("The number of pooled heap ByteBuffers") + public long getHeapByteBufferCount() + { + return getByteBufferCount(false); + } + + private long getByteBufferCount(boolean direct) + { + return Arrays.stream(bucketsFor(direct)) + .filter(Objects::nonNull) + .mapToLong(Bucket::size) + .sum(); + } + // Package local for testing ByteBufferPool.Bucket[] bucketsFor(boolean direct) { diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayEndPoint.java index 0b25f5600e6..542365364d7 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayEndPoint.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -39,19 +39,18 @@ import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.thread.Locker; import org.eclipse.jetty.util.thread.Scheduler; -/* ------------------------------------------------------------ */ -/** ByteArrayEndPoint. - * +/** + * ByteArrayEndPoint. */ public class ByteArrayEndPoint extends AbstractEndPoint { static final Logger LOG = Log.getLogger(ByteArrayEndPoint.class); - static final InetAddress NOIP; + static final InetAddress NOIP; static final InetSocketAddress NOIPPORT; - + static { - InetAddress noip=null; + InetAddress noip = null; try { noip = Inet4Address.getByName("0.0.0.0"); @@ -62,12 +61,11 @@ public class ByteArrayEndPoint extends AbstractEndPoint } finally { - NOIP=noip; - NOIPPORT=new InetSocketAddress(NOIP,0); + NOIP = noip; + NOIPPORT = new InetSocketAddress(NOIP, 0); } } - - + private static final ByteBuffer EOF = BufferUtil.allocate(0); private final Runnable _runFillable = new Runnable() @@ -85,118 +83,104 @@ public class ByteArrayEndPoint extends AbstractEndPoint private ByteBuffer _out; private boolean _growOutput; - /* ------------------------------------------------------------ */ /** * */ public ByteArrayEndPoint() { - this(null,0,null,null); + this(null, 0, null, null); } - /* ------------------------------------------------------------ */ /** * @param input the input bytes * @param outputSize the output size */ public ByteArrayEndPoint(byte[] input, int outputSize) { - this(null,0,input!=null?BufferUtil.toBuffer(input):null,BufferUtil.allocate(outputSize)); + this(null, 0, input != null ? BufferUtil.toBuffer(input) : null, BufferUtil.allocate(outputSize)); } - /* ------------------------------------------------------------ */ /** * @param input the input string (converted to bytes using default encoding charset) * @param outputSize the output size */ public ByteArrayEndPoint(String input, int outputSize) { - this(null,0,input!=null?BufferUtil.toBuffer(input):null,BufferUtil.allocate(outputSize)); + this(null, 0, input != null ? BufferUtil.toBuffer(input) : null, BufferUtil.allocate(outputSize)); } - /* ------------------------------------------------------------ */ public ByteArrayEndPoint(Scheduler scheduler, long idleTimeoutMs) { - this(scheduler,idleTimeoutMs,null,null); + this(scheduler, idleTimeoutMs, null, null); } - /* ------------------------------------------------------------ */ public ByteArrayEndPoint(Scheduler timer, long idleTimeoutMs, byte[] input, int outputSize) { - this(timer,idleTimeoutMs,input!=null?BufferUtil.toBuffer(input):null,BufferUtil.allocate(outputSize)); + this(timer, idleTimeoutMs, input != null ? BufferUtil.toBuffer(input) : null, BufferUtil.allocate(outputSize)); } - /* ------------------------------------------------------------ */ public ByteArrayEndPoint(Scheduler timer, long idleTimeoutMs, String input, int outputSize) { - this(timer,idleTimeoutMs,input!=null?BufferUtil.toBuffer(input):null,BufferUtil.allocate(outputSize)); + this(timer, idleTimeoutMs, input != null ? BufferUtil.toBuffer(input) : null, BufferUtil.allocate(outputSize)); } - /* ------------------------------------------------------------ */ public ByteArrayEndPoint(Scheduler timer, long idleTimeoutMs, ByteBuffer input, ByteBuffer output) { super(timer); if (BufferUtil.hasContent(input)) addInput(input); - _out=output==null?BufferUtil.allocate(1024):output; + _out = output == null ? BufferUtil.allocate(1024) : output; setIdleTimeout(idleTimeoutMs); onOpen(); } - - /* ------------------------------------------------------------ */ + @Override public void doShutdownOutput() { - super.doShutdownOutput(); - try(Locker.Lock lock = _locker.lock()) - { - _hasOutput.signalAll(); - } - } - - /* ------------------------------------------------------------ */ - @Override - public void doClose() - { - super.doClose(); - try(Locker.Lock lock = _locker.lock()) + super.doShutdownOutput(); + try (Locker.Lock lock = _locker.lock()) + { + _hasOutput.signalAll(); + } + } + + @Override + public void doClose() + { + super.doClose(); + try (Locker.Lock lock = _locker.lock()) { _hasOutput.signalAll(); } } - /* ------------------------------------------------------------ */ @Override public InetSocketAddress getLocalAddress() { return NOIPPORT; } - /* ------------------------------------------------------------ */ @Override public InetSocketAddress getRemoteAddress() { return NOIPPORT; } - /* ------------------------------------------------------------ */ @Override protected void onIncompleteFlush() { // Don't need to do anything here as takeOutput does the signalling. } - /* ------------------------------------------------------------ */ protected void execute(Runnable task) { - new Thread(task,"BAEPoint-"+Integer.toHexString(hashCode())).start(); + new Thread(task, "BAEPoint-" + Integer.toHexString(hashCode())).start(); } - /* ------------------------------------------------------------ */ @Override protected void needsFillInterest() throws IOException { - try(Locker.Lock lock = _locker.lock()) + try (Locker.Lock lock = _locker.lock()) { if (!isOpen()) throw new ClosedChannelException(); @@ -207,90 +191,84 @@ public class ByteArrayEndPoint extends AbstractEndPoint } } - /* ------------------------------------------------------------ */ /** + * */ public void addInputEOF() { addInput((ByteBuffer)null); } - /* ------------------------------------------------------------ */ /** * @param in The in to set. */ public void addInput(ByteBuffer in) { - boolean fillable=false; - try(Locker.Lock lock = _locker.lock()) + boolean fillable = false; + try (Locker.Lock lock = _locker.lock()) { if (isEOF(_inQ.peek())) throw new RuntimeIOException(new EOFException()); - boolean was_empty=_inQ.isEmpty(); - if (in==null) + boolean wasEmpty = _inQ.isEmpty(); + if (in == null) { _inQ.add(EOF); - fillable=true; + fillable = true; } if (BufferUtil.hasContent(in)) { _inQ.add(in); - fillable=was_empty; + fillable = wasEmpty; } } if (fillable) _runFillable.run(); } - /* ------------------------------------------------------------ */ public void addInputAndExecute(ByteBuffer in) { - boolean fillable=false; - try(Locker.Lock lock = _locker.lock()) + boolean fillable = false; + try (Locker.Lock lock = _locker.lock()) { if (isEOF(_inQ.peek())) throw new RuntimeIOException(new EOFException()); - boolean was_empty=_inQ.isEmpty(); - if (in==null) + boolean wasEmpty = _inQ.isEmpty(); + if (in == null) { _inQ.add(EOF); - fillable=true; + fillable = true; } if (BufferUtil.hasContent(in)) { _inQ.add(in); - fillable=was_empty; + fillable = wasEmpty; } } if (fillable) execute(_runFillable); } - /* ------------------------------------------------------------ */ public void addInput(String s) { - addInput(BufferUtil.toBuffer(s,StandardCharsets.UTF_8)); + addInput(BufferUtil.toBuffer(s, StandardCharsets.UTF_8)); } - /* ------------------------------------------------------------ */ - public void addInput(String s,Charset charset) + public void addInput(String s, Charset charset) { - addInput(BufferUtil.toBuffer(s,charset)); + addInput(BufferUtil.toBuffer(s, charset)); } - /* ------------------------------------------------------------ */ /** * @return Returns the out. */ public ByteBuffer getOutput() { - try(Locker.Lock lock = _locker.lock()) + try (Locker.Lock lock = _locker.lock()) { return _out; } } - /* ------------------------------------------------------------ */ /** * @return Returns the out. */ @@ -299,17 +277,15 @@ public class ByteArrayEndPoint extends AbstractEndPoint return getOutputString(StandardCharsets.UTF_8); } - /* ------------------------------------------------------------ */ /** * @param charset the charset to encode the output as * @return Returns the out. */ public String getOutputString(Charset charset) { - return BufferUtil.toString(_out,charset); + return BufferUtil.toString(_out, charset); } - /* ------------------------------------------------------------ */ /** * @return Returns the out. */ @@ -317,41 +293,41 @@ public class ByteArrayEndPoint extends AbstractEndPoint { ByteBuffer b; - try(Locker.Lock lock = _locker.lock()) + try (Locker.Lock lock = _locker.lock()) { - b=_out; - _out=BufferUtil.allocate(b.capacity()); + b = _out; + _out = BufferUtil.allocate(b.capacity()); } getWriteFlusher().completeWrite(); return b; } - /* ------------------------------------------------------------ */ - /** Wait for some output + /** + * Wait for some output + * * @param time Time to wait * @param unit Units for time to wait * @return The buffer of output * @throws InterruptedException if interrupted */ - public ByteBuffer waitForOutput(long time,TimeUnit unit) throws InterruptedException + public ByteBuffer waitForOutput(long time, TimeUnit unit) throws InterruptedException { ByteBuffer b; - try(Locker.Lock lock = _locker.lock()) + try (Locker.Lock lock = _locker.lock()) { while (BufferUtil.isEmpty(_out) && !isOutputShutdown()) { - if (!_hasOutput.await(time,unit)) + if (!_hasOutput.await(time, unit)) return null; } - b=_out; - _out=BufferUtil.allocate(b.capacity()); + b = _out; + _out = BufferUtil.allocate(b.capacity()); } getWriteFlusher().completeWrite(); return b; } - /* ------------------------------------------------------------ */ /** * @return Returns the out. */ @@ -360,50 +336,46 @@ public class ByteArrayEndPoint extends AbstractEndPoint return takeOutputString(StandardCharsets.UTF_8); } - /* ------------------------------------------------------------ */ /** * @param charset the charset to encode the output as * @return Returns the out. */ public String takeOutputString(Charset charset) { - ByteBuffer buffer=takeOutput(); - return BufferUtil.toString(buffer,charset); + ByteBuffer buffer = takeOutput(); + return BufferUtil.toString(buffer, charset); } - /* ------------------------------------------------------------ */ /** * @param out The out to set. */ public void setOutput(ByteBuffer out) { - try(Locker.Lock lock = _locker.lock()) + try (Locker.Lock lock = _locker.lock()) { _out = out; } getWriteFlusher().completeWrite(); } - /* ------------------------------------------------------------ */ /** * @return true if there are bytes remaining to be read from the encoded input */ public boolean hasMore() { - return getOutput().position()>0; + return getOutput().position() > 0; } - /* ------------------------------------------------------------ */ /* * @see org.eclipse.io.EndPoint#fill(org.eclipse.io.Buffer) */ @Override public int fill(ByteBuffer buffer) throws IOException { - int filled=0; - try(Locker.Lock lock = _locker.lock()) + int filled = 0; + try (Locker.Lock lock = _locker.lock()) { - while(true) + while (true) { if (!isOpen()) throw new EofException("CLOSED"); @@ -414,16 +386,16 @@ public class ByteArrayEndPoint extends AbstractEndPoint if (_inQ.isEmpty()) break; - ByteBuffer in= _inQ.peek(); + ByteBuffer in = _inQ.peek(); if (isEOF(in)) { - filled=-1; + filled = -1; break; } if (BufferUtil.hasContent(in)) { - filled=BufferUtil.append(buffer,in); + filled = BufferUtil.append(buffer, in); if (BufferUtil.isEmpty(in)) _inQ.poll(); break; @@ -432,51 +404,50 @@ public class ByteArrayEndPoint extends AbstractEndPoint } } - if (filled>0) + if (filled > 0) notIdle(); - else if (filled<0) + else if (filled < 0) shutdownInput(); return filled; } - /* ------------------------------------------------------------ */ /* * @see org.eclipse.io.EndPoint#flush(org.eclipse.io.Buffer, org.eclipse.io.Buffer, org.eclipse.io.Buffer) */ @Override public boolean flush(ByteBuffer... buffers) throws IOException { - boolean flushed=true; - try(Locker.Lock lock = _locker.lock()) + boolean flushed = true; + try (Locker.Lock lock = _locker.lock()) { if (!isOpen()) throw new IOException("CLOSED"); if (isOutputShutdown()) throw new IOException("OSHUT"); - - boolean idle=true; + + boolean idle = true; for (ByteBuffer b : buffers) { if (BufferUtil.hasContent(b)) { - if (_growOutput && b.remaining()>BufferUtil.space(_out)) + if (_growOutput && b.remaining() > BufferUtil.space(_out)) { BufferUtil.compact(_out); - if (b.remaining()>BufferUtil.space(_out)) + if (b.remaining() > BufferUtil.space(_out)) { - ByteBuffer n = BufferUtil.allocate(_out.capacity()+b.remaining()*2); - BufferUtil.append(n,_out); - _out=n; + ByteBuffer n = BufferUtil.allocate(_out.capacity() + b.remaining() * 2); + BufferUtil.append(n, _out); + _out = n; } } - if (BufferUtil.append(_out,b)>0) - idle=false; + if (BufferUtil.append(_out, b) > 0) + idle = false; if (BufferUtil.hasContent(b)) { - flushed=false; + flushed = false; break; } } @@ -490,14 +461,13 @@ public class ByteArrayEndPoint extends AbstractEndPoint return flushed; } - /* ------------------------------------------------------------ */ /** * */ @Override public void reset() { - try(Locker.Lock lock = _locker.lock()) + try (Locker.Lock lock = _locker.lock()) { _inQ.clear(); _hasOutput.signalAll(); @@ -506,7 +476,6 @@ public class ByteArrayEndPoint extends AbstractEndPoint super.reset(); } - /* ------------------------------------------------------------ */ /* * @see org.eclipse.io.EndPoint#getConnection() */ @@ -516,7 +485,6 @@ public class ByteArrayEndPoint extends AbstractEndPoint return null; } - /* ------------------------------------------------------------ */ /** * @return the growOutput */ @@ -525,41 +493,39 @@ public class ByteArrayEndPoint extends AbstractEndPoint return _growOutput; } - /* ------------------------------------------------------------ */ /** * @param growOutput the growOutput to set */ public void setGrowOutput(boolean growOutput) { - _growOutput=growOutput; + _growOutput = growOutput; } - /* ------------------------------------------------------------ */ @Override public String toString() { int q; ByteBuffer b; String o; - try(Locker.Lock lock = _locker.lock()) + try (Locker.Lock lock = _locker.lock()) { - q=_inQ.size(); - b=_inQ.peek(); - o=BufferUtil.toDetailString(_out); + q = _inQ.size(); + b = _inQ.peek(); + o = BufferUtil.toDetailString(_out); } - return String.format("%s[q=%d,q[0]=%s,o=%s]",super.toString(),q,b,o); + return String.format("%s[q=%d,q[0]=%s,o=%s]", super.toString(), q, b, o); } - /* ------------------------------------------------------------ */ /** * Compares a ByteBuffer Object to EOF by Reference + * * @param buffer the input ByteBuffer to be compared to EOF * @return Whether the reference buffer is equal to that of EOF */ private static boolean isEOF(ByteBuffer buffer) { @SuppressWarnings("ReferenceEquality") - boolean is_EOF = (buffer==EOF); - return is_EOF; + boolean isEof = (buffer == EOF); + return isEof; } } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferOutputStream.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferOutputStream.java new file mode 100644 index 00000000000..fc68e4714b9 --- /dev/null +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferOutputStream.java @@ -0,0 +1,62 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.io; + +import java.io.OutputStream; +import java.nio.ByteBuffer; + +import org.eclipse.jetty.util.BufferUtil; + +/** + * Simple wrapper of a ByteBuffer as an OutputStream. + * The buffer does not grow and this class will throw an + * {@link java.nio.BufferOverflowException} if the buffer capacity is exceeded. + */ +public class ByteBufferOutputStream extends OutputStream +{ + final ByteBuffer _buffer; + + public ByteBufferOutputStream(ByteBuffer buffer) + { + _buffer = buffer; + } + + public void close() + { + } + + public void flush() + { + } + + public void write(byte[] b) + { + write(b, 0, b.length); + } + + public void write(byte[] b, int off, int len) + { + BufferUtil.append(_buffer, b, off, len); + } + + public void write(int b) + { + BufferUtil.append(_buffer, (byte)b); + } +} diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java index d8f834498d1..3c41615bea8 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -24,6 +24,7 @@ import java.util.Deque; import java.util.List; import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; import org.eclipse.jetty.util.BufferUtil; @@ -40,12 +41,12 @@ public interface ByteBufferPool *

        The returned buffer may have a bigger capacity than the size being * requested but it will have the limit set to the given size.

        * - * @param size the size of the buffer + * @param size the size of the buffer * @param direct whether the buffer must be direct or not * @return the requested buffer * @see #release(ByteBuffer) */ - public ByteBuffer acquire(int size, boolean direct); + ByteBuffer acquire(int size, boolean direct); /** *

        Returns a {@link ByteBuffer}, usually obtained with {@link #acquire(int, boolean)} @@ -54,14 +55,21 @@ public interface ByteBufferPool * @param buffer the buffer to return * @see #acquire(int, boolean) */ - public void release(ByteBuffer buffer); + void release(ByteBuffer buffer); + /** + *

        Creates a new ByteBuffer of the given capacity and the given directness.

        + * + * @param capacity the ByteBuffer capacity + * @param direct the ByteBuffer directness + * @return a newly allocated ByteBuffer + */ default ByteBuffer newByteBuffer(int capacity, boolean direct) { return direct ? BufferUtil.allocateDirect(capacity) : BufferUtil.allocate(capacity); } - public static class Lease + class Lease { private final ByteBufferPool byteBufferPool; private final List buffers; @@ -102,7 +110,9 @@ public interface ByteBufferPool { long length = 0; for (ByteBuffer buffer : buffers) + { length += buffer.remaining(); + } return length; } @@ -129,49 +139,75 @@ public interface ByteBufferPool private final Deque _queue = new ConcurrentLinkedDeque<>(); private final ByteBufferPool _pool; private final int _capacity; - private final AtomicInteger _space; + private final int _maxSize; + private final AtomicInteger _size; + private long _lastUpdate = System.nanoTime(); - public Bucket(ByteBufferPool pool, int bufferSize, int maxSize) + public Bucket(ByteBufferPool pool, int capacity, int maxSize) { _pool = pool; - _capacity = bufferSize; - _space = maxSize > 0 ? new AtomicInteger(maxSize) : null; + _capacity = capacity; + _maxSize = maxSize; + _size = maxSize > 0 ? new AtomicInteger() : null; } + public ByteBuffer acquire() + { + ByteBuffer buffer = queuePoll(); + if (buffer == null) + return null; + if (_size != null) + _size.decrementAndGet(); + return buffer; + } + + /** + * @param direct whether to create a direct buffer when none is available + * @return a ByteBuffer + * @deprecated use {@link #acquire()} instead + */ + @Deprecated public ByteBuffer acquire(boolean direct) { ByteBuffer buffer = queuePoll(); if (buffer == null) return _pool.newByteBuffer(_capacity, direct); - if (_space != null) - _space.incrementAndGet(); + if (_size != null) + _size.decrementAndGet(); return buffer; } public void release(ByteBuffer buffer) { + _lastUpdate = System.nanoTime(); BufferUtil.clear(buffer); - if (_space == null) + if (_size == null) queueOffer(buffer); - else if (_space.decrementAndGet() >= 0) + else if (_size.incrementAndGet() <= _maxSize) queueOffer(buffer); else - _space.incrementAndGet(); + _size.decrementAndGet(); } public void clear() { - if (_space == null) + clear(null); + } + + void clear(Consumer memoryFn) + { + int size = _size == null ? 0 : _size.get() - 1; + while (size >= 0) { - queueClear(); - } - else - { - int s = _space.getAndSet(0); - while (s-- > 0) + ByteBuffer buffer = queuePoll(); + if (buffer == null) + break; + if (memoryFn != null) + memoryFn.accept(buffer); + if (_size != null) { - if (queuePoll() == null) - _space.incrementAndGet(); + _size.decrementAndGet(); + --size; } } } @@ -186,11 +222,6 @@ public interface ByteBufferPool return _queue.poll(); } - private void queueClear() - { - _queue.clear(); - } - boolean isEmpty() { return _queue.isEmpty(); @@ -201,10 +232,15 @@ public interface ByteBufferPool return _queue.size(); } + long getLastUpdate() + { + return _lastUpdate; + } + @Override public String toString() { - return String.format("Bucket@%x{%d/%d}", hashCode(), size(), _capacity); + return String.format("%s@%x{%d/%d@%d}", getClass().getSimpleName(), hashCode(), size(), _maxSize, _capacity); } } } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ChannelEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ChannelEndPoint.java index ed6a761c041..8dd474e05db 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ChannelEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ChannelEndPoint.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -31,7 +31,6 @@ import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.thread.Invocable; -import org.eclipse.jetty.util.thread.Locker; import org.eclipse.jetty.util.thread.Scheduler; /** @@ -58,19 +57,19 @@ public abstract class ChannelEndPoint extends AbstractEndPoint implements Manage */ protected int _desiredInterestOps; - private abstract class RunnableTask implements Runnable, Invocable + private abstract class RunnableTask implements Runnable, Invocable { final String _operation; protected RunnableTask(String op) { - _operation=op; + _operation = op; } @Override public String toString() { - return String.format("CEP:%s:%s:%s",ChannelEndPoint.this,_operation,getInvocationType()); + return String.format("CEP:%s:%s:%s", ChannelEndPoint.this, _operation, getInvocationType()); } } @@ -111,7 +110,7 @@ public abstract class ChannelEndPoint extends AbstractEndPoint implements Manage { return getFillInterest().getCallbackInvocationType(); } - + @Override public void run() { @@ -126,7 +125,7 @@ public abstract class ChannelEndPoint extends AbstractEndPoint implements Manage { return getWriteFlusher().getCallbackInvocationType(); } - + @Override public void run() { @@ -136,9 +135,8 @@ public abstract class ChannelEndPoint extends AbstractEndPoint implements Manage @Override public String toString() { - return String.format("CEP:%s:%s:%s->%s",ChannelEndPoint.this,_operation,getInvocationType(),getWriteFlusher()); + return String.format("CEP:%s:%s:%s->%s", ChannelEndPoint.this, _operation, getInvocationType(), getWriteFlusher()); } - }; private final Runnable _runCompleteWriteFillable = new RunnableCloseable("runCompleteWriteFillable") @@ -148,18 +146,18 @@ public abstract class ChannelEndPoint extends AbstractEndPoint implements Manage { InvocationType fillT = getFillInterest().getCallbackInvocationType(); InvocationType flushT = getWriteFlusher().getCallbackInvocationType(); - if (fillT==flushT) + if (fillT == flushT) return fillT; - - if (fillT==InvocationType.EITHER && flushT==InvocationType.NON_BLOCKING) + + if (fillT == InvocationType.EITHER && flushT == InvocationType.NON_BLOCKING) return InvocationType.EITHER; - - if (fillT==InvocationType.NON_BLOCKING && flushT==InvocationType.EITHER) + + if (fillT == InvocationType.NON_BLOCKING && flushT == InvocationType.EITHER) return InvocationType.EITHER; - + return InvocationType.BLOCKING; } - + @Override public void run() { @@ -171,10 +169,10 @@ public abstract class ChannelEndPoint extends AbstractEndPoint implements Manage public ChannelEndPoint(ByteChannel channel, ManagedSelector selector, SelectionKey key, Scheduler scheduler) { super(scheduler); - _channel=channel; - _selector=selector; - _key=key; - _gather=(channel instanceof GatheringByteChannel)?(GatheringByteChannel)channel:null; + _channel = channel; + _selector = selector; + _key = key; + _gather = (channel instanceof GatheringByteChannel) ? (GatheringByteChannel)channel : null; } @Override @@ -217,7 +215,7 @@ public abstract class ChannelEndPoint extends AbstractEndPoint implements Manage } finally { - if (_selector!=null) + if (_selector != null) _selector.destroyEndPoint(this); } } @@ -228,51 +226,50 @@ public abstract class ChannelEndPoint extends AbstractEndPoint implements Manage if (isInputShutdown()) return -1; - int pos=BufferUtil.flipToFill(buffer); + int pos = BufferUtil.flipToFill(buffer); + int filled; try { - int filled = _channel.read(buffer); - if (LOG.isDebugEnabled()) // Avoid boxing of variable 'filled' - LOG.debug("filled {} {}", filled, this); - - if (filled>0) + filled = _channel.read(buffer); + if (filled > 0) notIdle(); - else if (filled==-1) + else if (filled == -1) shutdownInput(); - - return filled; } - catch(IOException e) + catch (IOException e) { LOG.debug(e); shutdownInput(); - return -1; + filled = -1; } finally { - BufferUtil.flipToFlush(buffer,pos); + BufferUtil.flipToFlush(buffer, pos); } + if (LOG.isDebugEnabled()) + LOG.debug("filled {} {}", filled, BufferUtil.toDetailString(buffer)); + return filled; } @Override public boolean flush(ByteBuffer... buffers) throws IOException { - long flushed=0; + long flushed = 0; try { - if (buffers.length==1) - flushed=_channel.write(buffers[0]); - else if (_gather!=null && buffers.length>1) - flushed=_gather.write(buffers,0,buffers.length); + if (buffers.length == 1) + flushed = _channel.write(buffers[0]); + else if (_gather != null && buffers.length > 1) + flushed = _gather.write(buffers, 0, buffers.length); else { for (ByteBuffer b : buffers) { if (b.hasRemaining()) { - int l=_channel.write(b); - if (l>0) - flushed+=l; + int l = _channel.write(b); + if (l > 0) + flushed += l; if (b.hasRemaining()) break; } @@ -286,12 +283,14 @@ public abstract class ChannelEndPoint extends AbstractEndPoint implements Manage throw new EofException(e); } - if (flushed>0) + if (flushed > 0) notIdle(); for (ByteBuffer b : buffers) + { if (!BufferUtil.isEmpty(b)) return false; + } return true; } @@ -307,7 +306,6 @@ public abstract class ChannelEndPoint extends AbstractEndPoint implements Manage return _channel; } - @Override protected void needsFillInterest() { @@ -330,7 +328,7 @@ public abstract class ChannelEndPoint extends AbstractEndPoint implements Manage int readyOps = _key.readyOps(); int oldInterestOps; int newInterestOps; - synchronized(this) + synchronized (this) { _updatePending = true; // Remove the readyOps, that here can only be OP_READ or OP_WRITE (or both). @@ -346,16 +344,16 @@ public abstract class ChannelEndPoint extends AbstractEndPoint implements Manage LOG.debug("onSelected {}->{} r={} w={} for {}", oldInterestOps, newInterestOps, fillable, flushable, this); // return task to complete the job - Runnable task= fillable - ? (flushable - ? _runCompleteWriteFillable - : _runFillable) - : (flushable - ? _runCompleteWrite - : null); + Runnable task = fillable + ? (flushable + ? _runCompleteWriteFillable + : _runFillable) + : (flushable + ? _runCompleteWrite + : null); if (LOG.isDebugEnabled()) - LOG.debug("task {}",task); + LOG.debug("task {}", task); return task; } @@ -370,7 +368,7 @@ public abstract class ChannelEndPoint extends AbstractEndPoint implements Manage { int oldInterestOps; int newInterestOps; - synchronized(this) + synchronized (this) { _updatePending = false; oldInterestOps = _currentInterestOps; @@ -407,7 +405,7 @@ public abstract class ChannelEndPoint extends AbstractEndPoint implements Manage int oldInterestOps; int newInterestOps; boolean pending; - synchronized(this) + synchronized (this) { pending = _updatePending; oldInterestOps = _desiredInterestOps; @@ -419,7 +417,7 @@ public abstract class ChannelEndPoint extends AbstractEndPoint implements Manage if (LOG.isDebugEnabled()) LOG.debug("changeInterests p={} {}->{} for {}", pending, oldInterestOps, newInterestOps, this); - if (!pending && _selector!=null) + if (!pending && _selector != null) _selector.submit(_updateKeyAction); } @@ -427,21 +425,11 @@ public abstract class ChannelEndPoint extends AbstractEndPoint implements Manage public String toEndPointString() { // We do a best effort to print the right toString() and that's it. - try - { - boolean valid = _key != null && _key.isValid(); - int keyInterests = valid ? _key.interestOps() : -1; - int keyReadiness = valid ? _key.readyOps() : -1; - return String.format("%s{io=%d/%d,kio=%d,kro=%d}", - super.toEndPointString(), - _currentInterestOps, - _desiredInterestOps, - keyInterests, - keyReadiness); - } - catch (Throwable x) - { - return String.format("%s{io=%s,kio=-2,kro=-2}", super.toString(), _desiredInterestOps); - } + return String.format("%s{io=%d/%d,kio=%d,kro=%d}", + super.toEndPointString(), + _currentInterestOps, + _desiredInterestOps, + ManagedSelector.safeInterestOps(_key), + ManagedSelector.safeReadyOps(_key)); } } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ClientConnectionFactory.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ClientConnectionFactory.java index e6aa50ce1b0..9cddb8e6b92 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ClientConnectionFactory.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ClientConnectionFactory.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -28,18 +28,17 @@ import org.eclipse.jetty.util.component.ContainerLifeCycle; */ public interface ClientConnectionFactory { - public static final String CONNECTOR_CONTEXT_KEY = "client.connector"; + String CONNECTOR_CONTEXT_KEY = "client.connector"; /** - * * @param endPoint the {@link org.eclipse.jetty.io.EndPoint} to link the newly created connection to * @param context the context data to create the connection * @return a new {@link Connection} * @throws IOException if the connection cannot be created */ - public Connection newConnection(EndPoint endPoint, Map context) throws IOException; + Connection newConnection(EndPoint endPoint, Map context) throws IOException; - public default Connection customize(Connection connection, Map context) + default Connection customize(Connection connection, Map context) { ContainerLifeCycle connector = (ContainerLifeCycle)context.get(CONNECTOR_CONTEXT_KEY); connector.getBeans(Connection.Listener.class).forEach(connection::addListener); diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/Connection.java b/jetty-io/src/main/java/org/eclipse/jetty/io/Connection.java index 0414ad906bd..1e48e8e1787 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/Connection.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/Connection.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -38,32 +38,32 @@ public interface Connection extends Closeable * * @param listener the listener to add */ - public void addListener(Listener listener); + void addListener(Listener listener); /** *

        Removes a listener of connection events.

        * * @param listener the listener to remove */ - public void removeListener(Listener listener); + void removeListener(Listener listener); /** *

        Callback method invoked when this connection is opened.

        *

        Creators of the connection implementation are responsible for calling this method.

        */ - public void onOpen(); + void onOpen(); /** *

        Callback method invoked when this connection is closed.

        *

        Creators of the connection implementation are responsible for calling this method.

        */ - public void onClose(); + void onClose(); /** * @return the {@link EndPoint} associated with this Connection. */ - public EndPoint getEndPoint(); - + EndPoint getEndPoint(); + /** *

        Performs a logical close of this connection.

        *

        For simple connections, this may just mean to delegate the close to the associated @@ -71,7 +71,7 @@ public interface Connection extends Closeable * before closing the associated {@link EndPoint}.

        */ @Override - public void close(); + void close(); /** *

        Callback method invoked upon an idle timeout event.

        @@ -82,17 +82,21 @@ public interface Connection extends Closeable * immediately and the EndPoint left in the state it was before the idle timeout event.

        * * @return true to let the EndPoint handle the idle timeout, - * false to tell the EndPoint to halt the handling of the idle timeout. + * false to tell the EndPoint to halt the handling of the idle timeout. */ - public boolean onIdleExpired(); + boolean onIdleExpired(); - public long getMessagesIn(); - public long getMessagesOut(); - public long getBytesIn(); - public long getBytesOut(); - public long getCreatedTimeStamp(); - - public interface UpgradeFrom + long getMessagesIn(); + + long getMessagesOut(); + + long getBytesIn(); + + long getBytesOut(); + + long getCreatedTimeStamp(); + + interface UpgradeFrom { /** *

        Takes the input buffer from the connection on upgrade.

        @@ -104,12 +108,13 @@ public interface Connection extends Closeable */ ByteBuffer onUpgradeFrom(); } - - public interface UpgradeTo + + interface UpgradeTo { /** *

        Callback method invoked when this connection is upgraded.

        *

        This must be called before {@link #onOpen()}.

        + * * @param prefilled An optional buffer that can contain prefilled data. Typically this * results from an upgrade of one protocol to the other where the old connection has buffered * data destined for the new connection. The new connection must take ownership of the buffer @@ -117,8 +122,8 @@ public interface Connection extends Closeable */ void onUpgradeTo(ByteBuffer prefilled); } - - /** + + /** *

        A Listener for connection events.

        *

        Listeners can be added to a {@link Connection} to get open and close events. * The AbstractConnectionFactory implements a pattern where objects implement @@ -126,13 +131,13 @@ public interface Connection extends Closeable * the Connector or ConnectionFactory are added as listeners to all new connections *

        */ - public interface Listener + interface Listener { - public void onOpened(Connection connection); + void onOpened(Connection connection); - public void onClosed(Connection connection); + void onClosed(Connection connection); - public static class Adapter implements Listener + class Adapter implements Listener { @Override public void onOpened(Connection connection) diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ConnectionStatistics.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ConnectionStatistics.java index 871d57c6353..bf062408cb0 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ConnectionStatistics.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ConnectionStatistics.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,8 +19,6 @@ package org.eclipse.jetty.io; import java.io.IOException; -import java.util.ArrayList; -import java.util.List; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.LongAdder; @@ -29,7 +27,6 @@ import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.annotation.ManagedOperation; import org.eclipse.jetty.util.component.AbstractLifeCycle; -import org.eclipse.jetty.util.component.ContainerLifeCycle; import org.eclipse.jetty.util.component.Dumpable; import org.eclipse.jetty.util.statistic.CounterStatistic; import org.eclipse.jetty.util.statistic.SampleStatistic; @@ -210,19 +207,17 @@ public class ConnectionStatistics extends AbstractLifeCycle implements Connectio @Override public String dump() { - return ContainerLifeCycle.dump(this); + return Dumpable.dump(this); } @Override public void dump(Appendable out, String indent) throws IOException { - ContainerLifeCycle.dumpObject(out, this); - List children = new ArrayList<>(); - children.add(String.format("connections=%s", _connections)); - children.add(String.format("durations=%s", _connectionsDuration)); - children.add(String.format("bytes in/out=%s/%s", getReceivedBytes(), getSentBytes())); - children.add(String.format("messages in/out=%s/%s", getReceivedMessages(), getSentMessages())); - ContainerLifeCycle.dump(out, indent, children); + Dumpable.dumpObjects(out, indent, this, + String.format("connections=%s", _connections), + String.format("durations=%s", _connectionsDuration), + String.format("bytes in/out=%s/%s", getReceivedBytes(), getSentBytes()), + String.format("messages in/out=%s/%s", getReceivedMessages(), getSentMessages())); } @Override diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/CyclicTimeout.java b/jetty-io/src/main/java/org/eclipse/jetty/io/CyclicTimeout.java index 7eca7e18722..211b1e11ed2 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/CyclicTimeout.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/CyclicTimeout.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -33,6 +33,20 @@ import static java.lang.Long.MAX_VALUE; *

        Subclasses should implement {@link #onTimeoutExpired()}.

        *

        This implementation is optimised assuming that the timeout * will mostly be cancelled and then reused with a similar value.

        + *

        This implementation has a {@link Timeout} holding the time + * at which the scheduled task should fire, and a linked list of + * {@link Wakeup}, each holding the actual scheduled task.

        + *

        Calling {@link #schedule(long, TimeUnit)} the first time will + * create a Timeout with an associated Wakeup and submit a task to + * the scheduler. + * Calling {@link #schedule(long, TimeUnit)} again with the same or + * a larger delay will cancel the previous Timeout, but keep the + * previous Wakeup without submitting a new task to the scheduler, + * therefore reducing the pressure on the scheduler and avoid it + * becomes a bottleneck. + * When the Wakeup task fires, it will see that the Timeout is now + * in the future and will attach a new Wakeup with the future time + * to the Timeout, and submit a scheduler task for the new Wakeup.

        */ public abstract class CyclicTimeout implements Destroyable { @@ -59,38 +73,38 @@ public abstract class CyclicTimeout implements Destroyable } /** - * Schedules a timeout, even if already set, cancelled or expired. + *

        Schedules a timeout, even if already set, cancelled or expired.

        + *

        If a timeout is already set, it will be cancelled and replaced + * by the new one.

        * * @param delay The period of time before the timeout expires. * @param units The unit of time of the period. - * @return true if the timer was already set. + * @return true if the timeout was already set. */ public boolean schedule(long delay, TimeUnit units) { long now = System.nanoTime(); - long new_timeout_at = now + units.toNanos(delay); + long newTimeoutAt = now + units.toNanos(delay); + Wakeup newWakeup = null; boolean result; - Wakeup new_wakeup; while (true) { Timeout timeout = _timeout.get(); - - new_wakeup = null; result = timeout._at != MAX_VALUE; // Is the current wakeup good to use? ie before our timeout time? Wakeup wakeup = timeout._wakeup; - if (wakeup == null || wakeup._at > new_timeout_at) + if (wakeup == null || wakeup._at > newTimeoutAt) // No, we need an earlier wakeup. - wakeup = new_wakeup = new Wakeup(new_timeout_at, wakeup); + wakeup = newWakeup = new Wakeup(newTimeoutAt, wakeup); - if (_timeout.compareAndSet(timeout, new Timeout(new_timeout_at, wakeup))) + if (_timeout.compareAndSet(timeout, new Timeout(newTimeoutAt, wakeup))) { if (LOG.isDebugEnabled()) LOG.debug("Installed timeout in {} ms, waking up in {} ms", - units.toMillis(delay), - TimeUnit.NANOSECONDS.toMillis(wakeup._at - now)); + units.toMillis(delay), + TimeUnit.NANOSECONDS.toMillis(wakeup._at - now)); break; } } @@ -98,8 +112,8 @@ public abstract class CyclicTimeout implements Destroyable // If we created a new wakeup, we need to actually schedule it. // Any wakeup that is created and discarded by the failed CAS will not be // in the wakeup chain, will not have a scheduler task set and will be GC'd. - if (new_wakeup != null) - new_wakeup.schedule(now); + if (newWakeup != null) + newWakeup.schedule(now); return result; } @@ -114,15 +128,13 @@ public abstract class CyclicTimeout implements Destroyable public boolean cancel() { boolean result; - Timeout timeout; - Timeout new_timeout; while (true) { - timeout = _timeout.get(); + Timeout timeout = _timeout.get(); result = timeout._at != MAX_VALUE; Wakeup wakeup = timeout._wakeup; - new_timeout = wakeup == null ? NOT_SET : new Timeout(MAX_VALUE, wakeup); - if (_timeout.compareAndSet(timeout, new_timeout)) + Timeout newTimeout = wakeup == null ? NOT_SET : new Timeout(MAX_VALUE, wakeup); + if (_timeout.compareAndSet(timeout, newTimeout)) break; } return result; @@ -166,7 +178,11 @@ public abstract class CyclicTimeout implements Destroyable @Override public String toString() { - return String.format("%s@%x:%d,%s", getClass().getSimpleName(), hashCode(), _at, _wakeup); + return String.format("%s@%x:%dms,%s", + getClass().getSimpleName(), + hashCode(), + TimeUnit.NANOSECONDS.toMillis(_at - System.nanoTime()), + _wakeup); } } @@ -200,10 +216,9 @@ public abstract class CyclicTimeout implements Destroyable @Override public void run() { - long now; - Wakeup new_wakeup; - boolean has_expired; - + long now = System.nanoTime(); + Wakeup newWakeup = null; + boolean hasExpired = false; while (true) { Timeout timeout = _timeout.get(); @@ -226,21 +241,17 @@ public abstract class CyclicTimeout implements Destroyable // Not found, we become a noop. return; - now = System.nanoTime(); - new_wakeup = null; - has_expired = false; - Timeout new_timeout; - // We are in the wakeup list! So we have to act and we know our // tail has not expired (else it would have removed us from the list). // Remove ourselves (and any prior Wakeup) from the wakeup list. wakeup = wakeup._next; + Timeout newTimeout; if (timeout._at <= now) { // We have timed out! - has_expired = true; - new_timeout = wakeup == null ? NOT_SET : new Timeout(MAX_VALUE, wakeup); + hasExpired = true; + newTimeout = wakeup == null ? NOT_SET : new Timeout(MAX_VALUE, wakeup); } else if (timeout._at != MAX_VALUE) { @@ -248,33 +259,37 @@ public abstract class CyclicTimeout implements Destroyable // Is the current wakeup good to use? ie before our timeout time? if (wakeup == null || wakeup._at >= timeout._at) // No, we need an earlier wakeup. - wakeup = new_wakeup = new Wakeup(timeout._at, wakeup); - new_timeout = new Timeout(timeout._at, wakeup); + wakeup = newWakeup = new Wakeup(timeout._at, wakeup); + newTimeout = new Timeout(timeout._at, wakeup); } else { // We don't timeout, preserve scheduled chain. - new_timeout = wakeup == null ? NOT_SET : new Timeout(MAX_VALUE, wakeup); + newTimeout = wakeup == null ? NOT_SET : new Timeout(MAX_VALUE, wakeup); } // Loop until we succeed in changing state or we are a noop! - if (_timeout.compareAndSet(timeout, new_timeout)) + if (_timeout.compareAndSet(timeout, newTimeout)) break; } // If we created a new wakeup, we need to actually schedule it. - if (new_wakeup != null) - new_wakeup.schedule(now); + if (newWakeup != null) + newWakeup.schedule(now); // If we expired, then do the callback. - if (has_expired) + if (hasExpired) onTimeoutExpired(); } @Override public String toString() { - return String.format("%s@%x:%d->%s", getClass().getSimpleName(), hashCode(), _at, _next); + return String.format("%s@%x:%dms->%s", + getClass().getSimpleName(), + hashCode(), + _at == MAX_VALUE ? _at : TimeUnit.NANOSECONDS.toMillis(_at - System.nanoTime()), + _next); } } } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/EndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/EndPoint.java index c1a2613547a..3f6a7bcaf42 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/EndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/EndPoint.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -31,7 +31,6 @@ import org.eclipse.jetty.util.IteratingCallback; import org.eclipse.jetty.util.thread.Invocable; /** - * * A transport EndPoint * *

        Asynchronous Methods

        @@ -95,29 +94,26 @@ import org.eclipse.jetty.util.thread.Invocable; *
        */ public interface EndPoint extends Closeable -{ - /* ------------------------------------------------------------ */ +{ + /** * @return The local Inet address to which this EndPoint is bound, or null * if this EndPoint does not represent a network connection. */ InetSocketAddress getLocalAddress(); - /* ------------------------------------------------------------ */ /** * @return The remote Inet address to which this EndPoint is bound, or null * if this EndPoint does not represent a network connection. */ InetSocketAddress getRemoteAddress(); - /* ------------------------------------------------------------ */ boolean isOpen(); - /* ------------------------------------------------------------ */ long getCreatedTimeStamp(); - /* ------------------------------------------------------------ */ - /** Shutdown the output. + /** + * Shutdown the output. *

        This call indicates that no more data will be sent on this endpoint that * that the remote end should read an EOF once all previously sent data has been * consumed. Shutdown may be done either at the TCP/IP level, as a protocol exchange (Eg @@ -128,20 +124,22 @@ public interface EndPoint extends Closeable */ void shutdownOutput(); - /* ------------------------------------------------------------ */ - /** Test if output is shutdown. + /** + * Test if output is shutdown. * The output is shutdown by a call to {@link #shutdownOutput()} * or {@link #close()}. + * * @return true if the output is shutdown or the endpoint is closed. */ boolean isOutputShutdown(); - /* ------------------------------------------------------------ */ - /** Test if the input is shutdown. + /** + * Test if the input is shutdown. * The input is shutdown if an EOF has been read while doing * a {@link #fill(ByteBuffer)}. Once the input is shutdown, all calls to * {@link #fill(ByteBuffer)} will return -1, until such time as the * end point is close, when they will return {@link EofException}. + * * @return True if the input is shutdown or the endpoint is closed. */ boolean isInputShutdown(); @@ -165,11 +163,11 @@ public interface EndPoint extends Closeable */ int fill(ByteBuffer buffer) throws IOException; - /** * Flush data from the passed header/buffer to this endpoint. As many bytes as can be consumed * are taken from the header/buffer position up until the buffer limit. The header/buffers position * is updated to indicate how many bytes have been consumed. + * * @param buffer the buffers to flush * @return True IFF all the buffers have been consumed and the endpoint has flushed the data to its * destination (ie is not buffering any data). @@ -177,32 +175,32 @@ public interface EndPoint extends Closeable */ boolean flush(ByteBuffer... buffer) throws IOException; - /* ------------------------------------------------------------ */ /** * @return The underlying transport object (socket, channel, etc.) */ Object getTransport(); - /* ------------------------------------------------------------ */ - /** Get the max idle time in ms. + /** + * Get the max idle time in ms. *

        The max idle time is the time the endpoint can be idle before * extraordinary handling takes place. + * * @return the max idle time in ms or if ms <= 0 implies an infinite timeout */ long getIdleTimeout(); - /* ------------------------------------------------------------ */ - /** Set the idle timeout. + /** + * Set the idle timeout. + * * @param idleTimeout the idle timeout in MS. Timeout <= 0 implies an infinite timeout */ void setIdleTimeout(long idleTimeout); - /** *

        Requests callback methods to be invoked when a call to {@link #fill(ByteBuffer)} would return data or EOF.

        * * @param callback the callback to call when an error occurs or we are readable. The callback may implement the {@link Invocable} interface to - * self declare its blocking status. Non-blocking callbacks may be called more efficiently without dispatch delays. + * self declare its blocking status. Non-blocking callbacks may be called more efficiently without dispatch delays. * @throws ReadPendingException if another read operation is concurrent. */ void fillInterested(Callback callback) throws ReadPendingException; @@ -248,28 +246,33 @@ public interface EndPoint extends Closeable /** *

        Callback method invoked when this {@link EndPoint} is opened.

        + * * @see #onClose() */ void onOpen(); /** *

        Callback method invoked when this {@link EndPoint} is close.

        + * * @see #onOpen() */ void onClose(); - /** Is the endpoint optimized for DirectBuffer usage + /** + * Is the endpoint optimized for DirectBuffer usage + * * @return True if direct buffers can be used optimally. */ boolean isOptimizedForDirectBuffers(); - - /** Upgrade connections. + /** + * Upgrade connections. * Close the old connection, update the endpoint and open the new connection. * If the oldConnection is an instance of {@link Connection.UpgradeFrom} then * a prefilled buffer is requested and passed to the newConnection if it is an instance * of {@link Connection.UpgradeTo} + * * @param newConnection The connection to upgrade to */ - public void upgrade(Connection newConnection); + void upgrade(Connection newConnection); } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/EofException.java b/jetty-io/src/main/java/org/eclipse/jetty/io/EofException.java index 7c4e788abc5..fc8c0aa21e0 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/EofException.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/EofException.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,10 +20,9 @@ package org.eclipse.jetty.io; import java.io.EOFException; - -/* ------------------------------------------------------------ */ -/** A Jetty specialization of EOFException. - *

        This is thrown by Jetty to distinguish between EOF received from +/** + * A Jetty specialization of EOFException. + *

        This is thrown by Jetty to distinguish between EOF received from * the connection, vs and EOF thrown by some application talking to some other file/socket etc. * The only difference in handling is that Jetty EOFs are logged less verbosely. */ @@ -32,15 +31,15 @@ public class EofException extends EOFException implements QuietException public EofException() { } - + public EofException(String reason) { super(reason); } - + public EofException(Throwable th) { - if (th!=null) + if (th != null) initCause(th); } } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/FillInterest.java b/jetty-io/src/main/java/org/eclipse/jetty/io/FillInterest.java index 8cafdf56afd..6a90d9c2153 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/FillInterest.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/FillInterest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -35,7 +35,7 @@ import org.eclipse.jetty.util.thread.Invocable.InvocationType; */ public abstract class FillInterest { - private final static Logger LOG = Log.getLogger(FillInterest.class); + private static final Logger LOG = Log.getLogger(FillInterest.class); private final AtomicReference _interested = new AtomicReference<>(null); protected FillInterest() @@ -56,9 +56,9 @@ public abstract class FillInterest { LOG.warn("Read pending for {} prevented {}", _interested, callback); throw new ReadPendingException(); - } + } } - + /** * Call to register interest in a callback when a read is possible. * The callback will be called either immediately if {@link #needsFillInterest()} @@ -76,8 +76,8 @@ public abstract class FillInterest return false; if (LOG.isDebugEnabled()) - LOG.debug("interested {}",this); - + LOG.debug("interested {}", this); + try { needsFillInterest(); @@ -86,7 +86,7 @@ public abstract class FillInterest { onFail(e); } - + return true; } @@ -96,7 +96,7 @@ public abstract class FillInterest public boolean fillable() { if (LOG.isDebugEnabled()) - LOG.debug("fillable {}",this); + LOG.debug("fillable {}", this); Callback callback = _interested.get(); if (callback != null && _interested.compareAndSet(callback, null)) { @@ -104,7 +104,7 @@ public abstract class FillInterest return true; } if (LOG.isDebugEnabled()) - LOG.debug("{} lost race {}",this,callback); + LOG.debug("{} lost race {}", this, callback); return false; } @@ -115,7 +115,7 @@ public abstract class FillInterest { return _interested.get() != null; } - + public InvocationType getCallbackInvocationType() { Callback callback = _interested.get(); @@ -144,7 +144,7 @@ public abstract class FillInterest public void onClose() { if (LOG.isDebugEnabled()) - LOG.debug("onClose {}",this); + LOG.debug("onClose {}", this); Callback callback = _interested.get(); if (callback != null && _interested.compareAndSet(callback, null)) callback.failed(new ClosedChannelException()); @@ -156,10 +156,9 @@ public abstract class FillInterest return String.format("FillInterest@%x{%s}", hashCode(), _interested.get()); } - public String toStateString() { - return _interested.get()==null?"-":"FI"; + return _interested.get() == null ? "-" : "FI"; } /** @@ -169,5 +168,5 @@ public abstract class FillInterest * * @throws IOException if unable to fulfill interest in fill */ - abstract protected void needsFillInterest() throws IOException; + protected abstract void needsFillInterest() throws IOException; } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/IdleTimeout.java b/jetty-io/src/main/java/org/eclipse/jetty/io/IdleTimeout.java index caa29b8f59f..aae4b2c1449 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/IdleTimeout.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/IdleTimeout.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -40,18 +40,7 @@ public abstract class IdleTimeout private final Scheduler _scheduler; private final AtomicReference _timeout = new AtomicReference<>(); private volatile long _idleTimeout; - private volatile long _idleTimestamp = System.currentTimeMillis(); - - private final Runnable _idleTask = new Runnable() - { - @Override - public void run() - { - long idleLeft = checkIdleTimeout(); - if (idleLeft >= 0) - scheduleIdleTimeout(idleLeft > 0 ? idleLeft : getIdleTimeout()); - } - }; + private volatile long _idleTimestamp = System.nanoTime(); /** * @param scheduler A scheduler used to schedule checks for the idle timeout. @@ -65,22 +54,31 @@ public abstract class IdleTimeout { return _scheduler; } - - public long getIdleTimestamp() - { - return _idleTimestamp; - } + /** + * @return the period of time, in milliseconds, that this object was idle + */ public long getIdleFor() { - return System.currentTimeMillis() - getIdleTimestamp(); + return TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - _idleTimestamp); } + /** + * @return the idle timeout in milliseconds + * @see #setIdleTimeout(long) + */ public long getIdleTimeout() { return _idleTimeout; } + /** + *

        Sets the idle timeout in milliseconds.

        + *

        A value that is less than or zero disables the idle timeout checks.

        + * + * @param idleTimeout the idle timeout in milliseconds + * @see #getIdleTimeout() + */ public void setIdleTimeout(long idleTimeout) { long old = _idleTimeout; @@ -107,14 +105,21 @@ public abstract class IdleTimeout */ public void notIdle() { - _idleTimestamp = System.currentTimeMillis(); + _idleTimestamp = System.nanoTime(); + } + + private void idleCheck() + { + long idleLeft = checkIdleTimeout(); + if (idleLeft >= 0) + scheduleIdleTimeout(idleLeft > 0 ? idleLeft : getIdleTimeout()); } private void scheduleIdleTimeout(long delay) { Scheduler.Task newTimeout = null; if (isOpen() && delay > 0 && _scheduler != null) - newTimeout = _scheduler.schedule(_idleTask, delay, TimeUnit.MILLISECONDS); + newTimeout = _scheduler.schedule(this::idleCheck, delay, TimeUnit.MILLISECONDS); Scheduler.Task oldTimeout = _timeout.getAndSet(newTimeout); if (oldTimeout != null) oldTimeout.cancel(); @@ -128,7 +133,7 @@ public abstract class IdleTimeout private void activate() { if (_idleTimeout > 0) - _idleTask.run(); + idleCheck(); } public void onClose() @@ -147,15 +152,15 @@ public abstract class IdleTimeout { if (isOpen()) { - long idleTimestamp = getIdleTimestamp(); + long idleTimestamp = _idleTimestamp; + long idleElapsed = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - idleTimestamp); long idleTimeout = getIdleTimeout(); - long idleElapsed = System.currentTimeMillis() - idleTimestamp; long idleLeft = idleTimeout - idleElapsed; if (LOG.isDebugEnabled()) LOG.debug("{} idle timeout check, elapsed: {} ms, remaining: {} ms", this, idleElapsed, idleLeft); - if (idleTimestamp != 0 && idleTimeout > 0) + if (idleTimeout > 0) { if (idleLeft <= 0) { diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/LeakTrackingByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/LeakTrackingByteBufferPool.java index 1d8f150d0e2..300fceb2430 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/LeakTrackingByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/LeakTrackingByteBufferPool.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -47,7 +47,7 @@ public class LeakTrackingByteBufferPool extends ContainerLifeCycle implements By } }; - private final static boolean NOISY = Boolean.getBoolean(LeakTrackingByteBufferPool.class.getName() + ".NOISY"); + private static final boolean NOISY = Boolean.getBoolean(LeakTrackingByteBufferPool.class.getName() + ".NOISY"); private final ByteBufferPool delegate; private final AtomicLong leakedReleases = new AtomicLong(0); private final AtomicLong leakedAcquires = new AtomicLong(0); @@ -69,7 +69,7 @@ public class LeakTrackingByteBufferPool extends ContainerLifeCycle implements By { leakedAcquires.incrementAndGet(); LOG.info(String.format("ByteBuffer acquire %s leaked.acquired=%s", leakDetector.id(buffer), leaked ? "normal" : "LEAK"), - new Throwable("LeakStack.Acquire")); + new Throwable("LeakStack.Acquire")); } return buffer; } @@ -84,7 +84,7 @@ public class LeakTrackingByteBufferPool extends ContainerLifeCycle implements By { leakedReleases.incrementAndGet(); LOG.info(String.format("ByteBuffer release %s leaked.released=%s", leakDetector.id(buffer), leaked ? "normal" : "LEAK"), new Throwable( - "LeakStack.Release")); + "LeakStack.Release")); } delegate.release(buffer); } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ManagedSelector.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ManagedSelector.java index 801ce7bda87..d048ce6b312 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ManagedSelector.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ManagedSelector.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -31,11 +31,11 @@ import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayDeque; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.Deque; import java.util.Iterator; import java.util.List; +import java.util.Locale; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; @@ -61,6 +61,21 @@ import org.eclipse.jetty.util.thread.strategy.EatWhatYouKill; public class ManagedSelector extends ContainerLifeCycle implements Dumpable { private static final Logger LOG = Log.getLogger(ManagedSelector.class); + private static final boolean FORCE_SELECT_NOW; + + static + { + String property = System.getProperty("org.eclipse.jetty.io.forceSelectNow"); + if (property != null) + { + FORCE_SELECT_NOW = Boolean.parseBoolean(property); + } + else + { + property = System.getProperty("os.name"); + FORCE_SELECT_NOW = property != null && property.toLowerCase(Locale.ENGLISH).contains("windows"); + } + } private final AtomicBoolean _started = new AtomicBoolean(false); private boolean _selecting = false; @@ -77,8 +92,8 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable _id = id; SelectorProducer producer = new SelectorProducer(); Executor executor = selectorManager.getExecutor(); - _strategy = new EatWhatYouKill(producer,executor); - addBean(_strategy,true); + _strategy = new EatWhatYouKill(producer, executor); + addBean(_strategy, true); setStopTimeout(5000); } @@ -117,20 +132,20 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable @Override protected void doStop() throws Exception - { + { // doStop might be called for a failed managedSelector, // We do not want to wait twice, so we only stop once for each start - if (_started.compareAndSet(true,false)) + if (_started.compareAndSet(true, false)) { // Close connections, but only wait a single selector cycle for it to take effect - CloseConnections close_connections = new CloseConnections(); - submit(close_connections); - close_connections._complete.await(); + CloseConnections closeConnections = new CloseConnections(); + submit(closeConnections); + closeConnections._complete.await(); // Wait for any remaining endpoints to be closed and the selector to be stopped - StopSelector stop_selector = new StopSelector(); - submit(stop_selector); - stop_selector._stopped.await(); + StopSelector stopSelector = new StopSelector(); + submit(stopSelector); + stopSelector._stopped.await(); } super.doStop(); @@ -138,6 +153,7 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable /** * Submit an {@link SelectorUpdate} to be acted on between calls to {@link Selector#select()} + * * @param update The selector update to apply at next wakeup */ public void submit(SelectorUpdate update) @@ -146,10 +162,10 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable LOG.debug("Queued change {} on {}", update, this); Selector selector = null; - synchronized(ManagedSelector.this) + synchronized (ManagedSelector.this) { _updates.offer(update); - + if (_selecting) { selector = _selector; @@ -157,7 +173,7 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable _selecting = false; } } - + if (selector != null) { if (LOG.isDebugEnabled()) @@ -212,7 +228,7 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable if (connect.timeout.cancel()) { key.interestOps(0); - execute(new CreateEndPoint(connect,key)); + execute(new CreateEndPoint(connect, key)); } else { @@ -267,12 +283,38 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable private int getActionSize() { - synchronized(ManagedSelector.this) + synchronized (ManagedSelector.this) { return _updates.size(); } } + static int safeReadyOps(SelectionKey selectionKey) + { + try + { + return selectionKey.readyOps(); + } + catch (Throwable x) + { + LOG.ignore(x); + return -1; + } + } + + static int safeInterestOps(SelectionKey selectionKey) + { + try + { + return selectionKey.interestOps(); + } + catch (Throwable x) + { + LOG.ignore(x); + return -1; + } + } + @Override public void dump(Appendable out, String indent) throws IOException { @@ -283,7 +325,7 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable { DumpKeys dump = new DumpKeys(); String updatesAt = DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(ZonedDateTime.now()); - synchronized(ManagedSelector.this) + synchronized (ManagedSelector.this) { updates = new ArrayList<>(_updates); _updates.addFirst(dump); @@ -294,14 +336,16 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable selector.wakeup(); keys = dump.get(5, TimeUnit.SECONDS); String keysAt = DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(ZonedDateTime.now()); - if (keys==null) + if (keys == null) keys = Collections.singletonList("No dump keys retrieved"); - dumpBeans(out, indent, Arrays.asList(new DumpableCollection("updates @ "+updatesAt, updates), - new DumpableCollection("keys @ "+keysAt, keys))); + + dumpObjects(out, indent, + new DumpableCollection("updates @ " + updatesAt, updates), + new DumpableCollection("keys @ " + keysAt, keys)); } else { - dumpBeans(out, indent); + dumpObjects(out, indent); } } @@ -310,11 +354,11 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable { Selector selector = _selector; return String.format("%s id=%s keys=%d selected=%d updates=%d", - super.toString(), - _id, - selector != null && selector.isOpen() ? selector.keys().size() : -1, - selector != null && selector.isOpen() ? selector.selectedKeys().size() : -1, - getActionSize()); + super.toString(), + _id, + selector != null && selector.isOpen() ? selector.keys().size() : -1, + selector != null && selector.isOpen() ? selector.selectedKeys().size() : -1, + getActionSize()); } /** @@ -363,45 +407,45 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable private void processUpdates() { - synchronized(ManagedSelector.this) + synchronized (ManagedSelector.this) { Deque updates = _updates; _updates = _updateable; _updateable = updates; } - + if (LOG.isDebugEnabled()) - LOG.debug("updateable {}",_updateable.size()); - + LOG.debug("updateable {}", _updateable.size()); + for (SelectorUpdate update : _updateable) { - if (_selector==null) + if (_selector == null) break; try { if (LOG.isDebugEnabled()) - LOG.debug("update {}",update); + LOG.debug("update {}", update); update.update(_selector); } - catch(Throwable th) + catch (Throwable ex) { - LOG.warn(th); + LOG.warn(ex); } } _updateable.clear(); Selector selector; int updates; - synchronized(ManagedSelector.this) + synchronized (ManagedSelector.this) { updates = _updates.size(); - _selecting = updates==0; - selector = _selecting?null:_selector; + _selecting = updates == 0; + selector = _selecting ? null : _selector; } if (LOG.isDebugEnabled()) - LOG.debug("updates {}",updates); - + LOG.debug("updates {}", updates); + if (selector != null) { if (LOG.isDebugEnabled()) @@ -428,13 +472,14 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable if (Thread.interrupted() && !isRunning()) throw new ClosedSelectorException(); - selected = selector.selectNow(); + if (FORCE_SELECT_NOW) + selected = selector.selectNow(); } if (LOG.isDebugEnabled()) LOG.debug("Selector {} woken up from select, {}/{}/{} selected", selector, selected, selector.selectedKeys().size(), selector.keys().size()); int updates; - synchronized(ManagedSelector.this) + synchronized (ManagedSelector.this) { // finished selecting _selecting = false; @@ -451,12 +496,15 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable } catch (Throwable x) { - closeNoExceptions(_selector); _selector = null; if (isRunning()) LOG.warn(x); else + { + LOG.warn(x.toString()); LOG.debug(x); + } + closeNoExceptions(_selector); } return false; } @@ -470,7 +518,7 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable { Object attachment = key.attachment(); if (LOG.isDebugEnabled()) - LOG.debug("selected {} {} {} ",key.readyOps(),key,attachment); + LOG.debug("selected {} {} {} ", safeReadyOps(key), key, attachment); try { if (attachment instanceof Selectable) @@ -486,7 +534,7 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable } else { - throw new IllegalStateException("key=" + key + ", att=" + attachment + ", iOps=" + key.interestOps() + ", rOps=" + key.readyOps()); + throw new IllegalStateException("key=" + key + ", att=" + attachment + ", iOps=" + safeInterestOps(key) + ", rOps=" + safeReadyOps(key)); } } catch (CancelledKeyException x) @@ -534,13 +582,13 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable return String.format("%s@%x", getClass().getSimpleName(), hashCode()); } } - + /** * A selector update to be done when the selector has been woken. */ public interface SelectorUpdate { - public void update(Selector selector); + void update(Selector selector); } private class Start implements SelectorUpdate @@ -559,28 +607,18 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable { private CountDownLatch latch = new CountDownLatch(1); private List keys; - + @Override public void update(Selector selector) { - Set selector_keys = selector.keys(); - List list = new ArrayList<>(selector_keys.size()+1); - list.add(selector + " keys=" + selector_keys.size()); - for (SelectionKey key : selector_keys) + Set selectionKeys = selector.keys(); + List list = new ArrayList<>(selectionKeys.size()); + for (SelectionKey key : selectionKeys) { - if (key==null) - continue; - try - { - list.add(String.format("SelectionKey@%x{i=%d}->%s", key.hashCode(), key.interestOps(), key.attachment())); - } - catch (Throwable x) - { - list.add(String.format("SelectionKey@%x[%s]->%s", key.hashCode(), x, key.attachment())); - } + if (key != null) + list.add(String.format("SelectionKey@%x{i=%d}->%s", key.hashCode(), safeInterestOps(key), key.attachment())); } keys = list; - latch.countDown(); } @@ -613,10 +651,10 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable { try { - if (_key==null) + if (_key == null) { _key = _channel.register(selector, SelectionKey.OP_ACCEPT, this); - } + } if (LOG.isDebugEnabled()) LOG.debug("{} acceptor={}", this, _key); @@ -635,10 +673,10 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable SelectableChannel channel = null; try { - while(true) + while (true) { channel = _selectorManager.doAccept(server); - if (channel==null) + if (channel == null) break; _selectorManager.accepted(channel); } @@ -648,7 +686,7 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable closeNoExceptions(channel); LOG.warn("Accept failed for channel " + channel, x); } - + return null; } @@ -662,7 +700,7 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable { SelectionKey key = _key; _key = null; - if (key!=null && key.isValid()) + if (key != null && key.isValid()) key.cancel(); } } @@ -698,7 +736,7 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable catch (Throwable x) { closeNoExceptions(channel); - _selectorManager.onAcceptFailed(channel,x); + _selectorManager.onAcceptFailed(channel, x); LOG.debug(x); } } @@ -723,11 +761,10 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable closeNoExceptions(channel); LOG.warn(String.valueOf(failure)); LOG.debug(failure); - _selectorManager.onAcceptFailed(channel,failure); + _selectorManager.onAcceptFailed(channel, failure); } } - class Connect implements SelectorUpdate, Runnable { private final AtomicBoolean failed = new AtomicBoolean(); @@ -754,7 +791,7 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable failed(x); } } - + @Override public void run() { @@ -775,11 +812,11 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable ManagedSelector.this._selectorManager.connectionFailed(channel, failure, attachment); } } - + @Override public String toString() { - return String.format("Connect@%x{%s,%s}",hashCode(),channel,attachment); + return String.format("Connect@%x{%s,%s}", hashCode(), channel, attachment); } } @@ -793,7 +830,7 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable { this(null); } - + public CloseConnections(Set closed) { _closed = closed; @@ -801,13 +838,13 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable @Override public void update(Selector selector) - { + { if (LOG.isDebugEnabled()) LOG.debug("Closing {} connections on {}", selector.keys().size(), ManagedSelector.this); boolean zero = true; for (SelectionKey key : selector.keys()) { - if (key!=null && key.isValid()) + if (key != null && key.isValid()) { Closeable closeable = null; Object attachment = key.attachment(); @@ -822,45 +859,45 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable else closeable = endp; } - - if (closeable!=null) + + if (closeable != null) { - if (_closed==null) + if (_closed == null) { closeNoExceptions(closeable); } else if (!_closed.contains(closeable)) - { + { _closed.add(closeable); closeNoExceptions(closeable); } } } } - + if (zero) _noEndPoints.countDown(); _complete.countDown(); } } - + private class StopSelector implements SelectorUpdate { CountDownLatch _stopped = new CountDownLatch(1); - + @Override public void update(Selector selector) { for (SelectionKey key : selector.keys()) { - if (key!=null && key.isValid()) + if (key != null && key.isValid()) { Object attachment = key.attachment(); if (attachment instanceof EndPoint) closeNoExceptions((EndPoint)attachment); } } - + _selector = null; closeNoExceptions(selector); _stopped.countDown(); @@ -883,9 +920,9 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable { try { - createEndPoint(_connect.channel,_key); + createEndPoint(_connect.channel, _key); } - catch(Throwable failure) + catch (Throwable failure) { closeNoExceptions(_connect.channel); LOG.warn(String.valueOf(failure)); @@ -893,14 +930,14 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable _connect.failed(failure); } } - + @Override public String toString() { - return String.format("CreateEndPoint@%x{%s,%s}",hashCode(),_connect,_key); + return String.format("CreateEndPoint@%x{%s,%s}", hashCode(), _connect, _key); } } - + private class DestroyEndPoint implements Runnable, Closeable { private final EndPoint endPoint; diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/MappedByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/MappedByteBufferPool.java index 485f0a9701d..c2a4087be66 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/MappedByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/MappedByteBufferPool.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,51 +19,104 @@ package org.eclipse.jetty.io; import java.nio.ByteBuffer; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.annotation.ManagedAttribute; +import org.eclipse.jetty.util.annotation.ManagedObject; -public class MappedByteBufferPool implements ByteBufferPool +/** + *

        A ByteBuffer pool where ByteBuffers are held in queues that are held in a Map.

        + *

        Given a capacity {@code factor} of 1024, the Map entry with key {@code 1} holds a + * queue of ByteBuffers each of capacity 1024, the Map entry with key {@code 2} holds a + * queue of ByteBuffers each of capacity 2048, and so on.

        + */ +@ManagedObject +public class MappedByteBufferPool extends AbstractByteBufferPool { - private final ConcurrentMap directBuffers = new ConcurrentHashMap<>(); - private final ConcurrentMap heapBuffers = new ConcurrentHashMap<>(); - private final int _factor; + private final ConcurrentMap _directBuffers = new ConcurrentHashMap<>(); + private final ConcurrentMap _heapBuffers = new ConcurrentHashMap<>(); private final Function _newBucket; + /** + * Creates a new MappedByteBufferPool with a default configuration. + */ public MappedByteBufferPool() { this(-1); } + /** + * Creates a new MappedByteBufferPool with the given capacity factor. + * + * @param factor the capacity factor + */ public MappedByteBufferPool(int factor) { - this(factor,-1,null); + this(factor, -1); } - - public MappedByteBufferPool(int factor,int maxQueue) + + /** + * Creates a new MappedByteBufferPool with the given configuration. + * + * @param factor the capacity factor + * @param maxQueueLength the maximum ByteBuffer queue length + */ + public MappedByteBufferPool(int factor, int maxQueueLength) { - this(factor,maxQueue,null); + this(factor, maxQueueLength, null); } - - public MappedByteBufferPool(int factor,int maxQueue,Function newBucket) + + /** + * Creates a new MappedByteBufferPool with the given configuration. + * + * @param factor the capacity factor + * @param maxQueueLength the maximum ByteBuffer queue length + * @param newBucket the function that creates a Bucket + */ + public MappedByteBufferPool(int factor, int maxQueueLength, Function newBucket) { - _factor = factor<=0?1024:factor; - _newBucket = newBucket!=null?newBucket:i->new Bucket(this,i*_factor,maxQueue); + this(factor, maxQueueLength, newBucket, -1, -1); + } + + /** + * Creates a new MappedByteBufferPool with the given configuration. + * + * @param factor the capacity factor + * @param maxQueueLength the maximum ByteBuffer queue length + * @param newBucket the function that creates a Bucket + * @param maxHeapMemory the max heap memory in bytes + * @param maxDirectMemory the max direct memory in bytes + */ + public MappedByteBufferPool(int factor, int maxQueueLength, Function newBucket, long maxHeapMemory, long maxDirectMemory) + { + super(factor, maxQueueLength, maxHeapMemory, maxDirectMemory); + _newBucket = newBucket != null ? newBucket : this::newBucket; + } + + private Bucket newBucket(int key) + { + return new Bucket(this, key * getCapacityFactor(), getMaxQueueLength()); } @Override public ByteBuffer acquire(int size, boolean direct) { int b = bucketFor(size); + int capacity = b * getCapacityFactor(); ConcurrentMap buffers = bucketsFor(direct); - Bucket bucket = buffers.get(b); - if (bucket==null) - return newByteBuffer(b*_factor, direct); - return bucket.acquire(direct); + if (bucket == null) + return newByteBuffer(capacity, direct); + ByteBuffer buffer = bucket.acquire(); + if (buffer == null) + return newByteBuffer(capacity, direct); + decrementMemory(buffer); + return buffer; } @Override @@ -71,37 +124,87 @@ public class MappedByteBufferPool implements ByteBufferPool { if (buffer == null) return; // nothing to do - - // validate that this buffer is from this pool - assert((buffer.capacity() % _factor) == 0); - - int b = bucketFor(buffer.capacity()); - ConcurrentMap buckets = bucketsFor(buffer.isDirect()); - Bucket bucket = buckets.computeIfAbsent(b,_newBucket); + int capacity = buffer.capacity(); + // Validate that this buffer is from this pool. + assert ((capacity % getCapacityFactor()) == 0); + + int b = bucketFor(capacity); + boolean direct = buffer.isDirect(); + ConcurrentMap buckets = bucketsFor(direct); + Bucket bucket = buckets.computeIfAbsent(b, _newBucket); bucket.release(buffer); + incrementMemory(buffer); + releaseExcessMemory(direct, this::clearOldestBucket); } + @Override public void clear() { - directBuffers.values().forEach(Bucket::clear); - directBuffers.clear(); - heapBuffers.values().forEach(Bucket::clear); - heapBuffers.clear(); + super.clear(); + _directBuffers.values().forEach(Bucket::clear); + _directBuffers.clear(); + _heapBuffers.values().forEach(Bucket::clear); + _heapBuffers.clear(); + } + + private void clearOldestBucket(boolean direct) + { + long oldest = Long.MAX_VALUE; + int index = -1; + ConcurrentMap buckets = bucketsFor(direct); + for (Map.Entry entry : buckets.entrySet()) + { + Bucket bucket = entry.getValue(); + long lastUpdate = bucket.getLastUpdate(); + if (lastUpdate < oldest) + { + oldest = lastUpdate; + index = entry.getKey(); + } + } + if (index >= 0) + { + Bucket bucket = buckets.remove(index); + // The same bucket may be concurrently + // removed, so we need this null guard. + if (bucket != null) + bucket.clear(this::decrementMemory); + } } private int bucketFor(int size) { - int bucket = size / _factor; - if (size % _factor > 0) + int factor = getCapacityFactor(); + int bucket = size / factor; + if (bucket * factor != size) ++bucket; return bucket; } + @ManagedAttribute("The number of pooled direct ByteBuffers") + public long getDirectByteBufferCount() + { + return getByteBufferCount(true); + } + + @ManagedAttribute("The number of pooled heap ByteBuffers") + public long getHeapByteBufferCount() + { + return getByteBufferCount(false); + } + + private long getByteBufferCount(boolean direct) + { + return bucketsFor(direct).values().stream() + .mapToLong(Bucket::size) + .sum(); + } + // Package local for testing ConcurrentMap bucketsFor(boolean direct) { - return direct ? directBuffers : heapBuffers; + return direct ? _directBuffers : _heapBuffers; } public static class Tagged extends MappedByteBufferPool diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/NegotiatingClientConnection.java b/jetty-io/src/main/java/org/eclipse/jetty/io/NegotiatingClientConnection.java index 74092300669..da6014d4af0 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/NegotiatingClientConnection.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/NegotiatingClientConnection.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -21,7 +21,6 @@ package org.eclipse.jetty.io; import java.io.IOException; import java.util.Map; import java.util.concurrent.Executor; - import javax.net.ssl.SSLEngine; import org.eclipse.jetty.util.BufferUtil; diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/NegotiatingClientConnectionFactory.java b/jetty-io/src/main/java/org/eclipse/jetty/io/NegotiatingClientConnectionFactory.java index 9b4aa4b5f86..54b66f791a7 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/NegotiatingClientConnectionFactory.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/NegotiatingClientConnectionFactory.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,7 +18,6 @@ package org.eclipse.jetty.io; - public abstract class NegotiatingClientConnectionFactory implements ClientConnectionFactory { private final ClientConnectionFactory connectionFactory; diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/NetworkTrafficListener.java b/jetty-io/src/main/java/org/eclipse/jetty/io/NetworkTrafficListener.java index be902761551..9728b49a458 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/NetworkTrafficListener.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/NetworkTrafficListener.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -45,24 +45,24 @@ public interface NetworkTrafficListener * * @param socket the socket associated with the remote client */ - public void opened(Socket socket); + void opened(Socket socket); /** *

        Callback method invoked when bytes sent by a remote client arrived on the server.

        * * @param socket the socket associated with the remote client - * @param bytes the read-only buffer containing the incoming bytes + * @param bytes the read-only buffer containing the incoming bytes */ - public void incoming(Socket socket, ByteBuffer bytes); + void incoming(Socket socket, ByteBuffer bytes); /** *

        Callback method invoked when bytes are sent to a remote client from the server.

        *

        This method is invoked after the bytes have been actually written to the remote client.

        * * @param socket the socket associated with the remote client - * @param bytes the read-only buffer containing the outgoing bytes + * @param bytes the read-only buffer containing the outgoing bytes */ - public void outgoing(Socket socket, ByteBuffer bytes); + void outgoing(Socket socket, ByteBuffer bytes); /** *

        Callback method invoked when a connection to a remote client has been closed.

        @@ -74,12 +74,12 @@ public interface NetworkTrafficListener * * @param socket the (closed) socket associated with the remote client */ - public void closed(Socket socket); + void closed(Socket socket); /** *

        A commodity class that implements {@link NetworkTrafficListener} with empty methods.

        */ - public static class Adapter implements NetworkTrafficListener + class Adapter implements NetworkTrafficListener { @Override public void opened(Socket socket) diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/NetworkTrafficSelectChannelEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/NetworkTrafficSelectChannelEndPoint.java index f8831bca8e7..c879f36fa2d 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/NetworkTrafficSelectChannelEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/NetworkTrafficSelectChannelEndPoint.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -52,16 +52,16 @@ public class NetworkTrafficSelectChannelEndPoint extends SelectChannelEndPoint @Override public boolean flush(ByteBuffer... buffers) throws IOException { - boolean flushed=true; + boolean flushed = true; for (ByteBuffer b : buffers) { if (b.hasRemaining()) { int position = b.position(); - ByteBuffer view=b.slice(); - flushed&=super.flush(b); - int l=b.position()-position; - view.limit(view.position()+l); + ByteBuffer view = b.slice(); + flushed &= super.flush(b); + int l = b.position() - position; + view.limit(view.position() + l); notifyOutgoing(view); if (!flushed) break; @@ -70,8 +70,6 @@ public class NetworkTrafficSelectChannelEndPoint extends SelectChannelEndPoint return flushed; } - - @Override public void onOpen() { @@ -112,7 +110,6 @@ public class NetworkTrafficSelectChannelEndPoint extends SelectChannelEndPoint } } - public void notifyIncoming(ByteBuffer buffer, int read) { if (listeners != null && !listeners.isEmpty() && read > 0) @@ -136,12 +133,12 @@ public class NetworkTrafficSelectChannelEndPoint extends SelectChannelEndPoint { if (listeners != null && !listeners.isEmpty() && view.hasRemaining()) { - Socket socket=getSocket(); + Socket socket = getSocket(); for (NetworkTrafficListener listener : listeners) { try { - listener.outgoing(socket, view); + listener.outgoing(socket, view); } catch (Exception x) { @@ -150,5 +147,4 @@ public class NetworkTrafficSelectChannelEndPoint extends SelectChannelEndPoint } } } - } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/QuietException.java b/jetty-io/src/main/java/org/eclipse/jetty/io/QuietException.java index 9723b6bf40a..4e913d8cfb5 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/QuietException.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/QuietException.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,9 +18,8 @@ package org.eclipse.jetty.io; - -/* ------------------------------------------------------------ */ -/** A Quiet Exception. +/** + * A Quiet Exception. *

        Exception classes that extend this interface will be logged * less verbosely. */ diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/RetainableByteBuffer.java b/jetty-io/src/main/java/org/eclipse/jetty/io/RetainableByteBuffer.java new file mode 100644 index 00000000000..c605aee6d75 --- /dev/null +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/RetainableByteBuffer.java @@ -0,0 +1,99 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.io; + +import java.nio.ByteBuffer; +import java.util.concurrent.atomic.AtomicInteger; + +import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.Retainable; + +/** + * A Retainable ByteBuffer. + *

        Acquires a ByteBuffer from a {@link ByteBufferPool} and maintains a reference count that is + * initially 1, incremented with {@link #retain()} and decremented with {@link #release()}. The buffer + * is released to the pool when the reference count is decremented to 0.

        + */ +public class RetainableByteBuffer implements Retainable +{ + private final ByteBufferPool pool; + private final ByteBuffer buffer; + private final AtomicInteger references; + + public RetainableByteBuffer(ByteBufferPool pool, int size) + { + this(pool, size, false); + } + + public RetainableByteBuffer(ByteBufferPool pool, int size, boolean direct) + { + this.pool = pool; + this.buffer = pool.acquire(size, direct); + this.references = new AtomicInteger(1); + } + + public ByteBuffer getBuffer() + { + return buffer; + } + + public int getReferences() + { + return references.get(); + } + + @Override + public void retain() + { + while (true) + { + int r = references.get(); + if (r == 0) + throw new IllegalStateException("released " + this); + if (references.compareAndSet(r, r + 1)) + break; + } + } + + public int release() + { + int ref = references.decrementAndGet(); + if (ref == 0) + pool.release(buffer); + else if (ref < 0) + throw new IllegalStateException("already released " + this); + return ref; + } + + public boolean hasRemaining() + { + return buffer.hasRemaining(); + } + + public boolean isEmpty() + { + return !buffer.hasRemaining(); + } + + @Override + public String toString() + { + return String.format("%s@%x{%s,r=%d}", getClass().getSimpleName(), hashCode(), BufferUtil.toDetailString(buffer), getReferences()); + } +} diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/RuntimeIOException.java b/jetty-io/src/main/java/org/eclipse/jetty/io/RuntimeIOException.java index 894017f5a15..a552ec8c7ec 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/RuntimeIOException.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/RuntimeIOException.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,10 +16,8 @@ // ======================================================================== // - package org.eclipse.jetty.io; -/* ------------------------------------------------------------ */ /** * Subclass of {@link java.lang.RuntimeException} used to signal that there * was an {@link java.io.IOException} thrown by underlying {@link java.io.Writer} @@ -43,6 +41,6 @@ public class RuntimeIOException extends RuntimeException public RuntimeIOException(String message, Throwable cause) { - super(message,cause); + super(message, cause); } } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/SelectChannelEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/SelectChannelEndPoint.java index d18fc3ec2e3..17dc19d897a 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/SelectChannelEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/SelectChannelEndPoint.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -21,8 +21,6 @@ package org.eclipse.jetty.io; import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.thread.Scheduler; /** @@ -33,7 +31,7 @@ public class SelectChannelEndPoint extends SocketChannelEndPoint { public SelectChannelEndPoint(SelectableChannel channel, ManagedSelector selector, SelectionKey key, Scheduler scheduler, long idleTimeout) { - super(channel,selector,key,scheduler); + super(channel, selector, key, scheduler); setIdleTimeout(idleTimeout); } } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java b/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java index 33a830e8450..054bd694c77 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -74,11 +74,11 @@ public abstract class SelectorManager extends ContainerLifeCycle implements Dump { int threads = ((ThreadPool.SizedThreadPool)executor).getMaxThreads(); int cpus = ProcessorUtils.availableProcessors(); - return Math.max(1,Math.min(cpus/2,threads/16)); + return Math.max(1, Math.min(cpus / 2, threads / 16)); } - return Math.max(1,ProcessorUtils.availableProcessors()/2); + return Math.max(1, ProcessorUtils.availableProcessors() / 2); } - + protected SelectorManager(Executor executor, Scheduler scheduler) { this(executor, scheduler, -1); @@ -88,7 +88,7 @@ public abstract class SelectorManager extends ContainerLifeCycle implements Dump * @param executor The executor to use for handling selected {@link EndPoint}s * @param scheduler The scheduler to use for timing events * @param selectors The number of selectors to use, or -1 for a default derived - * from a heuristic over available CPUs and thread pool size. + * from a heuristic over available CPUs and thread pool size. */ protected SelectorManager(Executor executor, Scheduler scheduler, int selectors) { @@ -97,7 +97,7 @@ public abstract class SelectorManager extends ContainerLifeCycle implements Dump this.executor = executor; this.scheduler = scheduler; _selectors = new ManagedSelector[selectors]; - _selectorIndexUpdate = index -> (index+1)%_selectors.length; + _selectorIndexUpdate = index -> (index + 1) % _selectors.length; } @ManagedAttribute("The Executor") @@ -152,7 +152,7 @@ public abstract class SelectorManager extends ContainerLifeCycle implements Dump { throw new UnsupportedOperationException(); } - + /** * Executes the given task in a different thread. * @@ -183,7 +183,7 @@ public abstract class SelectorManager extends ContainerLifeCycle implements Dump * must be called prior to calling this method, and the connect operation must not be completed * (the return value of {@link SocketChannel#connect(SocketAddress)} must be false).

        * - * @param channel the channel to register + * @param channel the channel to register * @param attachment the attachment object * @see #accept(SelectableChannel, Object) */ @@ -209,7 +209,7 @@ public abstract class SelectorManager extends ContainerLifeCycle implements Dump * just after a non-blocking connect via {@link SocketChannel#connect(SocketAddress)} that completed * successfully.

        * - * @param channel the channel to register + * @param channel the channel to register * @param attachment the attachment object */ public void accept(SelectableChannel channel, Object attachment) @@ -285,10 +285,10 @@ public abstract class SelectorManager extends ContainerLifeCycle implements Dump // Cleanup for (ManagedSelector selector : _selectors) { - if (selector!=null) + if (selector != null) removeBean(selector); } - Arrays.fill(_selectors,null); + Arrays.fill(_selectors, null); if (_lease != null) _lease.close(); } @@ -365,13 +365,12 @@ public abstract class SelectorManager extends ContainerLifeCycle implements Dump return ((ServerSocketChannel)server).accept(); } - /** *

        Callback method invoked when a non-blocking connect cannot be completed.

        *

        By default it just logs with level warning.

        * - * @param channel the channel that attempted the connect - * @param ex the exception that caused the connect to fail + * @param channel the channel that attempted the connect + * @param ex the exception that caused the connect to fail * @param attachment the attachment object associated at registration */ protected void connectionFailed(SelectableChannel channel, Throwable ex, Object attachment) @@ -389,8 +388,8 @@ public abstract class SelectorManager extends ContainerLifeCycle implements Dump *

        This method is invoked as a result of the registration of a channel via {@link #connect(SelectableChannel, Object)} * or {@link #accept(SelectableChannel)}.

        * - * @param channel the channel associated to the endpoint - * @param selector the selector the channel is registered to + * @param channel the channel associated to the endpoint + * @param selector the selector the channel is registered to * @param selectionKey the selection key * @return a new endpoint * @throws IOException if the endPoint cannot be created @@ -401,8 +400,8 @@ public abstract class SelectorManager extends ContainerLifeCycle implements Dump /** *

        Factory method to create {@link Connection}.

        * - * @param channel the channel associated to the connection - * @param endpoint the endpoint + * @param channel the channel associated to the connection + * @param endpoint the endpoint * @param attachment the attachment * @return a new connection * @throws IOException if unable to create new connection @@ -414,15 +413,15 @@ public abstract class SelectorManager extends ContainerLifeCycle implements Dump if (isRunning()) throw new IllegalStateException(this.toString()); if (listener instanceof AcceptListener) - addAcceptListener(AcceptListener.class.cast(listener)); - } - + addAcceptListener((AcceptListener)listener); + } + public void removeEventListener(EventListener listener) { if (isRunning()) throw new IllegalStateException(this.toString()); if (listener instanceof AcceptListener) - removeAcceptListener(AcceptListener.class.cast(listener)); + removeAcceptListener((AcceptListener)listener); } public void addAcceptListener(AcceptListener listener) @@ -433,9 +432,9 @@ public abstract class SelectorManager extends ContainerLifeCycle implements Dump public void removeAcceptListener(AcceptListener listener) { - _acceptListeners.remove(listener); + _acceptListeners.remove(listener); } - + protected void onAccepting(SelectableChannel channel) { for (AcceptListener l : _acceptListeners) @@ -450,14 +449,14 @@ public abstract class SelectorManager extends ContainerLifeCycle implements Dump } } } - + protected void onAcceptFailed(SelectableChannel channel, Throwable cause) { for (AcceptListener l : _acceptListeners) { try { - l.onAcceptFailed(channel,cause); + l.onAcceptFailed(channel, cause); } catch (Throwable x) { @@ -465,7 +464,7 @@ public abstract class SelectorManager extends ContainerLifeCycle implements Dump } } } - + protected void onAccepted(SelectableChannel channel) { for (AcceptListener l : _acceptListeners) @@ -491,24 +490,33 @@ public abstract class SelectorManager extends ContainerLifeCycle implements Dump /** * Called immediately after a new SelectableChannel is accepted, but * before it has been submitted to the {@link SelectorManager}. + * * @param channel the accepted channel */ - default void onAccepting(SelectableChannel channel) {} - + default void onAccepting(SelectableChannel channel) + { + } + /** * Called if the processing of the accepted channel fails prior to calling * {@link #onAccepted(SelectableChannel)}. + * * @param channel the accepted channel * @param cause the cause of the failure */ - default void onAcceptFailed(SelectableChannel channel, Throwable cause) {} - + default void onAcceptFailed(SelectableChannel channel, Throwable cause) + { + } + /** - * Called after the accepted channel has been allocated an {@link EndPoint} + * Called after the accepted channel has been allocated an {@link EndPoint} * and associated {@link Connection}, and after the onOpen notifications have * been called on both endPoint and connection. + * * @param channel the accepted channel */ - default void onAccepted(SelectableChannel channel) {} + default void onAccepted(SelectableChannel channel) + { + } } } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/SocketChannelEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/SocketChannelEndPoint.java index cc8d9fa7351..249e8419d47 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/SocketChannelEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/SocketChannelEndPoint.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -38,16 +38,16 @@ public class SocketChannelEndPoint extends ChannelEndPoint public SocketChannelEndPoint(SelectableChannel channel, ManagedSelector selector, SelectionKey key, Scheduler scheduler) { - this((SocketChannel)channel,selector,key,scheduler); + this((SocketChannel)channel, selector, key, scheduler); } - + public SocketChannelEndPoint(SocketChannel channel, ManagedSelector selector, SelectionKey key, Scheduler scheduler) { - super(channel,selector,key,scheduler); - - _socket=channel.socket(); - _local=(InetSocketAddress)_socket.getLocalSocketAddress(); - _remote=(InetSocketAddress)_socket.getRemoteSocketAddress(); + super(channel, selector, key, scheduler); + + _socket = channel.socket(); + _local = (InetSocketAddress)_socket.getLocalSocketAddress(); + _remote = (InetSocketAddress)_socket.getRemoteSocketAddress(); } public Socket getSocket() @@ -66,7 +66,7 @@ public class SocketChannelEndPoint extends ChannelEndPoint { return _remote; } - + @Override protected void doShutdownOutput() { diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/WriteFlusher.java b/jetty-io/src/main/java/org/eclipse/jetty/io/WriteFlusher.java index a2d9c8fa008..743f0a1fcef 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/WriteFlusher.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/WriteFlusher.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -43,7 +43,7 @@ import org.eclipse.jetty.util.thread.Invocable.InvocationType; * flush and should organize for the {@link #completeWrite()} method to be called when a subsequent call to flush * should be able to make more progress. */ -abstract public class WriteFlusher +public abstract class WriteFlusher { private static final Logger LOG = Log.getLogger(WriteFlusher.class); private static final boolean DEBUG = LOG.isDebugEnabled(); // Easy for the compiler to remove the code if DEBUG==false @@ -98,7 +98,7 @@ abstract public class WriteFlusher * Tries to update the current state to the given new state. * * @param previous the expected current state - * @param next the desired new state + * @param next the desired new state * @return the previous state or null if the state transition failed * @throws WritePendingException if currentState is WRITING and new state is WRITING (api usage error) */ @@ -233,15 +233,15 @@ abstract public class WriteFlusher { State s = _state.get(); return (s instanceof PendingState) - ? ((PendingState)s).getCallbackInvocationType() - : Invocable.InvocationType.BLOCKING; + ? ((PendingState)s).getCallbackInvocationType() + : Invocable.InvocationType.BLOCKING; } /** * Abstract call to be implemented by specific WriteFlushers. It should schedule a call to {@link #completeWrite()} * or {@link #onFail(Throwable)} when appropriate. */ - abstract protected void onIncompleteFlush(); + protected abstract void onIncompleteFlush(); /** * Tries to switch state to WRITING. If successful it writes the given buffers to the EndPoint. If state transition @@ -253,14 +253,14 @@ abstract public class WriteFlusher * If all buffers have been written it calls callback.complete(). * * @param callback the callback to call on either failed or complete - * @param buffers the buffers to flush to the endpoint + * @param buffers the buffers to flush to the endpoint * @throws WritePendingException if unable to write due to prior pending write */ public void write(Callback callback, ByteBuffer... buffers) throws WritePendingException { - callback = Objects.requireNonNull(callback); + Objects.requireNonNull(callback); - if(isFailed()) + if (isFailed()) { fail(callback); return; @@ -294,7 +294,7 @@ abstract public class WriteFlusher else fail(callback); } - catch (IOException e) + catch (Throwable e) { if (DEBUG) LOG.debug("write exception", e); @@ -307,9 +307,38 @@ abstract public class WriteFlusher private void fail(Callback callback, Throwable... suppressed) { - FailedState failed = (FailedState)_state.get(); + Throwable cause; + loop: + while (true) + { + State state = _state.get(); + + switch (state.getType()) + { + case FAILED: + { + FailedState failed = (FailedState)state; + cause = failed.getCause(); + break loop; + } + + case IDLE: + for (Throwable t : suppressed) + { + LOG.warn(t); + } + return; + + default: + Throwable t = new IllegalStateException(); + if (!_state.compareAndSet(state, new FailedState(t))) + continue; + + cause = t; + break loop; + } + } - Throwable cause = failed.getCause(); for (Throwable t : suppressed) { if (t != cause) @@ -366,7 +395,7 @@ abstract public class WriteFlusher else fail(callback); } - catch (IOException e) + catch (Throwable e) { if (DEBUG) LOG.debug("completeWrite exception", e); @@ -389,9 +418,9 @@ abstract public class WriteFlusher boolean progress = true; while (progress && buffers != null) { - long before = remaining(buffers); + long before = BufferUtil.remaining(buffers); boolean flushed = _endPoint.flush(buffers); - long after = remaining(buffers); + long after = BufferUtil.remaining(buffers); long written = before - after; if (LOG.isDebugEnabled()) @@ -441,16 +470,6 @@ abstract public class WriteFlusher return buffers == null ? EMPTY_BUFFERS : buffers; } - private long remaining(ByteBuffer[] buffers) - { - if (buffers == null) - return 0; - long result = 0; - for (ByteBuffer buffer : buffers) - result += buffer.remaining(); - return result; - } - /** * Notify the flusher of a failure * @@ -504,12 +523,22 @@ abstract public class WriteFlusher boolean isFailed() { - return _state.get().getType() == StateType.FAILED; + return isState(StateType.FAILED); } boolean isIdle() { - return _state.get().getType() == StateType.IDLE; + return isState(StateType.IDLE); + } + + public boolean isPending() + { + return isState(StateType.PENDING); + } + + private boolean isState(StateType type) + { + return _state.get().getType() == type; } public String toStateString() diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/WriterOutputStream.java b/jetty-io/src/main/java/org/eclipse/jetty/io/WriterOutputStream.java index 659123aeb3c..126448c1cfc 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/WriterOutputStream.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/WriterOutputStream.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -23,78 +23,69 @@ import java.io.OutputStream; import java.io.Writer; import java.nio.charset.Charset; - -/* ------------------------------------------------------------ */ -/** Wrap a Writer as an OutputStream. +/** + * Wrap a Writer as an OutputStream. * When all you have is a Writer and only an OutputStream will do. * Try not to use this as it indicates that your design is a dogs * breakfast (JSP made me write it). - * */ public class WriterOutputStream extends OutputStream { protected final Writer _writer; protected final Charset _encoding; - private final byte[] _buf=new byte[1]; - - /* ------------------------------------------------------------ */ + private final byte[] _buf = new byte[1]; + public WriterOutputStream(Writer writer, String encoding) { - _writer=writer; - _encoding=encoding==null?null:Charset.forName(encoding); - } - - /* ------------------------------------------------------------ */ - public WriterOutputStream(Writer writer) - { - _writer=writer; - _encoding=null; + _writer = writer; + _encoding = encoding == null ? null : Charset.forName(encoding); + } + + public WriterOutputStream(Writer writer) + { + _writer = writer; + _encoding = null; } - /* ------------------------------------------------------------ */ @Override public void close() throws IOException { _writer.close(); } - - /* ------------------------------------------------------------ */ + @Override public void flush() throws IOException { _writer.flush(); } - - /* ------------------------------------------------------------ */ + @Override - public void write(byte[] b) + public void write(byte[] b) throws IOException { - if (_encoding==null) + if (_encoding == null) _writer.write(new String(b)); else - _writer.write(new String(b,_encoding)); + _writer.write(new String(b, _encoding)); } - - /* ------------------------------------------------------------ */ + @Override public void write(byte[] b, int off, int len) throws IOException { - if (_encoding==null) - _writer.write(new String(b,off,len)); + if (_encoding == null) + _writer.write(new String(b, off, len)); else - _writer.write(new String(b,off,len,_encoding)); + _writer.write(new String(b, off, len, _encoding)); } - - /* ------------------------------------------------------------ */ + @Override public synchronized void write(int b) throws IOException { - _buf[0]=(byte)b; + _buf[0] = (byte)b; write(_buf); } } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/package-info.java b/jetty-io/src/main/java/org/eclipse/jetty/io/package-info.java index 2f30f7b1124..f32f774ab72 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/package-info.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/ALPNProcessor.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/ALPNProcessor.java index cbac606261d..5d5ad20bc05 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/ALPNProcessor.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/ALPNProcessor.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -29,7 +29,7 @@ public interface ALPNProcessor * * @throws RuntimeException if this processor is unavailable (e.g. missing dependencies or wrong JVM) */ - public default void init() + default void init() { } @@ -39,7 +39,7 @@ public interface ALPNProcessor * @param sslEngine the SSLEngine to check * @return true if the processor can be applied to the given SSLEngine */ - public default boolean appliesTo(SSLEngine sslEngine) + default boolean appliesTo(SSLEngine sslEngine) { return false; } @@ -51,21 +51,21 @@ public interface ALPNProcessor * @param connection the Connection to configure * @throws RuntimeException if this processor cannot be configured */ - public default void configure(SSLEngine sslEngine, Connection connection) + default void configure(SSLEngine sslEngine, Connection connection) { } /** * Server-side interface used by ServiceLoader. */ - public interface Server extends ALPNProcessor + interface Server extends ALPNProcessor { } /** * Client-side interface used by ServiceLoader. */ - public interface Client extends ALPNProcessor + interface Client extends ALPNProcessor { } } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslClientConnectionFactory.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslClientConnectionFactory.java index 5ef729c15c8..9feb0e07140 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslClientConnectionFactory.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslClientConnectionFactory.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -22,8 +22,10 @@ import java.io.IOException; import java.util.Map; import java.util.Objects; import java.util.concurrent.Executor; - +import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLPeerUnverifiedException; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.ClientConnectionFactory; @@ -100,6 +102,7 @@ public class SslClientConnectionFactory implements ClientConnectionFactory EndPoint appEndPoint = sslConnection.getDecryptedEndPoint(); appEndPoint.setConnection(connectionFactory.newConnection(appEndPoint, context)); + sslConnection.addHandshakeListener(new HTTPSHandshakeListener(context)); customize(sslConnection, context); return sslConnection; @@ -124,4 +127,37 @@ public class SslClientConnectionFactory implements ClientConnectionFactory } return ClientConnectionFactory.super.customize(connection, context); } + + private class HTTPSHandshakeListener implements SslHandshakeListener + { + private final Map context; + + private HTTPSHandshakeListener(Map context) + { + this.context = context; + } + + @Override + public void handshakeSucceeded(Event event) throws SSLException + { + HostnameVerifier verifier = sslContextFactory.getHostnameVerifier(); + if (verifier != null) + { + String host = (String)context.get(SSL_PEER_HOST_CONTEXT_KEY); + try + { + if (!verifier.verify(host, event.getSSLEngine().getSession())) + throw new SSLPeerUnverifiedException("Host name verification failed for host: " + host); + } + catch (SSLException x) + { + throw x; + } + catch (Throwable x) + { + throw (SSLException)new SSLPeerUnverifiedException("Host name verification failed for host: " + host).initCause(x); + } + } + } + } } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java index 3b1d00c573b..c1b4398b6eb 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -25,7 +25,6 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicReference; - import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngineResult; import javax.net.ssl.SSLEngineResult.HandshakeStatus; @@ -41,6 +40,7 @@ import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.WriteFlusher; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.thread.Invocable; @@ -74,34 +74,33 @@ import org.eclipse.jetty.util.thread.Invocable; * MOST IMPORTANTLY, the encrypted callbacks from the active methods (#onFillable() and WriteFlusher#completeWrite()) do no filling or flushing * themselves. Instead they simple make the callbacks to the decrypted callbacks, so that the passive encrypted fill/flush will * be called again and make another best effort attempt to progress the connection. - * */ -public class SslConnection extends AbstractConnection +public class SslConnection extends AbstractConnection implements Connection.UpgradeTo { private static final Logger LOG = Log.getLogger(SslConnection.class); private static final String TLS_1_3 = "TLSv1.3"; - + private enum Handshake { INITIAL, SUCCEEDED, FAILED } - - private enum FillState + + private enum FillState { IDLE, // Not Filling any data INTERESTED, // We have a pending read interest WAIT_FOR_FLUSH // Waiting for a flush to happen } - - private enum FlushState - { + + private enum FlushState + { IDLE, // Not flushing any data WRITING, // We have a pending write of encrypted data WAIT_FOR_FILL // Waiting for a fill to happen } - + private final List handshakeListeners = new ArrayList<>(); private final ByteBufferPool _bufferPool; private final SSLEngine _sslEngine; @@ -119,20 +118,20 @@ public class SslConnection extends AbstractConnection private FillState _fillState = FillState.IDLE; private AtomicReference _handshake = new AtomicReference<>(Handshake.INITIAL); private boolean _underflown; - - private abstract class RunnableTask implements Runnable, Invocable + + private abstract class RunnableTask implements Runnable, Invocable { private final String _operation; protected RunnableTask(String op) { - _operation=op; + _operation = op; } @Override public String toString() { - return String.format("SSL:%s:%s:%s",SslConnection.this,_operation,getInvocationType()); + return String.format("SSL:%s:%s:%s", SslConnection.this, _operation, getInvocationType()); } } @@ -174,7 +173,7 @@ public class SslConnection extends AbstractConnection @Override public String toString() { - return String.format("SSLC.NBReadCB@%x{%s}", SslConnection.this.hashCode(),SslConnection.this); + return String.format("SSLC.NBReadCB@%x{%s}", SslConnection.this.hashCode(), SslConnection.this); } }; @@ -233,7 +232,7 @@ public class SslConnection extends AbstractConnection /** * @return The number of renegotions allowed for this connection. When the limit - * is 0 renegotiation will be denied. If the limit is less than 0 then no limit is applied. + * is 0 renegotiation will be denied. If the limit is less than 0 then no limit is applied. */ public int getRenegotiationLimit() { @@ -241,7 +240,7 @@ public class SslConnection extends AbstractConnection } /** - * @param renegotiationLimit The number of renegotions allowed for this connection. + * @param renegotiationLimit The number of renegotions allowed for this connection. * When the limit is 0 renegotiation will be denied. If the limit is less than 0 then no limit is applied. * Default -1. */ @@ -260,6 +259,22 @@ public class SslConnection extends AbstractConnection this._allowMissingCloseMessage = allowMissingCloseMessage; } + private void acquireEncryptedInput() + { + if (_encryptedInput == null) + _encryptedInput = _bufferPool.acquire(_sslEngine.getSession().getPacketBufferSize(), _encryptedDirectBuffers); + } + + @Override + public void onUpgradeTo(ByteBuffer buffer) + { + if (BufferUtil.hasContent(buffer)) + { + acquireEncryptedInput(); + BufferUtil.append(_encryptedInput, buffer); + } + } + @Override public void onOpen() { @@ -311,28 +326,28 @@ public class SslConnection extends AbstractConnection @Override public void onFillInterestedFailed(Throwable cause) { - _decryptedEndPoint.onFillableFail(cause==null?new IOException():cause); + _decryptedEndPoint.onFillableFail(cause == null ? new IOException() : cause); } @Override public String toConnectionString() { ByteBuffer b = _encryptedInput; - int ei=b==null?-1:b.remaining(); + int ei = b == null ? -1 : b.remaining(); b = _encryptedOutput; - int eo=b==null?-1:b.remaining(); + int eo = b == null ? -1 : b.remaining(); b = _decryptedInput; - int di=b==null?-1:b.remaining(); + int di = b == null ? -1 : b.remaining(); Connection connection = _decryptedEndPoint.getConnection(); return String.format("%s@%x{%s,eio=%d/%d,di=%d,fill=%s,flush=%s}~>%s=>%s", - getClass().getSimpleName(), - hashCode(), - _sslEngine.getHandshakeStatus(), - ei,eo,di, - _fillState,_flushState, - _decryptedEndPoint.toEndPointString(), - connection instanceof AbstractConnection ? ((AbstractConnection)connection).toConnectionString() : connection); + getClass().getSimpleName(), + hashCode(), + _sslEngine.getHandshakeStatus(), + ei, eo, di, + _fillState, _flushState, + _decryptedEndPoint.toEndPointString(), + connection instanceof AbstractConnection ? ((AbstractConnection)connection).toConnectionString() : connection); } private void releaseEncryptedOutputBuffer() @@ -349,7 +364,7 @@ public class SslConnection extends AbstractConnection public class DecryptedEndPoint extends AbstractEndPoint { private final Callback _incompleteWriteCallback = new IncompleteWriteCallback(); - + public DecryptedEndPoint() { // Disable idle timeout checking: no scheduler and -1 timeout for this instance. @@ -388,7 +403,7 @@ public class SslConnection extends AbstractConnection } @Override - protected WriteFlusher getWriteFlusher() + public WriteFlusher getWriteFlusher() { return super.getWriteFlusher(); } @@ -398,25 +413,25 @@ public class SslConnection extends AbstractConnection try { // If we are handshaking, then wake up any waiting write as well as it may have been blocked on the read - boolean waiting_for_fill; - synchronized(_decryptedEndPoint) + boolean waitingForFill; + synchronized (_decryptedEndPoint) { if (LOG.isDebugEnabled()) LOG.debug("onFillable {}", SslConnection.this); _fillState = FillState.IDLE; - waiting_for_fill = _flushState==FlushState.WAIT_FOR_FILL; + waitingForFill = _flushState == FlushState.WAIT_FOR_FILL; } - + getFillInterest().fillable(); - - if (waiting_for_fill) + + if (waitingForFill) { - synchronized(_decryptedEndPoint) + synchronized (_decryptedEndPoint) { - waiting_for_fill = _flushState==FlushState.WAIT_FOR_FILL; + waitingForFill = _flushState == FlushState.WAIT_FOR_FILL; } - if (waiting_for_fill) + if (waitingForFill) fill(BufferUtil.EMPTY_BUFFER); } } @@ -430,13 +445,13 @@ public class SslConnection extends AbstractConnection { // If we are handshaking, then wake up any waiting write as well as it may have been blocked on the read boolean fail = false; - synchronized(_decryptedEndPoint) + synchronized (_decryptedEndPoint) { if (LOG.isDebugEnabled()) LOG.debug("onFillableFail {}", SslConnection.this, failure); - + _fillState = FillState.IDLE; - switch(_flushState) + switch (_flushState) { case WAIT_FOR_FILL: _flushState = FlushState.IDLE; @@ -444,12 +459,12 @@ public class SslConnection extends AbstractConnection break; default: break; - } + } } // wake up whoever is doing the fill getFillInterest().onFail(failure); - + // Try to complete the write if (fail) { @@ -464,7 +479,7 @@ public class SslConnection extends AbstractConnection if (connection instanceof AbstractConnection) { AbstractConnection a = (AbstractConnection)connection; - if (a.getInputBufferSize()<_sslEngine.getSession().getApplicationBufferSize()) + if (a.getInputBufferSize() < _sslEngine.getSession().getApplicationBufferSize()) a.setInputBufferSize(_sslEngine.getSession().getApplicationBufferSize()); } super.setConnection(connection); @@ -480,7 +495,7 @@ public class SslConnection extends AbstractConnection { try { - synchronized(_decryptedEndPoint) + synchronized (_decryptedEndPoint) { if (LOG.isDebugEnabled()) LOG.debug(">fill {}", SslConnection.this); @@ -488,20 +503,20 @@ public class SslConnection extends AbstractConnection int filled = -2; try { - if (_fillState!=FillState.IDLE) + if (_fillState != FillState.IDLE) return filled = 0; - + // Do we already have some decrypted data? if (BufferUtil.hasContent(_decryptedInput)) - return filled = BufferUtil.append(buffer,_decryptedInput); - + return filled = BufferUtil.append(buffer, _decryptedInput); + // loop filling and unwrapping until we have something while (true) { HandshakeStatus status = _sslEngine.getHandshakeStatus(); if (LOG.isDebugEnabled()) LOG.debug("fill {}", status); - switch(status) + switch (status) { case NEED_UNWRAP: case NOT_HANDSHAKING: @@ -510,93 +525,97 @@ public class SslConnection extends AbstractConnection case NEED_TASK: _sslEngine.getDelegatedTask().run(); continue; - + case NEED_WRAP: - if (_flushState==FlushState.IDLE && flush(BufferUtil.EMPTY_BUFFER)) + if (_flushState == FlushState.IDLE && flush(BufferUtil.EMPTY_BUFFER)) + { + if (_sslEngine.isInboundDone()) + // TODO this is probably a JVM bug, work around it by -1 + return -1; continue; + } // handle in needsFillInterest return filled = 0; - + default: throw new IllegalStateException("Unexpected HandshakeStatus " + status); } - - if (_encryptedInput==null) - _encryptedInput = _bufferPool.acquire(_sslEngine.getSession().getPacketBufferSize(), _encryptedDirectBuffers); - + + acquireEncryptedInput(); + // can we use the passed buffer if it is big enough - ByteBuffer app_in; + ByteBuffer appIn; if (_decryptedInput == null) { if (BufferUtil.space(buffer) > _sslEngine.getSession().getApplicationBufferSize()) - app_in = buffer; + appIn = buffer; else - app_in = _decryptedInput = _bufferPool.acquire(_sslEngine.getSession().getApplicationBufferSize(), _decryptedDirectBuffers); + appIn = _decryptedInput = _bufferPool.acquire(_sslEngine.getSession().getApplicationBufferSize(), _decryptedDirectBuffers); } else { - app_in = _decryptedInput; + appIn = _decryptedInput; BufferUtil.compact(_encryptedInput); } - + // Let's try reading some encrypted data... even if we have some already. - int net_filled = getEndPoint().fill(_encryptedInput); + int netFilled = getEndPoint().fill(_encryptedInput); if (LOG.isDebugEnabled()) - LOG.debug("net filled={}", net_filled); + LOG.debug("net filled={}", netFilled); - if (net_filled > 0 && _handshake.get() == Handshake.INITIAL && isOutboundDone()) + if (netFilled > 0 && _handshake.get() == Handshake.INITIAL && isOutboundDone()) throw new SSLHandshakeException("Closed during handshake"); // Let's unwrap even if we have no net data because in that // case we want to fall through to the handshake handling - int pos = BufferUtil.flipToFill(app_in); + int pos = BufferUtil.flipToFill(appIn); SSLEngineResult unwrapResult; try { _underflown = false; - unwrapResult = _sslEngine.unwrap(_encryptedInput, app_in); + unwrapResult = _sslEngine.unwrap(_encryptedInput, appIn); } finally { - BufferUtil.flipToFlush(app_in, pos); + BufferUtil.flipToFlush(appIn, pos); } - if (LOG.isDebugEnabled()) - LOG.debug("unwrap {} {} unwrapBuffer={} appBuffer={}", - net_filled, - unwrapResult.toString().replace('\n',' '), - BufferUtil.toDetailString(app_in), + LOG.debug("unwrap net_filled={} {} encryptedBuffer={} unwrapBuffer={} appBuffer={}", + netFilled, + StringUtil.replace(unwrapResult.toString(), '\n', ' '), + BufferUtil.toSummaryString(_encryptedInput), + BufferUtil.toDetailString(appIn), BufferUtil.toDetailString(buffer)); SSLEngineResult.Status unwrap = unwrapResult.getStatus(); // Extra check on unwrapResultStatus == OK with zero bytes consumed // or produced is due to an SSL client on Android (see bug #454773). - if (unwrap==Status.OK && unwrapResult.bytesConsumed() == 0 && unwrapResult.bytesProduced() == 0) + if (unwrap == Status.OK && unwrapResult.bytesConsumed() == 0 && unwrapResult.bytesProduced() == 0) unwrap = Status.BUFFER_UNDERFLOW; - + switch (unwrap) { case CLOSED: return filled = -1; - + case BUFFER_UNDERFLOW: - if (net_filled > 0) + if (netFilled > 0) continue; // try filling some more _underflown = true; - if (net_filled < 0 && _sslEngine.getUseClientMode()) + if (netFilled < 0 && _sslEngine.getUseClientMode()) { closeInbound(); return filled = -1; } - return filled = net_filled; + return filled = netFilled; case OK: { if (unwrapResult.getHandshakeStatus() == HandshakeStatus.FINISHED) handshakeSucceeded(); - + if (isRenegotiating() && !allowRenegotiate()) return filled = -1; @@ -605,14 +624,14 @@ public class SslConnection extends AbstractConnection // another call to fill() or flush(). if (unwrapResult.bytesProduced() > 0) { - if (app_in==buffer) + if (appIn == buffer) return filled = unwrapResult.bytesProduced(); - return filled = BufferUtil.append(buffer,_decryptedInput); + return filled = BufferUtil.append(buffer, _decryptedInput); } - + break; } - + default: throw new IllegalStateException("Unexpected unwrap result " + unwrap); } @@ -622,10 +641,10 @@ public class SslConnection extends AbstractConnection { handshakeFailed(x); - if (_flushState==FlushState.WAIT_FOR_FILL) + if (_flushState == FlushState.WAIT_FOR_FILL) { - _flushState=FlushState.IDLE; - getExecutor().execute(()->_decryptedEndPoint.getWriteFlusher().onFail(x)); + _flushState = FlushState.IDLE; + getExecutor().execute(() -> _decryptedEndPoint.getWriteFlusher().onFail(x)); } throw x; @@ -637,19 +656,19 @@ public class SslConnection extends AbstractConnection _bufferPool.release(_encryptedInput); _encryptedInput = null; } - + if (_decryptedInput != null && !_decryptedInput.hasRemaining()) { _bufferPool.release(_decryptedInput); _decryptedInput = null; } - if (_flushState==FlushState.WAIT_FOR_FILL) + if (_flushState == FlushState.WAIT_FOR_FILL) { - _flushState=FlushState.IDLE; - getExecutor().execute(()->_decryptedEndPoint.getWriteFlusher().completeWrite()); + _flushState = FlushState.IDLE; + getExecutor().execute(() -> _decryptedEndPoint.getWriteFlusher().completeWrite()); } - + if (LOG.isDebugEnabled()) LOG.debug("needFillInterest uf={} {}", _underflown, SslConnection.this); - LOG.debug("ei={} di={}",BufferUtil.toDetailString(_encryptedInput),BufferUtil.toDetailString(_decryptedInput)); + LOG.debug("ei={} di={}", BufferUtil.toDetailString(_encryptedInput), BufferUtil.toDetailString(_decryptedInput)); } - if (_fillState!=FillState.IDLE) + if (_fillState != FillState.IDLE) return; // Fillable if we have decrypted Input OR encrypted input that has not yet been underflown. @@ -720,10 +739,10 @@ public class SslConnection extends AbstractConnection } if (LOG.isDebugEnabled()) - LOG.debug("0) + if (_renegotiationLimit > 0) _renegotiationLimit--; } } @@ -799,26 +818,34 @@ public class SslConnection extends AbstractConnection LOG.ignore(x); } } - + @Override public boolean flush(ByteBuffer... appOuts) throws IOException { try { - synchronized(_decryptedEndPoint) + synchronized (_decryptedEndPoint) { if (LOG.isDebugEnabled()) { LOG.debug(">flush {}", SslConnection.this); - int i=0; + int i = 0; for (ByteBuffer b : appOuts) + { LOG.debug("flush b[{}]={}", i++, BufferUtil.toDetailString(b)); + } } + // finish of any previous flushes + if (BufferUtil.hasContent(_encryptedOutput) && !getEndPoint().flush(_encryptedOutput)) + return false; + + boolean isEmpty = BufferUtil.isEmpty(appOuts); + Boolean result = null; try { - if (_flushState!=FlushState.IDLE) + if (_flushState != FlushState.IDLE) return result = false; // Keep going while we can make progress or until we are done @@ -826,8 +853,8 @@ public class SslConnection extends AbstractConnection { HandshakeStatus status = _sslEngine.getHandshakeStatus(); if (LOG.isDebugEnabled()) - LOG.debug("flush {}",status); - switch(status) + LOG.debug("flush {}", status); + switch (status) { case NEED_WRAP: case NOT_HANDSHAKING: @@ -836,18 +863,18 @@ public class SslConnection extends AbstractConnection case NEED_TASK: _sslEngine.getDelegatedTask().run(); continue; - + case NEED_UNWRAP: - if (_fillState==FillState.IDLE) + if (_fillState == FillState.IDLE) { int filled = fill(BufferUtil.EMPTY_BUFFER); - if (_sslEngine.getHandshakeStatus()!=status) + if (_sslEngine.getHandshakeStatus() != status) continue; if (filled < 0) throw new IOException("Broken pipe"); } - return result = false; - + return result = isEmpty; + default: throw new IllegalStateException("Unexpected HandshakeStatus " + status); } @@ -862,19 +889,20 @@ public class SslConnection extends AbstractConnection try { wrapResult = _sslEngine.wrap(appOuts, _encryptedOutput); - if (LOG.isDebugEnabled()) - LOG.debug("wrap {} {}", wrapResult.toString().replace('\n',' '), BufferUtil.toHexSummary(_encryptedOutput)); } finally { BufferUtil.flipToFlush(_encryptedOutput, pos); } - + if (LOG.isDebugEnabled()) + LOG.debug("wrap {} {} ioDone={}/{}", + StringUtil.replace(wrapResult.toString(), '\n', ' '), + BufferUtil.toSummaryString(_encryptedOutput), + _sslEngine.isInboundDone(), + _sslEngine.isOutboundDone()); + // Was all the data consumed? - boolean allConsumed=true; - for (ByteBuffer b : appOuts) - if (BufferUtil.hasContent(b)) - allConsumed=false; + isEmpty = BufferUtil.isEmpty(appOuts); // if we have net bytes, let's try to flush them boolean flushed = true; @@ -882,7 +910,7 @@ public class SslConnection extends AbstractConnection flushed = getEndPoint().flush(_encryptedOutput); if (LOG.isDebugEnabled()) - LOG.debug("net flushed={}, ac={}", flushed, allConsumed); + LOG.debug("net flushed={}, ac={}", flushed, isEmpty); // Now deal with the results returned from the wrap Status wrap = wrapResult.getStatus(); @@ -895,16 +923,16 @@ public class SslConnection extends AbstractConnection if (!flushed) return result = false; getEndPoint().shutdownOutput(); - if (allConsumed) + if (isEmpty) return result = true; throw new IOException("Broken pipe"); } - + case BUFFER_OVERFLOW: if (!flushed) return result = false; continue; - + case OK: if (wrapResult.getHandshakeStatus() == HandshakeStatus.FINISHED) handshakeSucceeded(); @@ -912,15 +940,20 @@ public class SslConnection extends AbstractConnection if (isRenegotiating() && !allowRenegotiate()) { getEndPoint().shutdownOutput(); - if (allConsumed && BufferUtil.isEmpty(_encryptedOutput)) + if (isEmpty && BufferUtil.isEmpty(_encryptedOutput)) return result = true; throw new IOException("Broken pipe"); } if (!flushed) return result = false; - if (allConsumed) - return result = true; + + if (isEmpty) + { + if (wrapResult.getHandshakeStatus() != HandshakeStatus.NEED_WRAP || + wrapResult.bytesProduced() == 0) + return result = true; + } break; default: @@ -960,24 +993,24 @@ public class SslConnection extends AbstractConnection { boolean fillInterest = false; ByteBuffer write = null; - synchronized(_decryptedEndPoint) + synchronized (_decryptedEndPoint) { if (LOG.isDebugEnabled()) LOG.debug(">onIncompleteFlush {} {}", SslConnection.this, BufferUtil.toDetailString(_encryptedOutput)); - if (_flushState!=FlushState.IDLE) + if (_flushState != FlushState.IDLE) return; - while(true) + while (true) { HandshakeStatus status = _sslEngine.getHandshakeStatus(); - switch(status) + switch (status) { case NEED_TASK: case NEED_WRAP: case NOT_HANDSHAKING: // write what we have or an empty buffer to reschedule a call to flush - write = BufferUtil.hasContent(_encryptedOutput)?_encryptedOutput:BufferUtil.EMPTY_BUFFER; + write = BufferUtil.hasContent(_encryptedOutput) ? _encryptedOutput : BufferUtil.EMPTY_BUFFER; _flushState = FlushState.WRITING; break; @@ -990,7 +1023,7 @@ public class SslConnection extends AbstractConnection break; } - if (_fillState!=FillState.IDLE) + if (_fillState != FillState.IDLE) { // Wait for a fill that is happening anyway _flushState = FlushState.WAIT_FOR_FILL; @@ -1002,12 +1035,12 @@ public class SslConnection extends AbstractConnection { int filled = fill(BufferUtil.EMPTY_BUFFER); // If this changed the status, let's try again - if (_sslEngine.getHandshakeStatus()!=status) + if (_sslEngine.getHandshakeStatus() != status) continue; if (filled < 0) throw new IOException("Broken pipe"); } - catch(IOException e) + catch (IOException e) { LOG.debug(e); close(e); @@ -1032,7 +1065,7 @@ public class SslConnection extends AbstractConnection LOG.debug(" + { + }, t -> endp.close()), _encryptedOutput); + } + } + if (close) - getEndPoint().close(); + endp.close(); else ensureFillInterested(); } catch (Throwable x) { LOG.ignore(x); - getEndPoint().close(); + endp.close(); } } @@ -1101,7 +1149,7 @@ public class SslConnection extends AbstractConnection private void ensureFillInterested() { if (LOG.isDebugEnabled()) - LOG.debug("ensureFillInterested {}",SslConnection.this); + LOG.debug("ensureFillInterested {}", SslConnection.this); SslConnection.this.tryFillInterested(_sslReadCallback); } @@ -1142,7 +1190,7 @@ public class SslConnection extends AbstractConnection @Override public boolean isInputShutdown() { - return getEndPoint().isInputShutdown() || isInboundDone(); + return BufferUtil.isEmpty(_decryptedInput) && (getEndPoint().isInputShutdown() || isInboundDone()); } private boolean isInboundDone() @@ -1158,7 +1206,7 @@ public class SslConnection extends AbstractConnection } } - private void notifyHandshakeSucceeded(SSLEngine sslEngine) + private void notifyHandshakeSucceeded(SSLEngine sslEngine) throws SSLException { SslHandshakeListener.Event event = null; for (SslHandshakeListener listener : handshakeListeners) @@ -1169,6 +1217,10 @@ public class SslConnection extends AbstractConnection { listener.handshakeSucceeded(event); } + catch (SSLException x) + { + throw x; + } catch (Throwable x) { LOG.info("Exception while notifying listener " + listener, x); @@ -1200,9 +1252,7 @@ public class SslConnection extends AbstractConnection return false; if (isTLS13()) return false; - if (_sslEngine.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING) - return false; - return true; + return _sslEngine.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING; } private boolean allowRenegotiate() @@ -1215,7 +1265,7 @@ public class SslConnection extends AbstractConnection return false; } - if (getRenegotiationLimit()==0) + if (getRenegotiationLimit() == 0) { if (LOG.isDebugEnabled()) LOG.debug("Renegotiation limit exceeded {}", SslConnection.this); @@ -1242,16 +1292,16 @@ public class SslConnection extends AbstractConnection { @Override public void succeeded() - { + { boolean fillable; - synchronized(_decryptedEndPoint) + synchronized (_decryptedEndPoint) { if (LOG.isDebugEnabled()) LOG.debug("IncompleteWriteCB succeeded {}", SslConnection.this); - + releaseEncryptedOutputBuffer(); _flushState = FlushState.IDLE; - fillable = _fillState==FillState.WAIT_FOR_FLUSH; + fillable = _fillState == FillState.WAIT_FOR_FLUSH; if (fillable) _fillState = FillState.IDLE; } @@ -1261,43 +1311,43 @@ public class SslConnection extends AbstractConnection _decryptedEndPoint.getWriteFlusher().completeWrite(); } - + @Override public void failed(final Throwable x) { - boolean fail_fill_interest; - synchronized(_decryptedEndPoint) + boolean failFillInterest; + synchronized (_decryptedEndPoint) { if (LOG.isDebugEnabled()) LOG.debug("IncompleteWriteCB failed {}", SslConnection.this, x); - + BufferUtil.clear(_encryptedOutput); releaseEncryptedOutputBuffer(); - + _flushState = FlushState.IDLE; - fail_fill_interest = _fillState==FillState.WAIT_FOR_FLUSH; - if (fail_fill_interest) + failFillInterest = _fillState == FillState.WAIT_FOR_FLUSH; + if (failFillInterest) _fillState = FillState.IDLE; } - - getExecutor().execute(()-> + + getExecutor().execute(() -> { - if (fail_fill_interest) + if (failFillInterest) _decryptedEndPoint.getFillInterest().onFail(x); _decryptedEndPoint.getWriteFlusher().onFail(x); }); } - + @Override public InvocationType getInvocationType() { return _decryptedEndPoint.getWriteFlusher().getCallbackInvocationType(); } - + @Override public String toString() { - return String.format("SSL@%h.DEP.writeCallback",SslConnection.this); + return String.format("SSL@%h.DEP.writeCallback", SslConnection.this); } } } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslHandshakeListener.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslHandshakeListener.java index c2961d5ec77..6706e269ba3 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslHandshakeListener.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslHandshakeListener.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,8 +20,8 @@ package org.eclipse.jetty.io.ssl; import java.util.EventListener; import java.util.EventObject; - import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLException; /** *

        Implementations of this interface are notified of TLS handshake events.

        @@ -35,8 +35,9 @@ public interface SslHandshakeListener extends EventListener *

        Callback method invoked when the TLS handshake succeeds.

        * * @param event the event object carrying information about the TLS handshake event + * @throws SSLException if any error happen during handshake */ - default void handshakeSucceeded(Event event) + default void handshakeSucceeded(Event event) throws SSLException { } @@ -53,7 +54,7 @@ public interface SslHandshakeListener extends EventListener /** *

        The event object carrying information about TLS handshake events.

        */ - public static class Event extends EventObject + class Event extends EventObject { public Event(Object source) { diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/package-info.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/package-info.java index dc21922272b..42403dc5dfe 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/package-info.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/ArrayByteBufferPoolTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/ArrayByteBufferPoolTest.java index a8ab2a5df0b..57d6b496a6d 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/ArrayByteBufferPoolTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/ArrayByteBufferPoolTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,76 +18,60 @@ package org.eclipse.jetty.io; -import static org.hamcrest.Matchers.greaterThanOrEqualTo; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.nio.ByteBuffer; import java.util.Arrays; +import java.util.Objects; import org.eclipse.jetty.io.ByteBufferPool.Bucket; import org.junit.jupiter.api.Test; -@SuppressWarnings("ReferenceEquality") +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.hamcrest.Matchers.lessThan; +import static org.hamcrest.Matchers.lessThanOrEqualTo; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class ArrayByteBufferPoolTest { @Test - public void testMinimumRelease() throws Exception + public void testMinimumRelease() { - ArrayByteBufferPool bufferPool = new ArrayByteBufferPool(10,100,1000); + ArrayByteBufferPool bufferPool = new ArrayByteBufferPool(10, 100, 1000); ByteBufferPool.Bucket[] buckets = bufferPool.bucketsFor(true); - for (int size=1;size<=9;size++) + for (int size = 1; size <= 9; size++) { ByteBuffer buffer = bufferPool.acquire(size, true); assertTrue(buffer.isDirect()); - assertEquals(size,buffer.capacity()); - for (ByteBufferPool.Bucket bucket : buckets) - assertTrue(bucket.isEmpty()); - - bufferPool.release(buffer); - - for (ByteBufferPool.Bucket bucket : buckets) - assertTrue(bucket.isEmpty()); - } - } - - @Test - public void testMaxRelease() throws Exception - { - ArrayByteBufferPool bufferPool = new ArrayByteBufferPool(10,100,1000); - ByteBufferPool.Bucket[] buckets = bufferPool.bucketsFor(true); - - for (int size=999;size<=1001;size++) - { - bufferPool.clear(); - ByteBuffer buffer = bufferPool.acquire(size, true); - - assertTrue(buffer.isDirect()); - assertThat(buffer.capacity(),greaterThanOrEqualTo(size)); - for (ByteBufferPool.Bucket bucket : buckets) - assertTrue(bucket.isEmpty()); - - bufferPool.release(buffer); - - int pooled=0; + assertEquals(size, buffer.capacity()); for (ByteBufferPool.Bucket bucket : buckets) { - pooled+=bucket.size(); + if (bucket != null) + assertTrue(bucket.isEmpty()); + } + + bufferPool.release(buffer); + + for (ByteBufferPool.Bucket bucket : buckets) + { + if (bucket != null) + assertTrue(bucket.isEmpty()); } - assertEquals(size<=1000,1==pooled); } } @Test - public void testAcquireRelease() throws Exception + public void testMaxRelease() { - ArrayByteBufferPool bufferPool = new ArrayByteBufferPool(10,100,1000); + ArrayByteBufferPool bufferPool = new ArrayByteBufferPool(10, 100, 1000); ByteBufferPool.Bucket[] buckets = bufferPool.bucketsFor(true); - for (int size=390;size<=510;size++) + for (int size = 999; size <= 1001; size++) { bufferPool.clear(); ByteBuffer buffer = bufferPool.acquire(size, true); @@ -95,32 +79,57 @@ public class ArrayByteBufferPoolTest assertTrue(buffer.isDirect()); assertThat(buffer.capacity(), greaterThanOrEqualTo(size)); for (ByteBufferPool.Bucket bucket : buckets) - assertTrue(bucket.isEmpty()); + { + if (bucket != null) + assertTrue(bucket.isEmpty()); + } bufferPool.release(buffer); - int pooled=0; - for (ByteBufferPool.Bucket bucket : buckets) - { - if (!bucket.isEmpty()) - { - pooled+=bucket.size(); - // TODO assertThat(bucket._bufferSize,greaterThanOrEqualTo(size)); - // TODO assertThat(bucket._bufferSize,Matchers.lessThan(size+100)); - } - } - assertEquals(1,pooled); + int pooled = Arrays.stream(buckets) + .filter(Objects::nonNull) + .mapToInt(Bucket::size) + .sum(); + assertEquals(size <= 1000, 1 == pooled); } } @Test - @SuppressWarnings("ReferenceEquality") - public void testAcquireReleaseAcquire() throws Exception + public void testAcquireRelease() { - ArrayByteBufferPool bufferPool = new ArrayByteBufferPool(10,100,1000); + ArrayByteBufferPool bufferPool = new ArrayByteBufferPool(10, 100, 1000); ByteBufferPool.Bucket[] buckets = bufferPool.bucketsFor(true); - for (int size=390;size<=510;size++) + for (int size = 390; size <= 510; size++) + { + bufferPool.clear(); + ByteBuffer buffer = bufferPool.acquire(size, true); + + assertTrue(buffer.isDirect()); + assertThat(buffer.capacity(), greaterThanOrEqualTo(size)); + for (ByteBufferPool.Bucket bucket : buckets) + { + if (bucket != null) + assertTrue(bucket.isEmpty()); + } + + bufferPool.release(buffer); + + int pooled = Arrays.stream(buckets) + .filter(Objects::nonNull) + .mapToInt(Bucket::size) + .sum(); + assertEquals(1, pooled); + } + } + + @Test + public void testAcquireReleaseAcquire() + { + ArrayByteBufferPool bufferPool = new ArrayByteBufferPool(10, 100, 1000); + ByteBufferPool.Bucket[] buckets = bufferPool.bucketsFor(true); + + for (int size = 390; size <= 510; size++) { bufferPool.clear(); ByteBuffer buffer1 = bufferPool.acquire(size, true); @@ -130,45 +139,80 @@ public class ArrayByteBufferPoolTest ByteBuffer buffer3 = bufferPool.acquire(size, false); bufferPool.release(buffer3); - int pooled=0; - for (ByteBufferPool.Bucket bucket : buckets) - { - if (!bucket.isEmpty()) - { - pooled+=bucket.size(); - // TODO assertThat(bucket._bufferSize,greaterThanOrEqualTo(size)); - // TODO assertThat(bucket._bufferSize,Matchers.lessThan(size+100)); - } - } - assertEquals(1,pooled); + int pooled = Arrays.stream(buckets) + .filter(Objects::nonNull) + .mapToInt(Bucket::size) + .sum(); + assertEquals(1, pooled); - assertTrue(buffer1==buffer2); - assertTrue(buffer1!=buffer3); + assertSame(buffer1, buffer2); + assertNotSame(buffer1, buffer3); } } - @Test - public void testMaxQueue() throws Exception + public void testMaxQueue() { - ArrayByteBufferPool bufferPool = new ArrayByteBufferPool(-1,-1,-1,2); + ArrayByteBufferPool bufferPool = new ArrayByteBufferPool(-1, -1, -1, 2); ByteBuffer buffer1 = bufferPool.acquire(512, false); ByteBuffer buffer2 = bufferPool.acquire(512, false); ByteBuffer buffer3 = bufferPool.acquire(512, false); Bucket[] buckets = bufferPool.bucketsFor(false); - Arrays.asList(buckets).forEach(b->assertEquals(0,b.size())); - + Arrays.stream(buckets) + .filter(Objects::nonNull) + .forEach(b -> assertEquals(0, b.size())); + bufferPool.release(buffer1); - Bucket bucket=Arrays.asList(buckets).stream().filter(b->b.size()>0).findFirst().get(); + Bucket bucket = Arrays.stream(buckets) + .filter(Objects::nonNull) + .filter(b -> b.size() > 0) + .findFirst() + .orElseThrow(AssertionError::new); assertEquals(1, bucket.size()); bufferPool.release(buffer2); assertEquals(2, bucket.size()); - + bufferPool.release(buffer3); assertEquals(2, bucket.size()); } + @Test + public void testMaxMemory() + { + int factor = 1024; + int maxMemory = 11 * 1024; + ArrayByteBufferPool bufferPool = new ArrayByteBufferPool(-1, factor, -1, -1, -1, maxMemory); + Bucket[] buckets = bufferPool.bucketsFor(true); + + // Create the buckets - the oldest is the larger. + // 1+2+3+4=10 / maxMemory=11. + for (int i = 4; i >= 1; --i) + { + int capacity = factor * i; + ByteBuffer buffer = bufferPool.acquire(capacity, true); + bufferPool.release(buffer); + } + + // Create and release a buffer to exceed the max memory. + ByteBuffer buffer = bufferPool.newByteBuffer(2 * factor, true); + bufferPool.release(buffer); + + // Now the oldest buffer should be gone and we have: 1+2x2+3=8 + long memory = bufferPool.getMemory(true); + assertThat(memory, lessThan((long)maxMemory)); + assertNull(buckets[3]); + + // Create and release a large buffer. + // Max memory is exceeded and buckets 3 and 1 are cleared. + // We will have 2x2+7=11. + buffer = bufferPool.newByteBuffer(7 * factor, true); + bufferPool.release(buffer); + memory = bufferPool.getMemory(true); + assertThat(memory, lessThanOrEqualTo((long)maxMemory)); + assertNull(buckets[0]); + assertNull(buckets[2]); + } } diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/ByteArrayEndPointTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/ByteArrayEndPointTest.java index 68e681a00f6..01dc31af16f 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/ByteArrayEndPointTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/ByteArrayEndPointTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,16 +18,6 @@ package org.eclipse.jetty.io; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.greaterThan; -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.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - import java.io.IOException; import java.nio.ByteBuffer; import java.util.concurrent.ExecutionException; @@ -42,6 +32,16 @@ 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.greaterThan; +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.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + public class ByteArrayEndPointTest { private Scheduler _scheduler; @@ -67,20 +67,20 @@ public class ByteArrayEndPointTest ByteBuffer buffer = BufferUtil.allocate(1024); - assertEquals(10,endp.fill(buffer)); - assertEquals("test input",BufferUtil.toString(buffer)); + assertEquals(10, endp.fill(buffer)); + assertEquals("test input", BufferUtil.toString(buffer)); - assertEquals(0,endp.fill(buffer)); + assertEquals(0, endp.fill(buffer)); endp.addInput(" more"); - assertEquals(5,endp.fill(buffer)); - assertEquals("test input more",BufferUtil.toString(buffer)); + assertEquals(5, endp.fill(buffer)); + assertEquals("test input more", BufferUtil.toString(buffer)); - assertEquals(0,endp.fill(buffer)); + assertEquals(0, endp.fill(buffer)); endp.addInput((ByteBuffer)null); - assertEquals(-1,endp.fill(buffer)); + assertEquals(-1, endp.fill(buffer)); endp.close(); @@ -89,66 +89,65 @@ public class ByteArrayEndPointTest endp.fill(buffer); fail("Expected IOException"); } - catch(IOException e) + catch (IOException e) { - assertThat(e.getMessage(),containsString("CLOSED")); + assertThat(e.getMessage(), containsString("CLOSED")); } endp.reset(); endp.addInput("and more"); buffer = BufferUtil.allocate(4); - assertEquals(4,endp.fill(buffer)); - assertEquals("and ",BufferUtil.toString(buffer)); - assertEquals(0,endp.fill(buffer)); + assertEquals(4, endp.fill(buffer)); + assertEquals("and ", BufferUtil.toString(buffer)); + assertEquals(0, endp.fill(buffer)); BufferUtil.clear(buffer); - assertEquals(4,endp.fill(buffer)); - assertEquals("more",BufferUtil.toString(buffer)); + assertEquals(4, endp.fill(buffer)); + assertEquals("more", BufferUtil.toString(buffer)); } @Test public void testGrowingFlush() throws Exception { - ByteArrayEndPoint endp = new ByteArrayEndPoint((byte[])null,15); + ByteArrayEndPoint endp = new ByteArrayEndPoint((byte[])null, 15); endp.setGrowOutput(true); - assertEquals(true,endp.flush(BufferUtil.toBuffer("some output"))); - assertEquals("some output",endp.getOutputString()); + assertEquals(true, endp.flush(BufferUtil.toBuffer("some output"))); + assertEquals("some output", endp.getOutputString()); - assertEquals(true,endp.flush(BufferUtil.toBuffer(" some more"))); - assertEquals("some output some more",endp.getOutputString()); + assertEquals(true, endp.flush(BufferUtil.toBuffer(" some more"))); + assertEquals("some output some more", endp.getOutputString()); - assertEquals(true,endp.flush()); - assertEquals("some output some more",endp.getOutputString()); + assertEquals(true, endp.flush()); + assertEquals("some output some more", endp.getOutputString()); - assertEquals(true,endp.flush(BufferUtil.EMPTY_BUFFER)); - assertEquals("some output some more",endp.getOutputString()); + assertEquals(true, endp.flush(BufferUtil.EMPTY_BUFFER)); + assertEquals("some output some more", endp.getOutputString()); - assertEquals(true,endp.flush(BufferUtil.EMPTY_BUFFER,BufferUtil.toBuffer(" and"),BufferUtil.toBuffer(" more"))); - assertEquals("some output some more and more",endp.getOutputString()); + assertEquals(true, endp.flush(BufferUtil.EMPTY_BUFFER, BufferUtil.toBuffer(" and"), BufferUtil.toBuffer(" more"))); + assertEquals("some output some more and more", endp.getOutputString()); endp.close(); } @Test public void testFlush() throws Exception { - ByteArrayEndPoint endp = new ByteArrayEndPoint((byte[])null,15); + ByteArrayEndPoint endp = new ByteArrayEndPoint((byte[])null, 15); endp.setGrowOutput(false); endp.setOutput(BufferUtil.allocate(10)); ByteBuffer data = BufferUtil.toBuffer("Some more data."); - assertEquals(false,endp.flush(data)); - assertEquals("Some more ",endp.getOutputString()); - assertEquals("data.",BufferUtil.toString(data)); + assertEquals(false, endp.flush(data)); + assertEquals("Some more ", endp.getOutputString()); + assertEquals("data.", BufferUtil.toString(data)); - assertEquals("Some more ",endp.takeOutputString()); + assertEquals("Some more ", endp.takeOutputString()); - assertEquals(true,endp.flush(data)); - assertEquals("data.",BufferUtil.toString(endp.takeOutput())); + assertEquals(true, endp.flush(data)); + assertEquals("data.", BufferUtil.toString(endp.takeOutput())); endp.close(); } - @Test public void testReadable() throws Exception { @@ -159,7 +158,7 @@ public class ByteArrayEndPointTest FutureCallback fcb = new FutureCallback(); endp.fillInterested(fcb); - fcb.get(100,TimeUnit.MILLISECONDS); + fcb.get(100, TimeUnit.MILLISECONDS); assertTrue(fcb.isDone()); assertEquals(null, fcb.get()); assertEquals(10, endp.fill(buffer)); @@ -172,7 +171,7 @@ public class ByteArrayEndPointTest assertEquals(0, endp.fill(buffer)); endp.addInput(" more"); - fcb.get(1000,TimeUnit.MILLISECONDS); + fcb.get(1000, TimeUnit.MILLISECONDS); assertTrue(fcb.isDone()); assertEquals(null, fcb.get()); assertEquals(5, endp.fill(buffer)); @@ -191,7 +190,7 @@ public class ByteArrayEndPointTest fcb = new FutureCallback(); endp.fillInterested(fcb); - fcb.get(1000,TimeUnit.MILLISECONDS); + fcb.get(1000, TimeUnit.MILLISECONDS); assertTrue(fcb.isDone()); assertEquals(null, fcb.get()); assertEquals(-1, endp.fill(buffer)); @@ -203,7 +202,7 @@ public class ByteArrayEndPointTest try { - fcb.get(1000,TimeUnit.MILLISECONDS); + fcb.get(1000, TimeUnit.MILLISECONDS); fail("Expected ExecutionException"); } catch (ExecutionException e) @@ -223,7 +222,7 @@ public class ByteArrayEndPointTest ByteBuffer more = BufferUtil.toBuffer(" Some more."); FutureCallback fcb = new FutureCallback(); - endp.write( fcb, data); + endp.write(fcb, data); assertTrue(fcb.isDone()); assertEquals(null, fcb.get()); assertEquals("Data.", endp.getOutputString()); @@ -240,7 +239,7 @@ public class ByteArrayEndPointTest assertEquals(" more.", endp.getOutputString()); endp.close(); } - + /** * Simulate AbstractConnection.ReadCallback.failed() */ @@ -303,6 +302,5 @@ public class ByteArrayEndPointTest } assertThat(TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start), greaterThan(halfIdleTimeout)); assertThat("Endpoint open", endp.isOpen(), is(true)); - } } diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/CyclicTimeoutTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/CyclicTimeoutTest.java index 4d316d05030..e9438fd43d8 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/CyclicTimeoutTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/CyclicTimeoutTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,20 +18,19 @@ package org.eclipse.jetty.io; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler; import org.junit.jupiter.api.AfterEach; - import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class CyclicTimeoutTest { private volatile boolean _expired; @@ -41,10 +40,10 @@ public class CyclicTimeoutTest @BeforeEach public void before() throws Exception { - _expired=false; + _expired = false; _timer.start(); - - _timeout=new CyclicTimeout(_timer) + + _timeout = new CyclicTimeout(_timer) { @Override public void onTimeoutExpired() @@ -52,8 +51,8 @@ public class CyclicTimeoutTest _expired = true; } }; - - _timeout.schedule(1000,TimeUnit.MILLISECONDS); + + _timeout.schedule(1000, TimeUnit.MILLISECONDS); } @AfterEach @@ -66,10 +65,10 @@ public class CyclicTimeoutTest @Test public void testReschedule() throws Exception { - for (int i=0;i<20;i++) + for (int i = 0; i < 20; i++) { Thread.sleep(100); - assertTrue(_timeout.schedule(1000,TimeUnit.MILLISECONDS)); + assertTrue(_timeout.schedule(1000, TimeUnit.MILLISECONDS)); } assertFalse(_expired); } @@ -77,10 +76,10 @@ public class CyclicTimeoutTest @Test public void testExpire() throws Exception { - for (int i=0;i<5;i++) + for (int i = 0; i < 5; i++) { Thread.sleep(100); - assertTrue(_timeout.schedule(1000,TimeUnit.MILLISECONDS)); + assertTrue(_timeout.schedule(1000, TimeUnit.MILLISECONDS)); } Thread.sleep(1500); assertTrue(_expired); @@ -89,10 +88,10 @@ public class CyclicTimeoutTest @Test public void testCancel() throws Exception { - for (int i=0;i<5;i++) + for (int i = 0; i < 5; i++) { Thread.sleep(100); - assertTrue(_timeout.schedule(1000,TimeUnit.MILLISECONDS)); + assertTrue(_timeout.schedule(1000, TimeUnit.MILLISECONDS)); } _timeout.cancel(); Thread.sleep(1500); @@ -102,12 +101,12 @@ public class CyclicTimeoutTest @Test public void testShorten() throws Exception { - for (int i=0;i<5;i++) + for (int i = 0; i < 5; i++) { Thread.sleep(100); - assertTrue(_timeout.schedule(1000,TimeUnit.MILLISECONDS)); + assertTrue(_timeout.schedule(1000, TimeUnit.MILLISECONDS)); } - assertTrue(_timeout.schedule(100,TimeUnit.MILLISECONDS)); + assertTrue(_timeout.schedule(100, TimeUnit.MILLISECONDS)); Thread.sleep(400); assertTrue(_expired); } @@ -115,12 +114,12 @@ public class CyclicTimeoutTest @Test public void testLengthen() throws Exception { - for (int i=0;i<5;i++) + for (int i = 0; i < 5; i++) { Thread.sleep(100); - assertTrue(_timeout.schedule(1000,TimeUnit.MILLISECONDS)); + assertTrue(_timeout.schedule(1000, TimeUnit.MILLISECONDS)); } - assertTrue(_timeout.schedule(10000,TimeUnit.MILLISECONDS)); + assertTrue(_timeout.schedule(10000, TimeUnit.MILLISECONDS)); Thread.sleep(1500); assertFalse(_expired); } @@ -130,12 +129,12 @@ public class CyclicTimeoutTest { Thread.sleep(1500); assertTrue(_expired); - _expired=false; - assertFalse(_timeout.schedule(500,TimeUnit.MILLISECONDS)); + _expired = false; + assertFalse(_timeout.schedule(500, TimeUnit.MILLISECONDS)); Thread.sleep(1000); assertTrue(_expired); - _expired=false; - _timeout.schedule(500,TimeUnit.MILLISECONDS); + _expired = false; + _timeout.schedule(500, TimeUnit.MILLISECONDS); Thread.sleep(1000); assertTrue(_expired); } @@ -146,16 +145,16 @@ public class CyclicTimeoutTest { QueuedThreadPool pool = new QueuedThreadPool(200); pool.start(); - + long test_until = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(1500); - assertTrue(_timeout.schedule(100,TimeUnit.MILLISECONDS)); - while(System.nanoTime() + pool.execute(() -> { - _timeout.schedule(100,TimeUnit.MILLISECONDS); + _timeout.schedule(100, TimeUnit.MILLISECONDS); latch.countDown(); }); latch.await(); diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/IOTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/IOTest.java index f3e41098f60..0463922154f 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/IOTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/IOTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,15 +18,6 @@ package org.eclipse.jetty.io; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; @@ -52,10 +43,19 @@ import java.util.concurrent.TimeUnit; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.IO; - +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.OS; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + public class IOTest { @Test @@ -94,14 +94,8 @@ public class IOTest assertEquals(-1, server.getInputStream().read()); // but cannot write - try - { - client.getOutputStream().write(1); - fail("exception expected"); - } - catch (SocketException expected) - { - } + Assertions.assertThrows(SocketException.class, () -> client.getOutputStream().write(1)); + // but can still write in opposite direction. server.getOutputStream().write(1); @@ -111,14 +105,7 @@ public class IOTest server.shutdownInput(); // now we EOF instead of reading -1 - try - { - server.getInputStream().read(); - fail("exception expected"); - } - catch (SocketException expected) - { - } + Assertions.assertThrows(SocketException.class, () -> server.getInputStream().read()); // but can still write in opposite direction. server.getOutputStream().write(1); @@ -128,14 +115,7 @@ public class IOTest client.shutdownInput(); // now we EOF instead of reading -1 - try - { - client.getInputStream().read(); - fail("exception expected"); - } - catch (SocketException expected) - { - } + Assertions.assertThrows(SocketException.class, () -> client.getInputStream().read()); // But we can still write at the server (data which will never be read) server.getOutputStream().write(1); @@ -147,14 +127,7 @@ public class IOTest server.shutdownOutput(); // and now we can't write - try - { - server.getOutputStream().write(1); - fail("exception expected"); - } - catch (SocketException expected) - { - } + Assertions.assertThrows(SocketException.class, () -> server.getOutputStream().write(1)); // but the sockets are still open assertFalse(client.isClosed()); @@ -227,7 +200,7 @@ public class IOTest catch (Exception e) { e.printStackTrace(); - assertTrue( OS.MAC.isCurrentOs()); + assertTrue(OS.MAC.isCurrentOs()); } } } @@ -289,10 +262,13 @@ public class IOTest client.getOutputStream().write(1); // Client eventually sees Broken Pipe - assertThrows(IOException.class, ()->{ + assertThrows(IOException.class, () -> + { int i = 0; for (i = 0; i < 100000; i++) + { client.getOutputStream().write(1); + } }); } } @@ -342,7 +318,9 @@ public class IOTest }); acceptor.start(); while (latch.getCount() == 2) + { Thread.sleep(10); + } // interrupt the acceptor acceptor.interrupt(); @@ -371,14 +349,12 @@ public class IOTest } } - - @Test public void testReset() throws Exception { try (ServerSocket connector = new ServerSocket(0); - Socket client = new Socket("127.0.0.1", connector.getLocalPort()); - Socket server = connector.accept()) + Socket client = new Socket("127.0.0.1", connector.getLocalPort()); + Socket server = connector.accept()) { client.setTcpNoDelay(true); client.setSoLinger(true, 0); @@ -417,12 +393,12 @@ public class IOTest { AsynchronousServerSocketChannel connector = AsynchronousServerSocketChannel.open(); connector.bind(null); - InetSocketAddress addr=(InetSocketAddress)connector.getLocalAddress(); + InetSocketAddress addr = (InetSocketAddress)connector.getLocalAddress(); Future acceptor = connector.accept(); AsynchronousSocketChannel client = AsynchronousSocketChannel.open(); - client.connect(new InetSocketAddress("127.0.0.1",addr.getPort())).get(5, TimeUnit.SECONDS); + client.connect(new InetSocketAddress("127.0.0.1", addr.getPort())).get(5, TimeUnit.SECONDS); AsynchronousSocketChannel server = acceptor.get(5, TimeUnit.SECONDS); @@ -447,31 +423,32 @@ public class IOTest if (!dir.exists()) dir.mkdir(); - File file = File.createTempFile("test",".txt",dir); + File file = File.createTempFile("test", ".txt", dir); file.deleteOnExit(); FileChannel out = FileChannel.open(file.toPath(), - StandardOpenOption.CREATE, - StandardOpenOption.READ, - StandardOpenOption.WRITE, - StandardOpenOption.DELETE_ON_CLOSE); + StandardOpenOption.CREATE, + StandardOpenOption.READ, + StandardOpenOption.WRITE, + StandardOpenOption.DELETE_ON_CLOSE); ByteBuffer[] buffers = new ByteBuffer[4096]; - long expected=0; - for (int i=0;i buckets = bufferPool.bucketsFor(true); + ConcurrentMap buckets = bufferPool.bucketsFor(true); int size = 512; ByteBuffer buffer = bufferPool.acquire(size, true); @@ -56,10 +59,10 @@ public class MappedByteBufferPoolTest } @Test - public void testAcquireReleaseAcquire() throws Exception + public void testAcquireReleaseAcquire() { MappedByteBufferPool bufferPool = new MappedByteBufferPool(); - ConcurrentMap buckets = bufferPool.bucketsFor(false); + ConcurrentMap buckets = bufferPool.bucketsFor(false); ByteBuffer buffer1 = bufferPool.acquire(512, false); bufferPool.release(buffer1); @@ -76,10 +79,10 @@ public class MappedByteBufferPoolTest } @Test - public void testAcquireReleaseClear() throws Exception + public void testAcquireReleaseClear() { MappedByteBufferPool bufferPool = new MappedByteBufferPool(); - ConcurrentMap buckets = bufferPool.bucketsFor(true); + ConcurrentMap buckets = bufferPool.bucketsFor(true); ByteBuffer buffer = bufferPool.acquire(512, true); bufferPool.release(buffer); @@ -91,16 +94,14 @@ public class MappedByteBufferPoolTest assertTrue(buckets.isEmpty()); } - + /** * In a scenario where MappedByteBufferPool is being used improperly, * such as releasing a buffer that wasn't created/acquired by the * MappedByteBufferPool, an assertion is tested for. - * - * @throws Exception test failure */ @Test - public void testReleaseAssertion() throws Exception + public void testReleaseAssertion() { int factor = 1024; MappedByteBufferPool bufferPool = new MappedByteBufferPool(factor); @@ -110,8 +111,8 @@ public class MappedByteBufferPoolTest // Release a few small non-pool buffers bufferPool.release(ByteBuffer.wrap(StringUtil.getUtf8Bytes("Hello"))); - /* NOTES: - * + /* NOTES: + * * 1) This test will pass on command line maven build, as its surefire setup uses "-ea" already. * 2) In Eclipse, goto the "Run Configuration" for this test case. * Select the "Arguments" tab, and make sure "-ea" is present in the text box titled "VM arguments" @@ -123,24 +124,24 @@ public class MappedByteBufferPoolTest // Expected path. } } - + @Test public void testTagged() { MappedByteBufferPool pool = new MappedByteBufferPool.Tagged(); - ByteBuffer buffer = pool.acquire(1024,false); + ByteBuffer buffer = pool.acquire(1024, false); - assertThat(BufferUtil.toDetailString(buffer),containsString("@T00000001")); - buffer = pool.acquire(1024,false); - assertThat(BufferUtil.toDetailString(buffer),containsString("@T00000002")); + assertThat(BufferUtil.toDetailString(buffer), containsString("@T00000001")); + buffer = pool.acquire(1024, false); + assertThat(BufferUtil.toDetailString(buffer), containsString("@T00000002")); } @Test - public void testMaxQueue() throws Exception + public void testMaxQueue() { - MappedByteBufferPool bufferPool = new MappedByteBufferPool(-1,2); - ConcurrentMap buckets = bufferPool.bucketsFor(false); + MappedByteBufferPool bufferPool = new MappedByteBufferPool(-1, 2); + ConcurrentMap buckets = bufferPool.bucketsFor(false); ByteBuffer buffer1 = bufferPool.acquire(512, false); ByteBuffer buffer2 = bufferPool.acquire(512, false); @@ -149,13 +150,50 @@ public class MappedByteBufferPoolTest bufferPool.release(buffer1); assertEquals(1, buckets.size()); - Bucket bucket=buckets.values().iterator().next(); + Bucket bucket = buckets.values().iterator().next(); assertEquals(1, bucket.size()); bufferPool.release(buffer2); assertEquals(2, bucket.size()); - + bufferPool.release(buffer3); assertEquals(2, bucket.size()); } + + @Test + public void testMaxMemory() + { + int factor = 1024; + int maxMemory = 11 * 1024; + MappedByteBufferPool bufferPool = new MappedByteBufferPool(factor, -1, null, -1, maxMemory); + ConcurrentMap buckets = bufferPool.bucketsFor(true); + + // Create the buckets - the oldest is the larger. + // 1+2+3+4=10 / maxMemory=11. + for (int i = 4; i >= 1; --i) + { + int capacity = factor * i; + ByteBuffer buffer = bufferPool.acquire(capacity, true); + bufferPool.release(buffer); + } + + // Create and release a buffer to exceed the max memory. + ByteBuffer buffer = bufferPool.newByteBuffer(2 * factor, true); + bufferPool.release(buffer); + + // Now the oldest buffer should be gone and we have: 1+2x2+3=8 + long memory = bufferPool.getMemory(true); + assertThat(memory, lessThan((long)maxMemory)); + assertNull(buckets.get(4)); + + // Create and release a large buffer. + // Max memory is exceeded and buckets 3 and 1 are cleared. + // We will have 2x2+7=11. + buffer = bufferPool.newByteBuffer(7 * factor, true); + bufferPool.release(buffer); + memory = bufferPool.getMemory(true); + assertThat(memory, lessThanOrEqualTo((long)maxMemory)); + assertNull(buckets.get(1)); + assertNull(buckets.get(3)); + } } diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/NIOTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/NIOTest.java index 8ecef4b3700..3dd1a65f5b1 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/NIOTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/NIOTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,10 +18,6 @@ package org.eclipse.jetty.io; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.net.ServerSocket; import java.net.Socket; import java.nio.ByteBuffer; @@ -31,6 +27,10 @@ import java.nio.channels.SocketChannel; 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; + /** * */ diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/SelectorManagerTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/SelectorManagerTest.java index 034e6eb8097..0c3845616fd 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/SelectorManagerTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/SelectorManagerTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,9 +18,6 @@ package org.eclipse.jetty.io; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; @@ -36,11 +33,13 @@ import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.eclipse.jetty.util.thread.TimerScheduler; import org.junit.jupiter.api.AfterEach; - import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledIfSystemProperty; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class SelectorManagerTest { private QueuedThreadPool executor = new QueuedThreadPool(); @@ -76,10 +75,10 @@ public class SelectorManagerTest protected EndPoint newEndPoint(SelectableChannel channel, ManagedSelector selector, SelectionKey key) throws IOException { SocketChannelEndPoint endp = new SocketChannelEndPoint(channel, selector, key, getScheduler()); - endp.setIdleTimeout(connectTimeout/2); + endp.setIdleTimeout(connectTimeout / 2); return endp; } - + @Override protected boolean doFinishConnect(SelectableChannel channel) throws IOException { diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/SocketChannelEndPointInterestsTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/SocketChannelEndPointInterestsTest.java index 87f5b03fbf1..cebf4594434 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/SocketChannelEndPointInterestsTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/SocketChannelEndPointInterestsTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,9 +18,6 @@ package org.eclipse.jetty.io; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -43,9 +40,11 @@ import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.eclipse.jetty.util.thread.Scheduler; import org.eclipse.jetty.util.thread.TimerScheduler; import org.junit.jupiter.api.AfterEach; - import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class SocketChannelEndPointInterestsTest { private QueuedThreadPool threadPool; @@ -79,7 +78,7 @@ public class SocketChannelEndPointInterestsTest interested.onIncompleteFlush(); } }; - + endp.setIdleTimeout(60000); return endp; } @@ -110,7 +109,7 @@ public class SocketChannelEndPointInterestsTest @AfterEach public void destroy() throws Exception { - if (scheduler!=null) + if (scheduler != null) scheduler.stop(); if (selectorManager != null) selectorManager.stop(); @@ -144,7 +143,7 @@ public class SocketChannelEndPointInterestsTest connection.fillInterested(); ByteBuffer output = ByteBuffer.allocate(size.get()); - endPoint.write(new Callback(){}, output); + endPoint.write(new Callback() {}, output); latch1.countDown(); } @@ -205,7 +204,9 @@ public class SocketChannelEndPointInterestsTest // Now read what was written, waking up the server for write InputStream clientInput = client.getInputStream(); while (size.getAndDecrement() > 0) + { clientInput.read(); + } assertNull(failure.get()); } diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/SocketChannelEndPointOpenCloseTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/SocketChannelEndPointOpenCloseTest.java index 0c5f1f5f21f..b3fa6288093 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/SocketChannelEndPointOpenCloseTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/SocketChannelEndPointOpenCloseTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,10 +18,6 @@ package org.eclipse.jetty.io; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.nio.ByteBuffer; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; @@ -31,6 +27,10 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; 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 SocketChannelEndPointOpenCloseTest { public static class EndPointPair @@ -52,15 +52,15 @@ public class SocketChannelEndPointOpenCloseTest public static void close() throws Exception { connector.close(); - connector=null; + connector = null; } private EndPointPair newConnection() throws Exception { EndPointPair c = new EndPointPair(); - c.client=new SocketChannelEndPoint(SocketChannel.open(connector.socket().getLocalSocketAddress()),null,null,null); - c.server=new SocketChannelEndPoint(connector.accept(),null,null,null); + c.client = new SocketChannelEndPoint(SocketChannel.open(connector.socket().getLocalSocketAddress()), null, null, null); + c.server = new SocketChannelEndPoint(connector.accept(), null, null, null); return c; } @@ -75,8 +75,8 @@ public class SocketChannelEndPointOpenCloseTest // Server receives the request int len = c.server.fill(buffer); - assertEquals(7,len); - assertEquals("request",BufferUtil.toString(buffer)); + assertEquals(7, len); + assertEquals("request", BufferUtil.toString(buffer)); // Client and server are open assertTrue(c.client.isOpen()); @@ -97,8 +97,8 @@ public class SocketChannelEndPointOpenCloseTest // Client reads response BufferUtil.clear(buffer); len = c.client.fill(buffer); - assertEquals(8,len); - assertEquals("response",BufferUtil.toString(buffer)); + assertEquals(8, len); + assertEquals("response", BufferUtil.toString(buffer)); // Client and server are open, server is oshut assertTrue(c.client.isOpen()); @@ -109,7 +109,7 @@ public class SocketChannelEndPointOpenCloseTest // Client reads -1 BufferUtil.clear(buffer); len = c.client.fill(buffer); - assertEquals(-1,len); + assertEquals(-1, len); // Client and server are open, server is oshut, client is ishut assertTrue(c.client.isOpen()); @@ -129,7 +129,7 @@ public class SocketChannelEndPointOpenCloseTest // Server reads close BufferUtil.clear(buffer); len = c.server.fill(buffer); - assertEquals(-1,len); + assertEquals(-1, len); // Client and Server are closed assertFalse(c.client.isOpen()); @@ -146,8 +146,8 @@ public class SocketChannelEndPointOpenCloseTest c.client.flush(BufferUtil.toBuffer("request")); int len = c.server.fill(buffer); - assertEquals(7,len); - assertEquals("request",BufferUtil.toString(buffer)); + assertEquals(7, len); + assertEquals("request", BufferUtil.toString(buffer)); assertTrue(c.client.isOpen()); assertFalse(c.client.isOutputShutdown()); @@ -162,7 +162,7 @@ public class SocketChannelEndPointOpenCloseTest assertFalse(c.server.isOutputShutdown()); len = c.server.fill(buffer); - assertEquals(-1,len); + assertEquals(-1, len); assertFalse(c.client.isOpen()); assertTrue(c.client.isOutputShutdown()); @@ -176,5 +176,4 @@ public class SocketChannelEndPointOpenCloseTest assertFalse(c.server.isOpen()); assertTrue(c.server.isOutputShutdown()); } - } diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/SocketChannelEndPointTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/SocketChannelEndPointTest.java index d0e11801a30..c53d267e3ca 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/SocketChannelEndPointTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/SocketChannelEndPointTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,15 +18,6 @@ package org.eclipse.jetty.io; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.greaterThan; -import static org.hamcrest.Matchers.greaterThanOrEqualTo; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; @@ -49,7 +40,6 @@ import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Stream; - import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLSocket; @@ -73,6 +63,15 @@ 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.greaterThan; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + @SuppressWarnings("Duplicates") public class SocketChannelEndPointTest { @@ -159,7 +158,7 @@ public class SocketChannelEndPointTest // wait for read timeout client.setSoTimeout(500); long start = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); - assertThrows(SocketTimeoutException.class, ()-> client.getInputStream().read()); + assertThrows(SocketTimeoutException.class, () -> client.getInputStream().read()); long duration = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) - start; assertThat("timeout duration", duration, greaterThanOrEqualTo(400L)); @@ -171,7 +170,7 @@ public class SocketChannelEndPointTest { int b = client.getInputStream().read(); assertThat("expect valid char integer", b, greaterThan(0)); - assertEquals(c, (char) b, "expect characters to be same"); + assertEquals(c, (char)b, "expect characters to be same"); } client.close(); @@ -214,7 +213,7 @@ public class SocketChannelEndPointTest // wait for read timeout long start = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); - assertThrows(SocketTimeoutException.class, ()-> client.getInputStream().read()); + assertThrows(SocketTimeoutException.class, () -> client.getInputStream().read()); assertTrue(TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) - start >= 400); // write then shutdown @@ -262,7 +261,7 @@ public class SocketChannelEndPointTest Thread.sleep((11 * specifiedTimeout) / 10); long start = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); - assertThrows(SocketTimeoutException.class, ()-> clientInputStream.read()); + assertThrows(SocketTimeoutException.class, () -> clientInputStream.read()); int elapsed = Long.valueOf(TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) - start).intValue(); assertThat("Expected timeout", elapsed, greaterThanOrEqualTo(3 * specifiedTimeout / 4)); @@ -417,7 +416,7 @@ public class SocketChannelEndPointTest int b = in.read(); byteNum++; assertTrue(b > 0); - assertEquals(c, (char) b, "test-" + i + "/" + j); + assertEquals(c, (char)b, "test-" + i + "/" + j); } if (i == 0) @@ -446,7 +445,6 @@ public class SocketChannelEndPointTest } } - @ParameterizedTest @MethodSource("scenarios") @Tag("Unstable") @@ -626,24 +624,23 @@ public class SocketChannelEndPointTest public static class SslScenario implements Scenario { private final NormalScenario _normalScenario; - private final SslContextFactory __sslCtxFactory = new SslContextFactory(); - private final ByteBufferPool __byteBufferPool = new MappedByteBufferPool(); + private final SslContextFactory _sslCtxFactory = new SslContextFactory.Server(); + private final ByteBufferPool _byteBufferPool = new MappedByteBufferPool(); public SslScenario(NormalScenario normalScenario) throws Exception { _normalScenario = normalScenario; File keystore = MavenTestingUtils.getTestResourceFile("keystore"); - __sslCtxFactory.setKeyStorePath(keystore.getAbsolutePath()); - __sslCtxFactory.setKeyStorePassword("storepwd"); - __sslCtxFactory.setKeyManagerPassword("keypwd"); - __sslCtxFactory.setEndpointIdentificationAlgorithm(""); - __sslCtxFactory.start(); + _sslCtxFactory.setKeyStorePath(keystore.getAbsolutePath()); + _sslCtxFactory.setKeyStorePassword("storepwd"); + _sslCtxFactory.setKeyManagerPassword("keypwd"); + _sslCtxFactory.start(); } @Override public Socket newClient(ServerSocketChannel connector) throws IOException { - SSLSocket socket = __sslCtxFactory.newSslSocket(); + SSLSocket socket = _sslCtxFactory.newSslSocket(); socket.connect(connector.socket().getLocalSocketAddress()); return socket; } @@ -651,11 +648,11 @@ public class SocketChannelEndPointTest @Override public Connection newConnection(SelectableChannel channel, EndPoint endpoint, Executor executor, AtomicInteger blockAt, AtomicInteger writeCount) { - SSLEngine engine = __sslCtxFactory.newSSLEngine(); + SSLEngine engine = _sslCtxFactory.newSSLEngine(); engine.setUseClientMode(false); - SslConnection sslConnection = new SslConnection(__byteBufferPool, executor, endpoint, engine); - sslConnection.setRenegotiationAllowed(__sslCtxFactory.isRenegotiationAllowed()); - sslConnection.setRenegotiationLimit(__sslCtxFactory.getRenegotiationLimit()); + SslConnection sslConnection = new SslConnection(_byteBufferPool, executor, endpoint, engine); + sslConnection.setRenegotiationAllowed(_sslCtxFactory.isRenegotiationAllowed()); + sslConnection.setRenegotiationLimit(_sslCtxFactory.getRenegotiationLimit()); Connection appConnection = _normalScenario.newConnection(channel, sslConnection.getDecryptedEndPoint(), executor, blockAt, writeCount); sslConnection.getDecryptedEndPoint().setConnection(appConnection); return sslConnection; @@ -817,7 +814,7 @@ public class SocketChannelEndPointTest } catch (InterruptedException | EofException e) { - if(LOG.isDebugEnabled()) + if (LOG.isDebugEnabled()) LOG.debug(e); else LOG.info(e.getClass().getName()); diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/SslConnectionTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/SslConnectionTest.java index 03bf26c0ad8..994b2a39f41 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/SslConnectionTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/SslConnectionTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,16 +18,12 @@ package org.eclipse.jetty.io; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.net.Socket; +import java.net.SocketTimeoutException; import java.nio.ByteBuffer; import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; @@ -36,8 +32,8 @@ import java.nio.channels.SocketChannel; import java.nio.charset.StandardCharsets; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; - import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLException; import javax.net.ssl.SSLSocket; @@ -52,19 +48,26 @@ import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.eclipse.jetty.util.thread.Scheduler; import org.eclipse.jetty.util.thread.TimerScheduler; import org.junit.jupiter.api.AfterEach; - -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class SslConnectionTest { private static final int TIMEOUT = 1000000; private static ByteBufferPool __byteBufferPool = new LeakTrackingByteBufferPool(new MappedByteBufferPool.Tagged()); - private final SslContextFactory _sslCtxFactory =new SslContextFactory(); + private final SslContextFactory _sslCtxFactory = new SslContextFactory.Server(); protected volatile EndPoint _lastEndp; - private volatile boolean _testFill=true; + private volatile boolean _testFill = true; + private volatile boolean _onXWriteThenShutdown = false; + private volatile FutureCallback _writeCallback; protected ServerSocketChannel _connector; final AtomicInteger _dispatches = new AtomicInteger(); @@ -76,7 +79,6 @@ public class SslConnectionTest _dispatches.incrementAndGet(); super.execute(job); } - }; protected Scheduler _scheduler = new TimerScheduler(); protected SelectorManager _manager = new SelectorManager(_threadPool, _scheduler) @@ -94,39 +96,41 @@ public class SslConnectionTest return sslConnection; } - @Override protected EndPoint newEndPoint(SelectableChannel channel, ManagedSelector selector, SelectionKey selectionKey) { SocketChannelEndPoint endp = new TestEP(channel, selector, selectionKey, getScheduler()); endp.setIdleTimeout(TIMEOUT); - _lastEndp=endp; + _lastEndp = endp; return endp; } }; static final AtomicInteger __startBlocking = new AtomicInteger(); static final AtomicInteger __blockFor = new AtomicInteger(); + static final AtomicBoolean __onIncompleteFlush = new AtomicBoolean(); + private static class TestEP extends SocketChannelEndPoint { public TestEP(SelectableChannel channel, ManagedSelector selector, SelectionKey key, Scheduler scheduler) { - super((SocketChannel)channel,selector,key,scheduler); + super((SocketChannel)channel, selector, key, scheduler); } @Override protected void onIncompleteFlush() { - super.onIncompleteFlush(); + __onIncompleteFlush.set(true); + // super.onIncompleteFlush(); } - @Override public boolean flush(ByteBuffer... buffers) throws IOException { - if (__startBlocking.get()==0 || __startBlocking.decrementAndGet()==0) + __onIncompleteFlush.set(false); + if (__startBlocking.get() == 0 || __startBlocking.decrementAndGet() == 0) { - if (__blockFor.get()>0 && __blockFor.getAndDecrement()>0) + if (__blockFor.get() > 0 && __blockFor.getAndDecrement() > 0) { return false; } @@ -135,7 +139,6 @@ public class SslConnectionTest } } - @BeforeEach public void initSSL() throws Exception { @@ -150,9 +153,9 @@ public class SslConnectionTest public void startManager() throws Exception { - _testFill=true; - _writeCallback=null; - _lastEndp=null; + _testFill = true; + _writeCallback = null; + _lastEndp = null; _connector = ServerSocketChannel.open(); _connector.socket().bind(null); _threadPool.start(); @@ -184,7 +187,7 @@ public class SslConnectionTest public class TestConnection extends AbstractConnection { - ByteBuffer _in = BufferUtil.allocate(8*1024); + ByteBuffer _in = BufferUtil.allocate(8 * 1024); public TestConnection(EndPoint endp) { @@ -199,7 +202,7 @@ public class SslConnectionTest fillInterested(); else { - getExecutor().execute(() -> getEndPoint().write(_writeCallback,BufferUtil.toBuffer("Hello Client"))); + getExecutor().execute(() -> getEndPoint().write(_writeCallback, BufferUtil.toBuffer("Hello Client"))); } } @@ -215,40 +218,43 @@ public class SslConnectionTest EndPoint endp = getEndPoint(); try { - boolean progress=true; - while(progress) + boolean progress = true; + while (progress) { - progress=false; + progress = false; // Fill the input buffer with everything available - int filled=endp.fill(_in); - while (filled>0) + int filled = endp.fill(_in); + while (filled > 0) { - progress=true; - filled=endp.fill(_in); + progress = true; + filled = endp.fill(_in); } + boolean shutdown = _onXWriteThenShutdown && BufferUtil.toString(_in).contains("X"); + // Write everything - int l=_in.remaining(); - if (l>0) + int l = _in.remaining(); + if (l > 0) { - FutureCallback blockingWrite= new FutureCallback(); - endp.write(blockingWrite,_in); + FutureCallback blockingWrite = new FutureCallback(); + + endp.write(blockingWrite, _in); blockingWrite.get(); + if (shutdown) + endp.shutdownOutput(); } // are we done? - if (endp.isInputShutdown()) - { + if (endp.isInputShutdown() || shutdown) endp.shutdownOutput(); - } } } - catch(InterruptedException|EofException e) + catch (InterruptedException | EofException e) { Log.getRootLogger().ignore(e); } - catch(Exception e) + catch (Exception e) { Log.getRootLogger().warn(e); } @@ -278,7 +284,7 @@ public class SslConnectionTest { server.configureBlocking(false); _manager.accept(server); - + client.getOutputStream().write("Hello".getBytes(StandardCharsets.UTF_8)); byte[] buffer = new byte[1024]; int len = client.getInputStream().read(buffer); @@ -289,7 +295,9 @@ public class SslConnectionTest client.getOutputStream().write("World".getBytes(StandardCharsets.UTF_8)); len = 5; while (len > 0) + { len -= client.getInputStream().read(buffer); + } } } } @@ -347,7 +355,7 @@ public class SslConnectionTest client.startHandshake(); client.getOutputStream().write("World".getBytes(StandardCharsets.UTF_8)); - assertThrows(SSLException.class, ()-> client.getInputStream().read(buffer)); + assertThrows(SSLException.class, () -> client.getInputStream().read(buffer)); } } } @@ -391,7 +399,7 @@ public class SslConnectionTest client.startHandshake(); client.getOutputStream().write("World".getBytes(StandardCharsets.UTF_8)); - assertThrows(SSLException.class, ()-> client.getInputStream().read(buffer)); + assertThrows(SSLException.class, () -> client.getInputStream().read(buffer)); } } } @@ -399,7 +407,7 @@ public class SslConnectionTest @Test public void testWriteOnConnect() throws Exception { - _testFill=false; + _testFill = false; _writeCallback = new FutureCallback(); startSSL(); try (SSLSocket client = newClient()) @@ -427,7 +435,7 @@ public class SslConnectionTest public void testBlockedWrite() throws Exception { startSSL(); - try (Socket client = newClient()) + try (SSLSocket client = newClient()) { client.setSoTimeout(5000); try (SocketChannel server = _connector.accept()) @@ -435,21 +443,79 @@ public class SslConnectionTest server.configureBlocking(false); _manager.accept(server); - __startBlocking.set(5); - __blockFor.set(3); - client.getOutputStream().write("Hello".getBytes(StandardCharsets.UTF_8)); byte[] buffer = new byte[1024]; int len = client.getInputStream().read(buffer); - assertEquals(5, len); assertEquals("Hello", new String(buffer, 0, len, StandardCharsets.UTF_8)); + __startBlocking.set(0); + __blockFor.set(2); _dispatches.set(0); client.getOutputStream().write("World".getBytes(StandardCharsets.UTF_8)); - len = 5; - while (len > 0) - len -= client.getInputStream().read(buffer); - assertEquals(0, len); + + try + { + client.setSoTimeout(500); + client.getInputStream().read(buffer); + throw new IllegalStateException(); + } + catch (SocketTimeoutException e) + { + // no op + } + + assertTrue(__onIncompleteFlush.get()); + ((TestEP)_lastEndp).getWriteFlusher().completeWrite(); + + len = client.getInputStream().read(buffer); + assertEquals("World", new String(buffer, 0, len, StandardCharsets.UTF_8)); + } + } + } + + @Test + public void testBlockedClose() throws Exception + { + startSSL(); + try (SSLSocket client = newClient()) + { + client.setSoTimeout(5000); + try (SocketChannel server = _connector.accept()) + { + server.configureBlocking(false); + _manager.accept(server); + + //__startBlocking.set(5); + //__blockFor.set(3); + + client.getOutputStream().write("Short".getBytes(StandardCharsets.UTF_8)); + byte[] buffer = new byte[1024]; + int len = client.getInputStream().read(buffer); + assertEquals("Short", new String(buffer, 0, len, StandardCharsets.UTF_8)); + + _onXWriteThenShutdown = true; + __startBlocking.set(2); // block on the close handshake flush + __blockFor.set(Integer.MAX_VALUE); // > retry loops in SslConnection + 1 + client.getOutputStream().write("This is a much longer example with X".getBytes(StandardCharsets.UTF_8)); + len = client.getInputStream().read(buffer); + assertEquals("This is a much longer example with X", new String(buffer, 0, len, StandardCharsets.UTF_8)); + + try + { + client.setSoTimeout(500); + client.getInputStream().read(buffer); + throw new IllegalStateException(); + } + catch (SocketTimeoutException e) + { + // no op + } + + __blockFor.set(0); + assertTrue(__onIncompleteFlush.get()); + ((TestEP)_lastEndp).getWriteFlusher().completeWrite(); + len = client.getInputStream().read(buffer); + assertThat(len, is(len)); } } } @@ -479,7 +545,6 @@ public class SslConnectionTest String line = in.readLine(); if (line == null) break; - // System.err.println(line); count.countDown(); } } @@ -492,7 +557,6 @@ public class SslConnectionTest for (int i = 0; i < LINES; i++) { client.getOutputStream().write(("HelloWorld " + i + "\n").getBytes(StandardCharsets.UTF_8)); - // System.err.println("wrote"); if (i % 1000 == 0) { client.getOutputStream().flush(); diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/SslEngineBehaviorTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/SslEngineBehaviorTest.java index ea6af2c6028..d4b475b2969 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/SslEngineBehaviorTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/SslEngineBehaviorTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,13 +18,8 @@ package org.eclipse.jetty.io; -import static org.hamcrest.Matchers.greaterThan; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.hamcrest.MatcherAssert.assertThat; - import java.io.File; import java.nio.ByteBuffer; - import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngineResult; @@ -32,12 +27,15 @@ import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.junit.jupiter.api.AfterAll; - import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledOnJre; import org.junit.jupiter.api.condition.JRE; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThan; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class SslEngineBehaviorTest { private static SslContextFactory sslCtxFactory; @@ -45,12 +43,11 @@ public class SslEngineBehaviorTest @BeforeAll public static void startSsl() throws Exception { - sslCtxFactory = new SslContextFactory(); + sslCtxFactory = new SslContextFactory.Server(); File keystore = MavenTestingUtils.getTestResourceFile("keystore"); sslCtxFactory.setKeyStorePath(keystore.getAbsolutePath()); sslCtxFactory.setKeyStorePassword("storepwd"); sslCtxFactory.setKeyManagerPassword("keypwd"); - sslCtxFactory.setEndpointIdentificationAlgorithm(""); sslCtxFactory.start(); } @@ -78,68 +75,68 @@ public class SslEngineBehaviorTest // start the client client.setUseClientMode(true); client.beginHandshake(); - assertEquals(SSLEngineResult.HandshakeStatus.NEED_WRAP,client.getHandshakeStatus()); + assertEquals(SSLEngineResult.HandshakeStatus.NEED_WRAP, client.getHandshakeStatus()); // what if we try an unwrap? netS2C.flip(); - result=client.unwrap(netS2C,clientIn); + result = client.unwrap(netS2C, clientIn); // unwrap is a noop - assertEquals(SSLEngineResult.Status.OK,result.getStatus()); - assertEquals(0,result.bytesConsumed()); - assertEquals(0,result.bytesProduced()); - assertEquals(SSLEngineResult.HandshakeStatus.NEED_WRAP,result.getHandshakeStatus()); + assertEquals(SSLEngineResult.Status.OK, result.getStatus()); + assertEquals(0, result.bytesConsumed()); + assertEquals(0, result.bytesProduced()); + assertEquals(SSLEngineResult.HandshakeStatus.NEED_WRAP, result.getHandshakeStatus()); netS2C.clear(); // do the needed WRAP of empty buffer - result=client.wrap(BufferUtil.EMPTY_BUFFER,netC2S); + result = client.wrap(BufferUtil.EMPTY_BUFFER, netC2S); // unwrap is a noop - assertEquals(SSLEngineResult.Status.OK,result.getStatus()); - assertEquals(0,result.bytesConsumed()); - assertThat(result.bytesProduced(),greaterThan(0)); - assertEquals(SSLEngineResult.HandshakeStatus.NEED_UNWRAP,result.getHandshakeStatus()); + assertEquals(SSLEngineResult.Status.OK, result.getStatus()); + assertEquals(0, result.bytesConsumed()); + assertThat(result.bytesProduced(), greaterThan(0)); + assertEquals(SSLEngineResult.HandshakeStatus.NEED_UNWRAP, result.getHandshakeStatus()); netC2S.flip(); - assertEquals(netC2S.remaining(),result.bytesProduced()); + assertEquals(netC2S.remaining(), result.bytesProduced()); // start the server server.setUseClientMode(false); server.beginHandshake(); - assertEquals(SSLEngineResult.HandshakeStatus.NEED_UNWRAP,server.getHandshakeStatus()); + assertEquals(SSLEngineResult.HandshakeStatus.NEED_UNWRAP, server.getHandshakeStatus()); // what if we try a needless wrap? serverOut.put(BufferUtil.toBuffer("Hello World")); serverOut.flip(); - result=server.wrap(serverOut,netS2C); + result = server.wrap(serverOut, netS2C); // wrap is a noop - assertEquals(SSLEngineResult.Status.OK,result.getStatus()); - assertEquals(0,result.bytesConsumed()); - assertEquals(0,result.bytesProduced()); - assertEquals(SSLEngineResult.HandshakeStatus.NEED_UNWRAP,result.getHandshakeStatus()); + assertEquals(SSLEngineResult.Status.OK, result.getStatus()); + assertEquals(0, result.bytesConsumed()); + assertEquals(0, result.bytesProduced()); + assertEquals(SSLEngineResult.HandshakeStatus.NEED_UNWRAP, result.getHandshakeStatus()); // Do the needed unwrap, to an empty buffer - result=server.unwrap(netC2S,BufferUtil.EMPTY_BUFFER); - assertEquals(SSLEngineResult.Status.BUFFER_OVERFLOW,result.getStatus()); - assertEquals(0,result.bytesConsumed()); - assertEquals(0,result.bytesProduced()); - assertEquals(SSLEngineResult.HandshakeStatus.NEED_UNWRAP,result.getHandshakeStatus()); + result = server.unwrap(netC2S, BufferUtil.EMPTY_BUFFER); + assertEquals(SSLEngineResult.Status.BUFFER_OVERFLOW, result.getStatus()); + assertEquals(0, result.bytesConsumed()); + assertEquals(0, result.bytesProduced()); + assertEquals(SSLEngineResult.HandshakeStatus.NEED_UNWRAP, result.getHandshakeStatus()); // Do the needed unwrap, to a full buffer serverIn.position(serverIn.limit()); - result=server.unwrap(netC2S,serverIn); - assertEquals(SSLEngineResult.Status.BUFFER_OVERFLOW,result.getStatus()); - assertEquals(0,result.bytesConsumed()); - assertEquals(0,result.bytesProduced()); - assertEquals(SSLEngineResult.HandshakeStatus.NEED_UNWRAP,result.getHandshakeStatus()); + result = server.unwrap(netC2S, serverIn); + assertEquals(SSLEngineResult.Status.BUFFER_OVERFLOW, result.getStatus()); + assertEquals(0, result.bytesConsumed()); + assertEquals(0, result.bytesProduced()); + assertEquals(SSLEngineResult.HandshakeStatus.NEED_UNWRAP, result.getHandshakeStatus()); // Do the needed unwrap, to an empty buffer serverIn.clear(); - result=server.unwrap(netC2S,serverIn); - assertEquals(SSLEngineResult.Status.OK,result.getStatus()); - assertThat(result.bytesConsumed(),greaterThan(0)); - assertEquals(0,result.bytesProduced()); - assertEquals(SSLEngineResult.HandshakeStatus.NEED_TASK,result.getHandshakeStatus()); + result = server.unwrap(netC2S, serverIn); + assertEquals(SSLEngineResult.Status.OK, result.getStatus()); + assertThat(result.bytesConsumed(), greaterThan(0)); + assertEquals(0, result.bytesProduced()); + assertEquals(SSLEngineResult.HandshakeStatus.NEED_TASK, result.getHandshakeStatus()); server.getDelegatedTask().run(); - assertEquals(SSLEngineResult.HandshakeStatus.NEED_WRAP,server.getHandshakeStatus()); + assertEquals(SSLEngineResult.HandshakeStatus.NEED_WRAP, server.getHandshakeStatus()); } } diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/WriteFlusherTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/WriteFlusherTest.java index 6b455c40ead..7a062d9b72a 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/WriteFlusherTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/WriteFlusherTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,14 +18,6 @@ package org.eclipse.jetty.io; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.instanceOf; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.IOException; import java.io.InterruptedIOException; import java.nio.ByteBuffer; @@ -43,10 +35,18 @@ import java.util.concurrent.atomic.AtomicBoolean; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.FutureCallback; +import org.eclipse.jetty.util.log.StacklessLogging; import org.hamcrest.Matchers; - import org.junit.jupiter.api.Test; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.instanceOf; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class WriteFlusherTest { @Test @@ -110,7 +110,8 @@ public class WriteFlusherTest assertTrue(callback.isDone()); assertFalse(incompleteFlush.get()); - ExecutionException e = assertThrows(ExecutionException.class, ()->{ + ExecutionException e = assertThrows(ExecutionException.class, () -> + { callback.get(); }); assertThat(e.getCause(), instanceOf(IOException.class)); @@ -143,7 +144,8 @@ public class WriteFlusherTest assertTrue(incompleteFlush.get()); - assertThrows(TimeoutException.class, ()->{ + assertThrows(TimeoutException.class, () -> + { callback.get(100, TimeUnit.MILLISECONDS); }); @@ -159,6 +161,43 @@ public class WriteFlusherTest assertTrue(flusher.isIdle()); } + @Test + public void testCallbackThrows() throws Exception + { + ByteArrayEndPoint endPoint = new ByteArrayEndPoint(new byte[0], 100); + + AtomicBoolean incompleteFlush = new AtomicBoolean(false); + WriteFlusher flusher = new WriteFlusher(endPoint) + { + @Override + protected void onIncompleteFlush() + { + incompleteFlush.set(true); + } + }; + + FutureCallback callback = new FutureCallback() + { + @Override + public void succeeded() + { + super.succeeded(); + throw new IllegalStateException(); + } + }; + + try (StacklessLogging stacklessLogging = new StacklessLogging(WriteFlusher.class)) + { + flusher.write(callback, BufferUtil.toBuffer("How now brown cow!")); + callback.get(100, TimeUnit.MILLISECONDS); + } + + assertEquals("How now brown cow!", endPoint.takeOutputString()); + assertTrue(callback.isDone()); + assertFalse(incompleteFlush.get()); + assertTrue(flusher.isIdle()); + } + @Test public void testCloseWhileBlocking() throws Exception { @@ -191,7 +230,7 @@ public class WriteFlusherTest assertTrue(callback.isDone()); assertFalse(incompleteFlush.get()); - ExecutionException e = assertThrows(ExecutionException.class, ()-> callback.get()); + ExecutionException e = assertThrows(ExecutionException.class, () -> callback.get()); assertThat(e.getCause(), instanceOf(IOException.class)); assertThat(e.getCause().getMessage(), containsString("CLOSED")); @@ -232,7 +271,7 @@ public class WriteFlusherTest assertTrue(callback.isDone()); assertFalse(incompleteFlush.get()); - ExecutionException e = assertThrows(ExecutionException.class, ()-> callback.get()); + ExecutionException e = assertThrows(ExecutionException.class, () -> callback.get()); assertThat(e.getCause(), instanceOf(IOException.class)); assertThat(e.getCause().getMessage(), containsString(reason)); @@ -311,7 +350,6 @@ public class WriteFlusherTest } }; - flusher.write(Callback.NOOP, buffer1, buffer2); assertTrue(incompleteFlush.get()); assertFalse(buffer1.hasRemaining()); @@ -362,7 +400,8 @@ public class WriteFlusherTest new Thread(() -> flusher.write(Callback.NOOP, BufferUtil.toBuffer("foo"))).start(); assertTrue(flushLatch.await(1, TimeUnit.SECONDS)); - assertThrows(WritePendingException.class, ()->{ + assertThrows(WritePendingException.class, () -> + { // The second write throws WritePendingException. flusher.write(Callback.NOOP, BufferUtil.toBuffer("bar")); }); @@ -371,18 +410,19 @@ public class WriteFlusherTest @Test public void testConcurrentWriteAndOnFail() throws Exception { - assertThrows( ExecutionException.class , () -> { - ByteArrayEndPoint endPoint = new ByteArrayEndPoint( new byte[0], 16 ); + assertThrows(ExecutionException.class, () -> + { + ByteArrayEndPoint endPoint = new ByteArrayEndPoint(new byte[0], 16); - WriteFlusher flusher = new WriteFlusher( endPoint ) + WriteFlusher flusher = new WriteFlusher(endPoint) { @Override - protected ByteBuffer[] flush( ByteBuffer[] buffers ) + protected ByteBuffer[] flush(ByteBuffer[] buffers) throws IOException { - ByteBuffer[] result = super.flush( buffers ); - boolean notified = onFail( new Throwable() ); - assertTrue( notified ); + ByteBuffer[] result = super.flush(buffers); + boolean notified = onFail(new Throwable()); + assertTrue(notified); return result; } @@ -393,11 +433,11 @@ public class WriteFlusherTest }; FutureCallback callback = new FutureCallback(); - flusher.write( callback, BufferUtil.toBuffer( "foo" ) ); + flusher.write(callback, BufferUtil.toBuffer("foo")); - assertTrue( flusher.isFailed() ); + assertTrue(flusher.isFailed()); - callback.get( 1, TimeUnit.SECONDS ); + callback.get(1, TimeUnit.SECONDS); }); } diff --git a/jetty-jaas/pom.xml b/jetty-jaas/pom.xml index 3db46da6f25..c538ee1d4ae 100644 --- a/jetty-jaas/pom.xml +++ b/jetty-jaas/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 jetty-jaas @@ -18,8 +18,8 @@ - org.apache.maven.plugins - maven-source-plugin + org.apache.maven.plugins + maven-source-plugin org.codehaus.mojo diff --git a/jetty-jaas/src/main/config/etc/jetty-jaas.xml b/jetty-jaas/src/main/config/etc/jetty-jaas.xml index 4e42594db61..f2f8a64aba1 100644 --- a/jetty-jaas/src/main/config/etc/jetty-jaas.xml +++ b/jetty-jaas/src/main/config/etc/jetty-jaas.xml @@ -1,5 +1,4 @@ - - + diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASGroup.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASGroup.java deleted file mode 100644 index e83dac76ea5..00000000000 --- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASGroup.java +++ /dev/null @@ -1,117 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.jaas; - -import java.security.Principal; -import java.security.acl.Group; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.Iterator; - -public class JAASGroup implements Group -{ - public static final String ROLES = "__roles__"; - - private String _name = null; - private HashSet _members = null; - - public JAASGroup(String n) - { - this._name = n; - this._members = new HashSet(); - } - - /* ------------------------------------------------------------ */ - @Override - public synchronized boolean addMember(Principal principal) - { - return _members.add(principal); - } - - @Override - public synchronized boolean removeMember(Principal principal) - { - return _members.remove(principal); - } - - @Override - public boolean isMember(Principal principal) - { - return _members.contains(principal); - } - - @Override - public Enumeration members() - { - - class MembersEnumeration implements Enumeration - { - private Iterator itor; - - public MembersEnumeration (Iterator itor) - { - this.itor = itor; - } - - @Override - public boolean hasMoreElements () - { - return this.itor.hasNext(); - } - - - @Override - public Principal nextElement () - { - return this.itor.next(); - } - - } - - return new MembersEnumeration (_members.iterator()); - } - - @Override - public int hashCode() - { - return getName().hashCode(); - } - - @Override - public boolean equals(Object object) - { - if (! (object instanceof JAASGroup)) - return false; - - return ((JAASGroup)object).getName().equals(getName()); - } - - @Override - public String toString() - { - return getName(); - } - - @Override - public String getName() - { - - return _name; - } -} diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASLoginService.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASLoginService.java index b983756fca1..60676da4f9b 100644 --- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASLoginService.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASLoginService.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -24,7 +24,6 @@ import java.util.Arrays; import java.util.Collection; import java.util.LinkedHashSet; import java.util.Set; - import javax.security.auth.Subject; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; @@ -37,10 +36,10 @@ import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; import javax.servlet.ServletRequest; -import org.eclipse.jetty.jaas.callback.ServletRequestCallback; import org.eclipse.jetty.jaas.callback.DefaultCallbackHandler; import org.eclipse.jetty.jaas.callback.ObjectCallback; import org.eclipse.jetty.jaas.callback.RequestParameterCallback; +import org.eclipse.jetty.jaas.callback.ServletRequestCallback; import org.eclipse.jetty.security.DefaultIdentityService; import org.eclipse.jetty.security.IdentityService; import org.eclipse.jetty.security.LoginService; @@ -52,14 +51,12 @@ import org.eclipse.jetty.util.component.AbstractLifeCycle; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; - -/** +/** * JAASLoginService * * * Implementation of jetty's LoginService that works with JAAS for * authorization and authentication. - * */ public class JAASLoginService extends AbstractLifeCycle implements LoginService { @@ -76,16 +73,11 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService protected IdentityService _identityService; protected Configuration _configuration; - - public JAASLoginService() { } - - /** - * * @param name the name of the realm */ public JAASLoginService(String name) @@ -95,8 +87,6 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService _loginModuleName = name; } - - /** * Get the name of the realm. * @@ -108,19 +98,16 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService return _realmName; } - - /** * Set the name of the realm * * @param name a String value */ - public void setName (String name) + public void setName(String name) { _realmName = name; } - /** * @return the configuration */ @@ -129,8 +116,6 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService return _configuration; } - - /** * @param configuration the configuration to set */ @@ -139,10 +124,9 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService _configuration = configuration; } - - - /** + /** * Get the identityService. + * * @return the identityService */ @Override @@ -151,9 +135,9 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService return _identityService; } - - /** + /** * Set the identityService. + * * @param identityService the identityService to set */ @Override @@ -162,55 +146,48 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService _identityService = identityService; } - /** * Set the name to use to index into the config * file of LoginModules. * * @param name a String value */ - public void setLoginModuleName (String name) + public void setLoginModuleName(String name) { _loginModuleName = name; } - - public void setCallbackHandlerClass (String classname) + public void setCallbackHandlerClass(String classname) { _callbackHandlerClass = classname; } - - public void setRoleClassNames (String[] classnames) + public void setRoleClassNames(String[] classnames) { if (classnames == null || classnames.length == 0) { _roleClassNames = DEFAULT_ROLE_CLASS_NAMES; return; } - + _roleClassNames = ArrayUtil.addToArray(classnames, DEFAULT_ROLE_CLASS_NAME, String.class); } - public String[] getRoleClassNames() { return _roleClassNames; } - - @Override protected void doStart() throws Exception { - if (_identityService==null) + if (_identityService == null) _identityService = new DefaultIdentityService(); super.doStart(); } - @Override - public UserIdentity login(final String username,final Object credentials, final ServletRequest request) + public UserIdentity login(final String username, final Object credentials, final ServletRequest request) { try { @@ -222,7 +199,7 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService @Override public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { - for (Callback callback: callbacks) + for (Callback callback : callbacks) { if (callback instanceof NameCallback) { @@ -239,7 +216,7 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService else if (callback instanceof RequestParameterCallback) { RequestParameterCallback rpc = (RequestParameterCallback)callback; - if (request!=null) + if (request != null) rpc.setParameterValues(Arrays.asList(request.getParameterValues(rpc.getParameterName()))); } else if (callback instanceof ServletRequestCallback) @@ -259,17 +236,17 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService if (DefaultCallbackHandler.class.isAssignableFrom(clazz)) { DefaultCallbackHandler dch = (DefaultCallbackHandler)callbackHandler; - if (request instanceof Request) + if (request instanceof Request) dch.setRequest((Request)request); dch.setCredential(credentials); dch.setUserName(username); } } - + //set up the login context Subject subject = new Subject(); - LoginContext loginContext = (_configuration==null?new LoginContext(_loginModuleName, subject, callbackHandler) - :new LoginContext(_loginModuleName, subject, callbackHandler, _configuration)); + LoginContext loginContext = (_configuration == null ? new LoginContext(_loginModuleName, subject, callbackHandler) + : new LoginContext(_loginModuleName, subject, callbackHandler, _configuration)); loginContext.login(); @@ -277,7 +254,7 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService JAASUserPrincipal userPrincipal = new JAASUserPrincipal(getUserName(callbackHandler), subject, loginContext); subject.getPrincipals().add(userPrincipal); - return _identityService.newUserIdentity(subject,userPrincipal,getGroups(subject)); + return _identityService.newUserIdentity(subject, userPrincipal, getGroups(subject)); } catch (FailedLoginException e) { @@ -291,7 +268,6 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService return null; } - @Override public boolean validate(UserIdentity user) { @@ -299,15 +275,13 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService return true; } - private String getUserName(CallbackHandler callbackHandler) throws IOException, UnsupportedCallbackException { NameCallback nameCallback = new NameCallback("foo"); - callbackHandler.handle(new Callback[] {nameCallback}); + callbackHandler.handle(new Callback[]{nameCallback}); return nameCallback.getName(); } - @Override public void logout(UserIdentity user) { @@ -323,31 +297,29 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService } } - /** * Get all of the groups for the user. - * + * * @param subject the Subject representing the user - * * @return all the names of groups that the user is in, or 0 length array if none */ - protected String[] getGroups (Subject subject) + protected String[] getGroups(Subject subject) { Collection groups = new LinkedHashSet<>(); Set principals = subject.getPrincipals(); for (Principal principal : principals) { Class c = principal.getClass(); - while (c!=null) + while (c != null) { if (roleClassNameMatches(c.getName())) { groups.add(principal.getName()); break; } - + boolean added = false; - for (Class ci:c.getInterfaces()) + for (Class ci : c.getInterfaces()) { if (roleClassNameMatches(ci.getName())) { @@ -356,7 +328,7 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService break; } } - + if (!added) { c = c.getSuperclass(); @@ -368,12 +340,11 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService return groups.toArray(new String[groups.size()]); } - - - private boolean roleClassNameMatches (String classname) + + private boolean roleClassNameMatches(String classname) { boolean result = false; - for (String roleClassName:getRoleClassNames()) + for (String roleClassName : getRoleClassNames()) { if (roleClassName.equals(classname)) { @@ -383,5 +354,4 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService } return result; } - } diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASPrincipal.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASPrincipal.java index 2cbe8b0165e..8fc5fdcc60f 100644 --- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASPrincipal.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASPrincipal.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -21,7 +21,7 @@ package org.eclipse.jetty.jaas; import java.io.Serializable; import java.security.Principal; -/** +/** * JAASPrincipal *

        * Impl class of Principal interface. @@ -29,37 +29,37 @@ import java.security.Principal; public class JAASPrincipal implements Principal, Serializable { private static final long serialVersionUID = -5538962177019315479L; - - private String _name = null; - + + private final String _name; + public JAASPrincipal(String userName) { this._name = userName; } @Override - public boolean equals (Object p) + public boolean equals(Object p) { - if (! (p instanceof JAASPrincipal)) + if (!(p instanceof JAASPrincipal)) return false; return getName().equals(((JAASPrincipal)p).getName()); } @Override - public int hashCode () + public int hashCode() { return getName().hashCode(); } @Override - public String getName () + public String getName() { return this._name; } @Override - public String toString () + public String toString() { return getName(); } diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASRole.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASRole.java index 312d4bff6ab..dddcf622ff2 100644 --- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASRole.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASRole.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -24,13 +24,13 @@ public class JAASRole extends JAASPrincipal public JAASRole(String name) { - super (name); + super(name); } @Override - public boolean equals (Object o) + public boolean equals(Object o) { - if (! (o instanceof JAASRole)) + if (!(o instanceof JAASRole)) return false; return getName().equals(((JAASRole)o).getName()); diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASUserPrincipal.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASUserPrincipal.java index 63616bc97db..7106edd0239 100644 --- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASUserPrincipal.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASUserPrincipal.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,15 +19,14 @@ package org.eclipse.jetty.jaas; import java.security.Principal; - import javax.security.auth.Subject; import javax.security.auth.login.LoginContext; -/** +/** * JAASUserPrincipal *

        * Implements the JAAS version of the - * org.eclipse.jetty.http.UserPrincipal interface. + * org.eclipse.jetty.http.UserPrincipal interface. */ public class JAASUserPrincipal implements Principal { @@ -35,7 +34,6 @@ public class JAASUserPrincipal implements Principal private final Subject _subject; private final LoginContext _loginContext; - /* ------------------------------------------------ */ public JAASUserPrincipal(String name, Subject subject, LoginContext loginContext) { this._name = name; @@ -43,26 +41,26 @@ public class JAASUserPrincipal implements Principal this._loginContext = loginContext; } - /* ------------------------------------------------ */ - /** Get the name identifying the user + /** + * Get the name identifying the user */ @Override - public String getName () + public String getName() { return _name; } - - /* ------------------------------------------------ */ - /** Provide access to the Subject + /** + * Provide access to the Subject + * * @return subject */ - public Subject getSubject () + public Subject getSubject() { return this._subject; } - LoginContext getLoginContext () + LoginContext getLoginContext() { return this._loginContext; } @@ -72,5 +70,4 @@ public class JAASUserPrincipal implements Principal { return getName(); } - } diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/StrictRoleCheckPolicy.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/StrictRoleCheckPolicy.java deleted file mode 100644 index 4684f282bc0..00000000000 --- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/StrictRoleCheckPolicy.java +++ /dev/null @@ -1,63 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// 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.jaas; - -import java.security.Principal; -import java.security.acl.Group; -import java.util.Enumeration; - - -/* ---------------------------------------------------- */ -/** StrictRoleCheckPolicy - *

        Enforces that if a runAsRole is present, then the - * role to check must be the same as that runAsRole and - * the set of static roles is ignored. - * - * - * - */ -public class StrictRoleCheckPolicy implements RoleCheckPolicy -{ - - @Override - public boolean checkRole (String roleName, Principal runAsRole, Group roles) - { - //check if this user has had any temporary role pushed onto - //them. If so, then only check if the user has that role. - if (runAsRole != null) - { - return (roleName.equals(runAsRole.getName())); - } - else - { - if (roles == null) - return false; - Enumeration rolesEnum = roles.members(); - boolean found = false; - while (rolesEnum.hasMoreElements() && !found) - { - Principal p = (Principal)rolesEnum.nextElement(); - found = roleName.equals(p.getName()); - } - return found; - } - - } - -} diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/AbstractCallbackHandler.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/AbstractCallbackHandler.java index 0880b52a0a6..108698b32df 100644 --- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/AbstractCallbackHandler.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/AbstractCallbackHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,43 +19,38 @@ package org.eclipse.jetty.jaas.callback; import java.io.IOException; - import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.UnsupportedCallbackException; - public abstract class AbstractCallbackHandler implements CallbackHandler { protected String _userName; protected Object _credential; - public void setUserName (String userName) + public void setUserName(String userName) { _userName = userName; } - public String getUserName () + public String getUserName() { return _userName; } - - public void setCredential (Object credential) + public void setCredential(Object credential) { _credential = credential; } - public Object getCredential () + public Object getCredential() { return _credential; } @Override - public void handle (Callback[] callbacks) + public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { } - - } diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/DefaultCallbackHandler.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/DefaultCallbackHandler.java index 62f9734346c..6dd3c85331e 100644 --- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/DefaultCallbackHandler.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/DefaultCallbackHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,7 +20,6 @@ package org.eclipse.jetty.jaas.callback; import java.io.IOException; import java.util.Arrays; - import javax.security.auth.callback.Callback; import javax.security.auth.callback.NameCallback; import javax.security.auth.callback.PasswordCallback; @@ -29,9 +28,9 @@ import javax.security.auth.callback.UnsupportedCallbackException; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.util.security.Password; -/** +/** * DefaultCallbackHandler - * + * * An implementation of the JAAS CallbackHandler. Users can provide * their own implementation instead and set the name of its class on the JAASLoginService. */ @@ -39,16 +38,16 @@ public class DefaultCallbackHandler extends AbstractCallbackHandler { private Request _request; - public void setRequest (Request request) + public void setRequest(Request request) { _request = request; } @Override - public void handle (Callback[] callbacks) + public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { - for (int i=0; i < callbacks.length; i++) + for (int i = 0; i < callbacks.length; i++) { if (callbacks[i] instanceof NameCallback) { @@ -61,13 +60,13 @@ public class DefaultCallbackHandler extends AbstractCallbackHandler else if (callbacks[i] instanceof PasswordCallback) { if (getCredential() instanceof Password) - ((PasswordCallback)callbacks[i]).setPassword (((Password)getCredential()).toString().toCharArray()); + ((PasswordCallback)callbacks[i]).setPassword(getCredential().toString().toCharArray()); else if (getCredential() instanceof String) { - ((PasswordCallback)callbacks[i]).setPassword (((String)getCredential()).toCharArray()); + ((PasswordCallback)callbacks[i]).setPassword(((String)getCredential()).toCharArray()); } else - throw new UnsupportedCallbackException (callbacks[i], "User supplied credentials cannot be converted to char[] for PasswordCallback: try using an ObjectCallback instead"); + throw new UnsupportedCallbackException(callbacks[i], "User supplied credentials cannot be converted to char[] for PasswordCallback: try using an ObjectCallback instead"); } else if (callbacks[i] instanceof RequestParameterCallback) { @@ -81,8 +80,6 @@ public class DefaultCallbackHandler extends AbstractCallbackHandler else throw new UnsupportedCallbackException(callbacks[i]); } - } - } diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/ObjectCallback.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/ObjectCallback.java index d79edce258a..80704993b1f 100644 --- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/ObjectCallback.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/ObjectCallback.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,7 +20,7 @@ package org.eclipse.jetty.jaas.callback; import javax.security.auth.callback.Callback; -/** +/** * ObjectCallback *

        * Can be used as a LoginModule Callback to @@ -31,18 +31,18 @@ import javax.security.auth.callback.Callback; public class ObjectCallback implements Callback { protected Object _object; - + public void setObject(Object o) { _object = o; } - public Object getObject () + public Object getObject() { return _object; } - public void clearObject () + public void clearObject() { _object = null; } diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/RequestParameterCallback.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/RequestParameterCallback.java index 37f50e3d097..ab2afd77e80 100644 --- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/RequestParameterCallback.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/RequestParameterCallback.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,7 +19,6 @@ package org.eclipse.jetty.jaas.callback; import java.util.List; - import javax.security.auth.callback.Callback; /** @@ -34,21 +33,22 @@ public class RequestParameterCallback implements Callback private String _paramName; private List _paramValues; - public void setParameterName (String name) + public void setParameterName(String name) { _paramName = name; } - public String getParameterName () + + public String getParameterName() { return _paramName; } - public void setParameterValues (List values) + public void setParameterValues(List values) { _paramValues = values; } - public List getParameterValues () + public List getParameterValues() { return _paramValues; } diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/ServletRequestCallback.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/ServletRequestCallback.java index 991c774e163..bfec2f2126c 100644 --- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/ServletRequestCallback.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/ServletRequestCallback.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,13 +16,11 @@ // ======================================================================== // - package org.eclipse.jetty.jaas.callback; import javax.security.auth.callback.Callback; import javax.servlet.ServletRequest; - /** * ServletRequestCallback * @@ -31,13 +29,13 @@ import javax.servlet.ServletRequest; public class ServletRequestCallback implements Callback { protected ServletRequest _request; - - public void setRequest (ServletRequest request) + + public void setRequest(ServletRequest request) { _request = request; } - - public ServletRequest getRequest () + + public ServletRequest getRequest() { return _request; } diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/package-info.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/package-info.java index 96564fa58aa..824fdbafb48 100644 --- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/package-info.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/package-info.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/package-info.java index 093e3ee87b4..79af1aad7e6 100644 --- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/package-info.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/AbstractDatabaseLoginModule.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/AbstractDatabaseLoginModule.java index 1c11e4beaa3..ba6cd500b1c 100644 --- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/AbstractDatabaseLoginModule.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/AbstractDatabaseLoginModule.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -24,7 +24,6 @@ import java.sql.ResultSet; import java.util.ArrayList; import java.util.List; import java.util.Map; - import javax.security.auth.Subject; import javax.security.auth.callback.CallbackHandler; @@ -38,7 +37,6 @@ import org.eclipse.jetty.util.security.Credential; * Abstract base class for LoginModules that interact with a * database to retrieve authentication and authorization information. * Used by the JDBCLoginModule and DataSourceLoginModule. - * */ public abstract class AbstractDatabaseLoginModule extends AbstractLoginModule { @@ -57,35 +55,31 @@ public abstract class AbstractDatabaseLoginModule extends AbstractLoginModule * @return a java.sql.Connection from the database * @throws Exception if unable to get the connection */ - public abstract Connection getConnection () throws Exception; - - + public abstract Connection getConnection() throws Exception; + public class JDBCUserInfo extends UserInfo { - public JDBCUserInfo (String userName, Credential credential) + public JDBCUserInfo(String userName, Credential credential) { super(userName, credential); } - - - + @Override - public List doFetchRoles () - throws Exception + public List doFetchRoles() + throws Exception { - return getRoles(getUserName()); + return getRoles(getUserName()); } } - - - /* ------------------------------------------------ */ - /** Load info from database + /** + * Load info from database + * * @param userName user info to load - * @exception Exception if unable to get the user info + * @throws Exception if unable to get the user info */ @Override - public UserInfo getUserInfo (String userName) + public UserInfo getUserInfo(String userName) throws Exception { try (Connection connection = getConnection()) @@ -93,9 +87,9 @@ public abstract class AbstractDatabaseLoginModule extends AbstractLoginModule //query for credential String dbCredential = null; - try (PreparedStatement statement = connection.prepareStatement (userQuery)) + try (PreparedStatement statement = connection.prepareStatement(userQuery)) { - statement.setString (1, userName); + statement.setString(1, userName); try (ResultSet results = statement.executeQuery()) { if (results.next()) @@ -105,53 +99,46 @@ public abstract class AbstractDatabaseLoginModule extends AbstractLoginModule } } - if (dbCredential==null) + if (dbCredential == null) { return null; } - - - return new JDBCUserInfo (userName, Credential.getCredential(dbCredential)); + return new JDBCUserInfo(userName, Credential.getCredential(dbCredential)); } } - - - public List getRoles (String userName) - throws Exception + + public List getRoles(String userName) + throws Exception { List roles = new ArrayList(); - + try (Connection connection = getConnection()) { //query for role names - try (PreparedStatement statement = connection.prepareStatement (rolesQuery)) + try (PreparedStatement statement = connection.prepareStatement(rolesQuery)) { - statement.setString (1, userName); + statement.setString(1, userName); try (ResultSet results = statement.executeQuery()) { while (results.next()) { - String roleName = results.getString (1); - roles.add (roleName); + String roleName = results.getString(1); + roles.add(roleName); } } } - } return roles; } - - - @Override public void initialize(Subject subject, - CallbackHandler callbackHandler, - Map sharedState, - Map options) + CallbackHandler callbackHandler, + Map sharedState, + Map options) { super.initialize(subject, callbackHandler, sharedState, options); @@ -160,17 +147,18 @@ public abstract class AbstractDatabaseLoginModule extends AbstractLoginModule dbUserTableUserField = (String)options.get("userField"); dbUserTableCredentialField = (String)options.get("credentialField"); - userQuery = "select "+dbUserTableCredentialField+" from "+dbUserTable+" where "+dbUserTableUserField+"=?"; - + userQuery = "select " + dbUserTableCredentialField + " from " + dbUserTable + " where " + dbUserTableUserField + "=?"; //get the user roles query out of the options dbUserRoleTable = (String)options.get("userRoleTable"); dbUserRoleTableUserField = (String)options.get("userRoleUserField"); dbUserRoleTableRoleField = (String)options.get("userRoleRoleField"); - rolesQuery = "select "+dbUserRoleTableRoleField+" from "+dbUserRoleTable+" where "+dbUserRoleTableUserField+"=?"; + rolesQuery = "select " + dbUserRoleTableRoleField + " from " + dbUserRoleTable + " where " + dbUserRoleTableUserField + "=?"; - if(LOG.isDebugEnabled())LOG.debug("userQuery = "+userQuery); - if(LOG.isDebugEnabled())LOG.debug("rolesQuery = "+rolesQuery); + if (LOG.isDebugEnabled()) + LOG.debug("userQuery = " + userQuery); + if (LOG.isDebugEnabled()) + LOG.debug("rolesQuery = " + rolesQuery); } } diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/AbstractLoginModule.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/AbstractLoginModule.java index 12ff84162d7..e59da6d286f 100644 --- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/AbstractLoginModule.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/AbstractLoginModule.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -24,7 +24,6 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; - import javax.security.auth.Subject; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; @@ -66,13 +65,13 @@ public abstract class AbstractLoginModule implements LoginModule private Principal principal; private List roles; - public JAASUserInfo (UserInfo u) + public JAASUserInfo(UserInfo u) { this.user = u; this.principal = new JAASPrincipal(u.getUserName()); } - public String getUserName () + public String getUserName() { return this.user.getUserName(); } @@ -82,30 +81,31 @@ public abstract class AbstractLoginModule implements LoginModule return this.principal; } - - public void setJAASInfo (Subject subject) + public void setJAASInfo(Subject subject) { subject.getPrincipals().add(this.principal); - if (this.user.getCredential() != null) { + if (this.user.getCredential() != null) + { subject.getPrivateCredentials().add(this.user.getCredential()); } subject.getPrincipals().addAll(roles); } - public void unsetJAASInfo (Subject subject) + public void unsetJAASInfo(Subject subject) { subject.getPrincipals().remove(this.principal); - if (this.user.getCredential() != null) { + if (this.user.getCredential() != null) + { subject.getPrivateCredentials().remove(this.user.getCredential()); } subject.getPrincipals().removeAll(this.roles); } - public boolean checkCredential (Object suppliedCredential) + public boolean checkCredential(Object suppliedCredential) { return this.user.checkCredential(suppliedCredential); } - + public void fetchRoles() throws Exception { this.user.fetchRoles(); @@ -114,23 +114,21 @@ public abstract class AbstractLoginModule implements LoginModule { Iterator itor = this.user.getRoleNames().iterator(); while (itor.hasNext()) - this.roles.add(new JAASRole((String)itor.next())); + { + this.roles.add(new JAASRole(itor.next())); + } } } } - - - public abstract UserInfo getUserInfo (String username) throws Exception; - - - - public Subject getSubject () + public abstract UserInfo getUserInfo(String username) throws Exception; + + public Subject getSubject() { return this.subject; } - public void setSubject (Subject s) + public void setSubject(Subject s) { this.subject = s; } @@ -140,7 +138,7 @@ public abstract class AbstractLoginModule implements LoginModule return this.currentUser; } - public void setCurrentUser (JAASUserInfo u) + public void setCurrentUser(JAASUserInfo u) { this.currentUser = u; } @@ -160,23 +158,24 @@ public abstract class AbstractLoginModule implements LoginModule return this.authState; } - public boolean isCommitted () + public boolean isCommitted() { return this.commitState; } - public void setAuthenticated (boolean authState) + public void setAuthenticated(boolean authState) { this.authState = authState; } - public void setCommitted (boolean commitState) + public void setCommitted(boolean commitState) { this.commitState = commitState; } + /** - * @see javax.security.auth.spi.LoginModule#abort() * @throws LoginException if unable to abort + * @see javax.security.auth.spi.LoginModule#abort() */ @Override public boolean abort() throws LoginException @@ -186,9 +185,9 @@ public abstract class AbstractLoginModule implements LoginModule } /** - * @see javax.security.auth.spi.LoginModule#commit() * @return true if committed, false if not (likely not authenticated) * @throws LoginException if unable to commit + * @see javax.security.auth.spi.LoginModule#commit() */ @Override public boolean commit() throws LoginException @@ -205,8 +204,7 @@ public abstract class AbstractLoginModule implements LoginModule return true; } - - public Callback[] configureCallbacks () + public Callback[] configureCallbacks() { Callback[] callbacks = new Callback[3]; callbacks[0] = new NameCallback("Enter user name"); @@ -214,31 +212,27 @@ public abstract class AbstractLoginModule implements LoginModule callbacks[2] = new PasswordCallback("Enter password", false); //only used if framework does not support the ObjectCallback return callbacks; } - - - public boolean isIgnored () + + public boolean isIgnored() { return false; } - - - /** - * @see javax.security.auth.spi.LoginModule#login() * @return true if is authenticated, false otherwise * @throws LoginException if unable to login + * @see javax.security.auth.spi.LoginModule#login() */ @Override public boolean login() throws LoginException { try - { + { if (isIgnored()) return false; - + if (callbackHandler == null) - throw new LoginException ("No callback handler"); + throw new LoginException("No callback handler"); Callback[] callbacks = configureCallbacks(); callbackHandler.handle(callbacks); @@ -266,7 +260,7 @@ public abstract class AbstractLoginModule implements LoginModule currentUser = new JAASUserInfo(userInfo); setAuthenticated(currentUser.checkCredential(webCredential)); - + if (isAuthenticated()) { currentUser.fetchRoles(); @@ -277,24 +271,24 @@ public abstract class AbstractLoginModule implements LoginModule } catch (IOException e) { - throw new LoginException (e.toString()); + throw new LoginException(e.toString()); } catch (UnsupportedCallbackException e) { - throw new LoginException (e.toString()); + throw new LoginException(e.toString()); } catch (Exception e) { if (e instanceof LoginException) throw (LoginException)e; - throw new LoginException (e.toString()); + throw new LoginException(e.toString()); } } /** - * @see javax.security.auth.spi.LoginModule#logout() * @return true always * @throws LoginException if unable to logout + * @see javax.security.auth.spi.LoginModule#logout() */ @Override public boolean logout() throws LoginException @@ -305,18 +299,17 @@ public abstract class AbstractLoginModule implements LoginModule } /** - * @see javax.security.auth.spi.LoginModule#initialize(javax.security.auth.Subject, javax.security.auth.callback.CallbackHandler, java.util.Map, java.util.Map) * @param subject the subject * @param callbackHandler the callback handler * @param sharedState the shared state map * @param options the option map + * @see javax.security.auth.spi.LoginModule#initialize(javax.security.auth.Subject, javax.security.auth.callback.CallbackHandler, java.util.Map, java.util.Map) */ @Override public void initialize(Subject subject, CallbackHandler callbackHandler, - Map sharedState, Map options) + Map sharedState, Map options) { this.callbackHandler = callbackHandler; this.subject = subject; } - } diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/DataSourceLoginModule.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/DataSourceLoginModule.java index 850f3451a2e..a990178f22e 100644 --- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/DataSourceLoginModule.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/DataSourceLoginModule.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,7 +20,6 @@ package org.eclipse.jetty.jaas.spi; import java.sql.Connection; import java.util.Map; - import javax.naming.InitialContext; import javax.naming.NamingException; import javax.security.auth.Subject; @@ -37,16 +36,14 @@ import javax.sql.DataSource; */ public class DataSourceLoginModule extends AbstractDatabaseLoginModule { - private String dbJNDIName; private DataSource dataSource; - /* ------------------------------------------------ */ - /** + /** * Init LoginModule. *

        * Called once by JAAS after new instance created. - * + * * @param subject the subject * @param callbackHandler the callback handler * @param sharedState the shared state map @@ -55,8 +52,8 @@ public class DataSourceLoginModule extends AbstractDatabaseLoginModule @Override public void initialize(Subject subject, CallbackHandler callbackHandler, - Map sharedState, - Map options) + Map sharedState, + Map options) { try { @@ -66,23 +63,24 @@ public class DataSourceLoginModule extends AbstractDatabaseLoginModule dbJNDIName = (String)options.get("dbJNDIName"); InitialContext ic = new InitialContext(); - dataSource = (DataSource)ic.lookup("java:comp/env/"+dbJNDIName); + dataSource = (DataSource)ic.lookup("java:comp/env/" + dbJNDIName); } catch (NamingException e) { - throw new IllegalStateException (e.toString()); + throw new IllegalStateException(e.toString()); } } /** * Get a connection from the DataSource - * @see AbstractDatabaseLoginModule#getConnection() + * * @return the connection for the datasource * @throws Exception if unable to get the connection + * @see AbstractDatabaseLoginModule#getConnection() */ @Override - public Connection getConnection () - throws Exception + public Connection getConnection() + throws Exception { return dataSource.getConnection(); } diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/JDBCLoginModule.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/JDBCLoginModule.java index 03552ec92fd..571e3cad6c2 100644 --- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/JDBCLoginModule.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/JDBCLoginModule.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -21,7 +21,6 @@ package org.eclipse.jetty.jaas.spi; import java.sql.Connection; import java.sql.DriverManager; import java.util.Map; - import javax.security.auth.Subject; import javax.security.auth.callback.CallbackHandler; @@ -29,7 +28,7 @@ import org.eclipse.jetty.util.Loader; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -/** +/** * JDBCLoginModule *

        * JAAS LoginModule to retrieve user information from @@ -49,34 +48,31 @@ public class JDBCLoginModule extends AbstractDatabaseLoginModule /** * Get a connection from the DriverManager - * @see AbstractDatabaseLoginModule#getConnection() + * * @return the connection for this datasource * @throws Exception if unable to get the connection + * @see AbstractDatabaseLoginModule#getConnection() */ @Override - public Connection getConnection () - throws Exception + public Connection getConnection() + throws Exception { - if (!((dbDriver != null) - && - (dbUrl != null))) - throw new IllegalStateException ("Database connection information not configured"); + if (!((dbDriver != null) && (dbUrl != null))) + throw new IllegalStateException("Database connection information not configured"); - if(LOG.isDebugEnabled())LOG.debug("Connecting using dbDriver="+dbDriver+"+ dbUserName="+dbUserName+", dbPassword="+dbUrl); + if (LOG.isDebugEnabled()) + LOG.debug("Connecting using dbDriver=" + dbDriver + "+ dbUserName=" + dbUserName + ", dbPassword=" + dbUrl); - return DriverManager.getConnection (dbUrl, - dbUserName, - dbPassword); + return DriverManager.getConnection(dbUrl, + dbUserName, + dbPassword); } - - - /* ------------------------------------------------ */ - /** + /** * Init LoginModule. *

        * Called once by JAAS after new instance created. - * + * * @param subject the subject * @param callbackHandler the callback handler * @param sharedState the shared state map @@ -85,8 +81,8 @@ public class JDBCLoginModule extends AbstractDatabaseLoginModule @Override public void initialize(Subject subject, CallbackHandler callbackHandler, - Map sharedState, - Map options) + Map sharedState, + Map options) { try { @@ -109,7 +105,7 @@ public class JDBCLoginModule extends AbstractDatabaseLoginModule } catch (Exception e) { - throw new IllegalStateException (e.toString()); + throw new IllegalStateException(e.toString()); } } } diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/LdapLoginModule.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/LdapLoginModule.java index 49f1a99a895..a75c7c62916 100644 --- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/LdapLoginModule.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/LdapLoginModule.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,12 +20,12 @@ package org.eclipse.jetty.jaas.spi; import java.io.IOException; import java.util.ArrayList; +import java.util.Base64; import java.util.Hashtable; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Properties; - import javax.naming.AuthenticationException; import javax.naming.Context; import javax.naming.NamingEnumeration; @@ -45,7 +45,6 @@ import javax.security.auth.login.FailedLoginException; import javax.security.auth.login.LoginException; import org.eclipse.jetty.jaas.callback.ObjectCallback; -import org.eclipse.jetty.util.B64Code; import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -180,7 +179,6 @@ public class LdapLoginModule extends AbstractLoginModule private DirContext _rootContext; - public class LDAPUserInfo extends UserInfo { Attributes attributes; @@ -201,10 +199,8 @@ public class LdapLoginModule extends AbstractLoginModule { return getUserRoles(_rootContext, getUserName(), attributes); } - } - /** * get the available information about the user *

        @@ -269,9 +265,7 @@ public class LdapLoginModule extends AbstractLoginModule *

        * NOTE: this is not an user authenticated operation * - * @param username * @return the {@link Attributes} from the user - * @throws LoginException */ private Attributes getUserAttributes(String username) throws LoginException { @@ -299,7 +293,8 @@ public class LdapLoginModule extends AbstractLoginModule } } - if(LOG.isDebugEnabled()) LOG.debug("user cred is: " + ldapCredential); + if (LOG.isDebugEnabled()) + LOG.debug("user cred is: " + ldapCredential); return ldapCredential; } @@ -308,11 +303,6 @@ public class LdapLoginModule extends AbstractLoginModule * attempts to get the users roles from the root context *

        * NOTE: this is not an user authenticated operation - * - * @param dirContext - * @param username - * @return - * @throws LoginException */ private List getUserRoles(DirContext dirContext, String username, Attributes attributes) throws LoginException, NamingException { @@ -324,7 +314,7 @@ public class LdapLoginModule extends AbstractLoginModule { rdnValue = (String)attribute.get(); // switch to the value stored in the _userRdnAttribute if we can } - catch (NamingException e) + catch (NamingException ignored) { } } @@ -332,8 +322,8 @@ public class LdapLoginModule extends AbstractLoginModule String filter = "({0}={1})"; Object[] filterArguments = new Object[]{ - _userRdnAttribute, - rdnValue + _userRdnAttribute, + rdnValue }; SearchResult searchResult = findUser(dirContext, filter, filterArguments); @@ -359,7 +349,8 @@ public class LdapLoginModule extends AbstractLoginModule Object[] filterArguments = {_roleObjectClass, _roleMemberAttribute, userDn}; NamingEnumeration results = dirContext.search(_roleBaseDn, filter, filterArguments, ctls); - if(LOG.isDebugEnabled()) LOG.debug("Found user roles?: " + results.hasMoreElements()); + if (LOG.isDebugEnabled()) + LOG.debug("Found user roles?: " + results.hasMoreElements()); while (results.hasMoreElements()) { @@ -389,7 +380,6 @@ public class LdapLoginModule extends AbstractLoginModule return roleList; } - /** * since ldap uses a context bind for valid authentication checking, we override login() *

        @@ -461,15 +451,15 @@ public class LdapLoginModule extends AbstractLoginModule { if (_debug) { - LOG.info( e ); + LOG.info(e); } throw new LoginException("IO Error performing login."); } - catch ( AuthenticationException e ) + catch (AuthenticationException e) { if (_debug) { - LOG.info( e ); + LOG.info(e); } return false; } @@ -481,7 +471,7 @@ public class LdapLoginModule extends AbstractLoginModule { if (_debug) LOG.info(e); - throw new LoginException ("Error obtaining user info"); + throw new LoginException("Error obtaining user info"); } } @@ -507,7 +497,7 @@ public class LdapLoginModule extends AbstractLoginModule * @param username the user name * @param password the password * @return true always - * @throws LoginException if unable to bind the login + * @throws LoginException if unable to bind the login */ public boolean bindingLogin(String username, Object password) throws LoginException { @@ -548,7 +538,7 @@ public class LdapLoginModule extends AbstractLoginModule } catch (NamingException e) { - throw new FailedLoginException (e.getMessage()); + throw new FailedLoginException(e.getMessage()); } } @@ -560,9 +550,9 @@ public class LdapLoginModule extends AbstractLoginModule LOG.debug("Searching for user " + username + " with filter: \'" + filter + "\'" + " from base dn: " + _userBaseDn); Object[] filterArguments = new Object[]{ - _userObjectClass, - _userIdAttribute, - username + _userObjectClass, + _userIdAttribute, + username }; return findUser(_rootContext, filter, filterArguments); @@ -579,9 +569,9 @@ public class LdapLoginModule extends AbstractLoginModule { results = _rootContext.search(_userBaseDn, filter, filterArguments, ctls); } - catch (NamingException ne) + catch (NamingException ex) { - throw new FailedLoginException(ne.getMessage()); + throw new FailedLoginException(ex.getMessage()); } if (LOG.isDebugEnabled()) @@ -590,23 +580,22 @@ public class LdapLoginModule extends AbstractLoginModule if (!results.hasMoreElements()) throw new FailedLoginException("User not found."); - SearchResult searchResult = (SearchResult)results.nextElement(); + SearchResult searchResult = results.nextElement(); if (results.hasMoreElements()) throw new FailedLoginException("Search result contains ambiguous entries"); return searchResult; } - /** * Init LoginModule. *

        * Called once by JAAS after new instance is created. * - * @param subject the subect + * @param subject the subect * @param callbackHandler the callback handler - * @param sharedState the shared state map - * @param options the option map + * @param sharedState the shared state map + * @param options the option map */ @Override public void initialize(Subject subject, @@ -741,13 +730,13 @@ public class LdapLoginModule extends AbstractLoginModule if (encryptedPassword.toUpperCase(Locale.ENGLISH).startsWith("{MD5}")) { - String src = encryptedPassword.substring("{MD5}".length(), encryptedPassword.length()); + String src = encryptedPassword.substring("{MD5}".length()); return "MD5:" + base64ToHex(src); } if (encryptedPassword.toUpperCase(Locale.ENGLISH).startsWith("{CRYPT}")) { - return "CRYPT:" + encryptedPassword.substring("{CRYPT}".length(), encryptedPassword.length()); + return "CRYPT:" + encryptedPassword.substring("{CRYPT}".length()); } return encryptedPassword; @@ -755,13 +744,13 @@ public class LdapLoginModule extends AbstractLoginModule private static String base64ToHex(String src) { - byte[] bytes = B64Code.decode(src); + byte[] bytes = Base64.getDecoder().decode(src); return TypeUtil.toString(bytes, 16); } private static String hexToBase64(String src) { byte[] bytes = TypeUtil.fromHexString(src); - return new String(B64Code.encode(bytes)); + return Base64.getEncoder().encodeToString(bytes); } } diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/PropertyFileLoginModule.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/PropertyFileLoginModule.java index 7d0b7cbbc9b..4626e4a7709 100644 --- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/PropertyFileLoginModule.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/PropertyFileLoginModule.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,16 +18,16 @@ package org.eclipse.jetty.jaas.spi; -import java.security.Principal; -import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; import javax.security.auth.Subject; import javax.security.auth.callback.CallbackHandler; +import org.eclipse.jetty.security.AbstractLoginService; import org.eclipse.jetty.security.PropertyUserStore; import org.eclipse.jetty.server.UserIdentity; import org.eclipse.jetty.util.log.Log; @@ -48,23 +48,20 @@ public class PropertyFileLoginModule extends AbstractLoginModule private int _refreshInterval = 0; private String _filename = DEFAULT_FILENAME; - - /** * Read contents of the configured property file. * - * @see javax.security.auth.spi.LoginModule#initialize(javax.security.auth.Subject, javax.security.auth.callback.CallbackHandler, java.util.Map, - * java.util.Map) - * * @param subject the subject * @param callbackHandler the callback handler * @param sharedState the shared state map * @param options the options map + * @see javax.security.auth.spi.LoginModule#initialize(javax.security.auth.Subject, javax.security.auth.callback.CallbackHandler, java.util.Map, + * java.util.Map) */ @Override public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) { - super.initialize(subject,callbackHandler,sharedState,options); + super.initialize(subject, callbackHandler, sharedState, options); setupPropertyUserStore(options); } @@ -88,7 +85,7 @@ public class PropertyFileLoginModule extends AbstractLoginModule } catch (Exception e) { - LOG.warn("Exception while starting propertyUserStore: ",e); + LOG.warn("Exception while starting propertyUserStore: ", e); } } } @@ -97,14 +94,12 @@ public class PropertyFileLoginModule extends AbstractLoginModule private void parseConfig(Map options) { String tmp = (String)options.get("file"); - _filename = (tmp == null? DEFAULT_FILENAME : tmp); + _filename = (tmp == null ? DEFAULT_FILENAME : tmp); tmp = (String)options.get("refreshInterval"); - _refreshInterval = (tmp == null?_refreshInterval:Integer.parseInt(tmp)); + _refreshInterval = (tmp == null ? _refreshInterval : Integer.parseInt(tmp)); } /** - * - * * @param userName the user name * @throws Exception if unable to get the user information */ @@ -114,26 +109,22 @@ public class PropertyFileLoginModule extends AbstractLoginModule PropertyUserStore propertyUserStore = _propertyUserStores.get(_filename); if (propertyUserStore == null) throw new IllegalStateException("PropertyUserStore should never be null here!"); - - LOG.debug("Checking PropertyUserStore "+_filename+" for "+userName); + + LOG.debug("Checking PropertyUserStore " + _filename + " for " + userName); UserIdentity userIdentity = propertyUserStore.getUserIdentity(userName); - if (userIdentity==null) + if (userIdentity == null) return null; //TODO in future versions change the impl of PropertyUserStore so its not //storing Subjects etc, just UserInfo - Set principals = userIdentity.getSubject().getPrincipals(); + Set principals = userIdentity.getSubject().getPrincipals(AbstractLoginService.RolePrincipal.class); - List roles = new ArrayList(); - - for ( Principal principal : principals ) - { - roles.add( principal.getName() ); - } + List roles = principals.stream() + .map(AbstractLoginService.RolePrincipal::getName) + .collect(Collectors.toList()); Credential credential = (Credential)userIdentity.getSubject().getPrivateCredentials().iterator().next(); - LOG.debug("Found: " + userName + " in PropertyUserStore "+_filename); + LOG.debug("Found: " + userName + " in PropertyUserStore " + _filename); return new UserInfo(userName, credential, roles); } - } diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/UserInfo.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/UserInfo.java index 8ee32265f18..18866601d52 100644 --- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/UserInfo.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/UserInfo.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -29,24 +29,23 @@ import org.eclipse.jetty.util.security.Credential; * * This is the information read from the external source * about a user. - * + * * Can be cached. */ public class UserInfo { - + private String _userName; private Credential _credential; protected List _roleNames = new ArrayList<>(); protected boolean _rolesLoaded = false; - - + /** * @param userName the user name * @param credential the credential * @param roleNames a {@link List} of role name */ - public UserInfo (String userName, Credential credential, List roleNames) + public UserInfo(String userName, Credential credential, List roleNames) { _userName = userName; _credential = credential; @@ -56,32 +55,29 @@ public class UserInfo _rolesLoaded = true; } } - - + /** * @param userName the user name * @param credential the credential */ - public UserInfo (String userName, Credential credential) + public UserInfo(String userName, Credential credential) { - this (userName, credential, null); + this(userName, credential, null); } - - - + /** * Should be overridden by subclasses to obtain * role info - * + * * @return List of role associated to the user * @throws Exception if the roles cannot be retrieved */ public List doFetchRoles() - throws Exception + throws Exception { return Collections.emptyList(); } - + public void fetchRoles() throws Exception { synchronized (_roleNames) @@ -93,25 +89,24 @@ public class UserInfo } } } - + public String getUserName() { return this._userName; } - - public List getRoleNames () - { + + public List getRoleNames() + { return Collections.unmodifiableList(_roleNames); } - - public boolean checkCredential (Object suppliedCredential) + + public boolean checkCredential(Object suppliedCredential) { return _credential.check(suppliedCredential); } - - protected Credential getCredential () + + protected Credential getCredential() { return _credential; } - } diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/package-info.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/package-info.java index c2fea422e55..22b8001adff 100644 --- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/package-info.java +++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-jaas/src/test/java/org/eclipse/jetty/jaas/JAASLdapLoginServiceTest.java b/jetty-jaas/src/test/java/org/eclipse/jetty/jaas/JAASLdapLoginServiceTest.java index addc8252856..fd77a0398fe 100644 --- a/jetty-jaas/src/test/java/org/eclipse/jetty/jaas/JAASLdapLoginServiceTest.java +++ b/jetty-jaas/src/test/java/org/eclipse/jetty/jaas/JAASLdapLoginServiceTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,9 +16,14 @@ // ======================================================================== // - package org.eclipse.jetty.jaas; +import java.util.HashMap; +import java.util.Map; +import javax.security.auth.login.AppConfigurationEntry; +import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag; +import javax.security.auth.login.Configuration; + import org.apache.directory.server.annotations.CreateLdapServer; import org.apache.directory.server.annotations.CreateTransport; import org.apache.directory.server.core.annotations.ApplyLdifs; @@ -33,24 +38,20 @@ import org.eclipse.jetty.server.UserIdentity; import org.junit.Test; import org.junit.runner.RunWith; -import javax.security.auth.login.AppConfigurationEntry; -import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag; -import javax.security.auth.login.Configuration; -import java.util.HashMap; -import java.util.Map; - -import static org.junit.Assert.*; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; /** * JAASLdapLoginServiceTest - * - * */ -@RunWith( FrameworkRunner.class) -@CreateLdapServer( transports = { @CreateTransport(protocol = "LDAP" ) } ) +@RunWith(FrameworkRunner.class) +@CreateLdapServer(transports = {@CreateTransport(protocol = "LDAP")}) @CreateDS(allowAnonAccess = false, partitions = { @CreatePartition(name = "Users Partition", suffix = "ou=people,dc=jetty,dc=org"), - @CreatePartition(name = "Groups Partition", suffix = "ou=groups,dc=jetty,dc=org")}) + @CreatePartition(name = "Groups Partition", suffix = "ou=groups,dc=jetty,dc=org") +}) @ApplyLdifs({ // Entry 1 "dn: ou=people,dc=jetty,dc=org", @@ -121,26 +122,29 @@ public class JAASLdapLoginServiceTest { private static LdapServer _ldapServer; - private JAASLoginService jaasLoginService(String name) { - JAASLoginService ls = new JAASLoginService("foo"); - ls.setCallbackHandlerClass("org.eclipse.jetty.jaas.callback.DefaultCallbackHandler"); - ls.setIdentityService(new DefaultIdentityService()); - ls.setConfiguration(new TestConfiguration(true)); - return ls; + private JAASLoginService jaasLoginService(String name) + { + JAASLoginService ls = new JAASLoginService("foo"); + ls.setCallbackHandlerClass("org.eclipse.jetty.jaas.callback.DefaultCallbackHandler"); + ls.setIdentityService(new DefaultIdentityService()); + ls.setConfiguration(new TestConfiguration(true)); + return ls; } private UserIdentity doLogin(String username, String password) throws Exception { JAASLoginService ls = jaasLoginService("foo"); Request request = new Request(null, null); - return ls.login( username, password, request); + return ls.login(username, password, request); } - public static LdapServer getLdapServer() { + public static LdapServer getLdapServer() + { return _ldapServer; } - public static void setLdapServer(LdapServer ldapServer) { + public static void setLdapServer(LdapServer ldapServer) + { _ldapServer = ldapServer; } @@ -148,7 +152,7 @@ public class JAASLdapLoginServiceTest { private boolean forceBindingLogin; - public TestConfiguration( boolean forceBindingLogin ) + public TestConfiguration(boolean forceBindingLogin) { this.forceBindingLogin = forceBindingLogin; } @@ -156,24 +160,22 @@ public class JAASLdapLoginServiceTest @Override public AppConfigurationEntry[] getAppConfigurationEntry(String name) { - Map options = new HashMap<>( ); - options.put( "hostname", "localhost" ); - options.put( "port", Integer.toString(_ldapServer.getTransports()[0].getPort())); - options.put( "contextFactory", "com.sun.jndi.ldap.LdapCtxFactory" ); - options.put( "bindDn", "uid=admin,ou=system"); - options.put( "bindPassword", "secret"); - options.put( "userBaseDn", "ou=people,dc=jetty,dc=org" ); - options.put( "roleBaseDn","ou=groups,dc=jetty,dc=org"); - options.put( "roleNameAttribute", "cn" ); - options.put( "forceBindingLogin", Boolean.toString( forceBindingLogin ) ); - AppConfigurationEntry entry = new AppConfigurationEntry( LdapLoginModule.class.getCanonicalName(), LoginModuleControlFlag.REQUIRED, options); + Map options = new HashMap<>(); + options.put("hostname", "localhost"); + options.put("port", Integer.toString(_ldapServer.getTransports()[0].getPort())); + options.put("contextFactory", "com.sun.jndi.ldap.LdapCtxFactory"); + options.put("bindDn", "uid=admin,ou=system"); + options.put("bindPassword", "secret"); + options.put("userBaseDn", "ou=people,dc=jetty,dc=org"); + options.put("roleBaseDn", "ou=groups,dc=jetty,dc=org"); + options.put("roleNameAttribute", "cn"); + options.put("forceBindingLogin", Boolean.toString(forceBindingLogin)); + AppConfigurationEntry entry = new AppConfigurationEntry(LdapLoginModule.class.getCanonicalName(), LoginModuleControlFlag.REQUIRED, options); - return new AppConfigurationEntry[] {entry}; + return new AppConfigurationEntry[]{entry}; } - } - @Test public void testLdapUserIdentity() throws Exception { @@ -182,17 +184,17 @@ public class JAASLdapLoginServiceTest ls.setIdentityService(new DefaultIdentityService()); ls.setConfiguration(new TestConfiguration(false)); Request request = new Request(null, null); - UserIdentity userIdentity = ls.login( "someone", "complicatedpassword", request); - assertNotNull( userIdentity ); - assertTrue( userIdentity.isUserInRole( "developers", null) ); - assertTrue( userIdentity.isUserInRole( "admin", null) ); - assertFalse( userIdentity.isUserInRole( "blabla", null) ); + UserIdentity userIdentity = ls.login("someone", "complicatedpassword", request); + assertNotNull(userIdentity); + assertTrue(userIdentity.isUserInRole("developers", null)); + assertTrue(userIdentity.isUserInRole("admin", null)); + assertFalse(userIdentity.isUserInRole("blabla", null)); - userIdentity = ls.login( "someoneelse", "verycomplicatedpassword", request); - assertNotNull( userIdentity ); - assertFalse( userIdentity.isUserInRole( "developers", null) ); - assertTrue( userIdentity.isUserInRole( "admin", null) ); - assertFalse( userIdentity.isUserInRole( "blabla", null) ); + userIdentity = ls.login("someoneelse", "verycomplicatedpassword", request); + assertNotNull(userIdentity); + assertFalse(userIdentity.isUserInRole("developers", null)); + assertTrue(userIdentity.isUserInRole("admin", null)); + assertFalse(userIdentity.isUserInRole("blabla", null)); } @Test @@ -203,38 +205,37 @@ public class JAASLdapLoginServiceTest ls.setIdentityService(new DefaultIdentityService()); ls.setConfiguration(new TestConfiguration(true)); Request request = new Request(null, null); - UserIdentity userIdentity = ls.login( "someone", "complicatedpassword", request); - assertNotNull( userIdentity ); - assertTrue( userIdentity.isUserInRole( "developers", null) ); - assertTrue( userIdentity.isUserInRole( "admin", null) ); - assertFalse( userIdentity.isUserInRole( "blabla", null) ); - - userIdentity = ls.login( "someone", "wrongpassword", request); - assertNull( userIdentity ); + UserIdentity userIdentity = ls.login("someone", "complicatedpassword", request); + assertNotNull(userIdentity); + assertTrue(userIdentity.isUserInRole("developers", null)); + assertTrue(userIdentity.isUserInRole("admin", null)); + assertFalse(userIdentity.isUserInRole("blabla", null)); + userIdentity = ls.login("someone", "wrongpassword", request); + assertNull(userIdentity); } @Test public void testLdapBindingSubdirUniqueUserName() throws Exception { UserIdentity userIdentity = doLogin("uniqueuser", "hello123"); - assertNotNull( userIdentity ); - assertTrue( userIdentity.isUserInRole( "developers", null) ); - assertTrue( userIdentity.isUserInRole( "admin", null) ); - assertFalse( userIdentity.isUserInRole( "blabla", null) ); + assertNotNull(userIdentity); + assertTrue(userIdentity.isUserInRole("developers", null)); + assertTrue(userIdentity.isUserInRole("admin", null)); + assertFalse(userIdentity.isUserInRole("blabla", null)); } @Test public void testLdapBindingAmbiguousUserName() throws Exception { - UserIdentity userIdentity = doLogin( "ambiguousone", "foobar"); - assertNull( userIdentity ); + UserIdentity userIdentity = doLogin("ambiguousone", "foobar"); + assertNull(userIdentity); } @Test public void testLdapBindingSubdirAmbiguousUserName() throws Exception { - UserIdentity userIdentity = doLogin( "ambiguousone", "barfoo"); - assertNull( userIdentity ); + UserIdentity userIdentity = doLogin("ambiguousone", "barfoo"); + assertNull(userIdentity); } } diff --git a/jetty-jaas/src/test/java/org/eclipse/jetty/jaas/JAASLoginServiceTest.java b/jetty-jaas/src/test/java/org/eclipse/jetty/jaas/JAASLoginServiceTest.java index b247eeb1344..b4e82633eea 100644 --- a/jetty-jaas/src/test/java/org/eclipse/jetty/jaas/JAASLoginServiceTest.java +++ b/jetty-jaas/src/test/java/org/eclipse/jetty/jaas/JAASLoginServiceTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,15 +16,10 @@ // ======================================================================== // - package org.eclipse.jetty.jaas; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.security.Principal; import java.util.Collections; - import javax.security.auth.Subject; import javax.security.auth.login.AppConfigurationEntry; import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag; @@ -34,6 +29,9 @@ import org.eclipse.jetty.security.DefaultIdentityService; import org.eclipse.jetty.server.Request; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + /** * JAASLoginServiceTest */ @@ -46,87 +44,83 @@ public class JAASLoginServiceTest @Override public AppConfigurationEntry[] getAppConfigurationEntry(String name) { - return new AppConfigurationEntry[] {_entry}; + return new AppConfigurationEntry[]{_entry}; } - } - - + interface SomeRole { - + } public class TestRole implements Principal, SomeRole { String _name; - public TestRole (String name) + public TestRole(String name) { _name = name; } public String getName() { - return _name; + return _name; } } - - + public class AnotherTestRole extends TestRole { public AnotherTestRole(String name) { super(name); - } + } } - + public class NotTestRole implements Principal { String _name; - - public NotTestRole (String n) + + public NotTestRole(String n) { _name = n; } - + public String getName() { - return _name; + return _name; } } - + @Test - public void testServletRequestCallback () throws Exception + public void testServletRequestCallback() throws Exception { //Test with the DefaultCallbackHandler JAASLoginService ls = new JAASLoginService("foo"); ls.setCallbackHandlerClass("org.eclipse.jetty.jaas.callback.DefaultCallbackHandler"); ls.setIdentityService(new DefaultIdentityService()); ls.setConfiguration(new TestConfiguration()); - Request request = new Request(null, null); + Request request = new Request(null, null); ls.login("aaardvaark", "aaa", request); - + //Test with the fallback CallbackHandler ls = new JAASLoginService("foo"); ls.setIdentityService(new DefaultIdentityService()); - ls.setConfiguration(new TestConfiguration()); + ls.setConfiguration(new TestConfiguration()); ls.login("aaardvaark", "aaa", request); - } @Test - public void testLoginServiceRoles () throws Exception + public void testLoginServiceRoles() throws Exception { JAASLoginService ls = new JAASLoginService("foo"); - + //test that we always add in the DEFAULT ROLE CLASSNAME - ls.setRoleClassNames(new String[] {"arole", "brole"}); + ls.setRoleClassNames(new String[]{"arole", "brole"}); String[] roles = ls.getRoleClassNames(); assertEquals(3, roles.length); assertEquals(JAASLoginService.DEFAULT_ROLE_CLASS_NAME, roles[2]); - - ls.setRoleClassNames(new String[] {}); + + ls.setRoleClassNames(new String[]{}); assertEquals(1, ls.getRoleClassNames().length); assertEquals(JAASLoginService.DEFAULT_ROLE_CLASS_NAME, ls.getRoleClassNames()[0]); @@ -135,20 +129,22 @@ public class JAASLoginServiceTest assertEquals(JAASLoginService.DEFAULT_ROLE_CLASS_NAME, ls.getRoleClassNames()[0]); //test a custom role class where some of the roles are subclasses of it - ls.setRoleClassNames(new String[] {TestRole.class.getName()}); + ls.setRoleClassNames(new String[]{TestRole.class.getName()}); Subject subject = new Subject(); subject.getPrincipals().add(new NotTestRole("w")); subject.getPrincipals().add(new TestRole("x")); subject.getPrincipals().add(new TestRole("y")); subject.getPrincipals().add(new AnotherTestRole("z")); - + String[] groups = ls.getGroups(subject); assertEquals(3, groups.length); - for (String g:groups) + for (String g : groups) + { assertTrue(g.equals("x") || g.equals("y") || g.equals("z")); - + } + //test a custom role class - ls.setRoleClassNames(new String[] {AnotherTestRole.class.getName()}); + ls.setRoleClassNames(new String[]{AnotherTestRole.class.getName()}); Subject subject2 = new Subject(); subject2.getPrincipals().add(new NotTestRole("w")); subject2.getPrincipals().add(new TestRole("x")); @@ -156,25 +152,26 @@ public class JAASLoginServiceTest subject2.getPrincipals().add(new AnotherTestRole("z")); assertEquals(1, ls.getGroups(subject2).length); assertEquals("z", ls.getGroups(subject2)[0]); - + //test a custom role class that implements an interface - ls.setRoleClassNames(new String[] {SomeRole.class.getName()}); + ls.setRoleClassNames(new String[]{SomeRole.class.getName()}); Subject subject3 = new Subject(); subject3.getPrincipals().add(new NotTestRole("w")); subject3.getPrincipals().add(new TestRole("x")); subject3.getPrincipals().add(new TestRole("y")); subject3.getPrincipals().add(new AnotherTestRole("z")); assertEquals(3, ls.getGroups(subject3).length); - for (String g:groups) + for (String g : groups) + { assertTrue(g.equals("x") || g.equals("y") || g.equals("z")); - + } + //test a class that doesn't match - ls.setRoleClassNames(new String[] {NotTestRole.class.getName()}); + ls.setRoleClassNames(new String[]{NotTestRole.class.getName()}); Subject subject4 = new Subject(); subject4.getPrincipals().add(new TestRole("x")); subject4.getPrincipals().add(new TestRole("y")); subject4.getPrincipals().add(new AnotherTestRole("z")); - assertEquals(0, ls.getGroups(subject4).length); + assertEquals(0, ls.getGroups(subject4).length); } - } diff --git a/jetty-jaas/src/test/java/org/eclipse/jetty/jaas/TestLoginModule.java b/jetty-jaas/src/test/java/org/eclipse/jetty/jaas/TestLoginModule.java index 593d1530084..c09e39f1ac3 100644 --- a/jetty-jaas/src/test/java/org/eclipse/jetty/jaas/TestLoginModule.java +++ b/jetty-jaas/src/test/java/org/eclipse/jetty/jaas/TestLoginModule.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,11 +16,8 @@ // ======================================================================== // - package org.eclipse.jetty.jaas; -import static org.junit.jupiter.api.Assertions.assertNotNull; - import javax.security.auth.callback.Callback; import javax.security.auth.login.LoginException; @@ -30,6 +27,7 @@ import org.eclipse.jetty.jaas.spi.UserInfo; import org.eclipse.jetty.util.ArrayUtil; import org.eclipse.jetty.util.security.Password; +import static org.junit.jupiter.api.Assertions.assertNotNull; public class TestLoginModule extends AbstractLoginModule { @@ -47,7 +45,6 @@ public class TestLoginModule extends AbstractLoginModule return ArrayUtil.addToArray(super.configureCallbacks(), _callback, Callback.class); } - @Override public boolean login() throws LoginException { @@ -55,5 +52,4 @@ public class TestLoginModule extends AbstractLoginModule assertNotNull(_callback.getRequest()); return result; } - -} \ No newline at end of file +} diff --git a/jetty-jaas/src/test/java/org/eclipse/jetty/jaas/spi/PropertyFileLoginModuleTest.java b/jetty-jaas/src/test/java/org/eclipse/jetty/jaas/spi/PropertyFileLoginModuleTest.java new file mode 100644 index 00000000000..e62320ea54a --- /dev/null +++ b/jetty-jaas/src/test/java/org/eclipse/jetty/jaas/spi/PropertyFileLoginModuleTest.java @@ -0,0 +1,53 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.jaas.spi; + +import java.io.File; +import java.util.HashMap; + +import javax.security.auth.Subject; + +import org.eclipse.jetty.jaas.callback.DefaultCallbackHandler; +import org.eclipse.jetty.toolchain.test.MavenTestingUtils; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.not; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class PropertyFileLoginModuleTest +{ + @Test + public void testRoles() + throws Exception + { + File file = MavenTestingUtils.getTestResourceFile("login.properties"); + PropertyFileLoginModule module = new PropertyFileLoginModule(); + Subject subject = new Subject(); + HashMap options = new HashMap<>(); + options.put("file", file.getCanonicalPath()); + module.initialize(subject, new DefaultCallbackHandler(), new HashMap(), options); + UserInfo fred = module.getUserInfo("fred"); + assertEquals("fred", fred.getUserName()); + assertThat(fred.getRoleNames(), containsInAnyOrder("role1", "role2", "role3")); + assertThat(fred.getRoleNames(), not(contains("fred"))); + } +} diff --git a/jetty-jaas/src/test/resources/login.properties b/jetty-jaas/src/test/resources/login.properties new file mode 100644 index 00000000000..22a4bedc7b7 --- /dev/null +++ b/jetty-jaas/src/test/resources/login.properties @@ -0,0 +1 @@ +fred=pwd,role1,role2,role3 \ No newline at end of file diff --git a/jetty-jaspi/pom.xml b/jetty-jaspi/pom.xml index c536a7709d6..f1a22cec0b4 100644 --- a/jetty-jaspi/pom.xml +++ b/jetty-jaspi/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 diff --git a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/JaspiAuthenticator.java b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/JaspiAuthenticator.java index ec01d9ebe78..3ee6dc1836a 100644 --- a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/JaspiAuthenticator.java +++ b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/JaspiAuthenticator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -22,7 +22,6 @@ import java.io.IOException; import java.security.Principal; import java.util.Map; import java.util.Set; - import javax.security.auth.Subject; import javax.security.auth.message.AuthException; import javax.security.auth.message.AuthStatus; @@ -54,7 +53,7 @@ import org.eclipse.jetty.util.log.Logger; public class JaspiAuthenticator extends LoginAuthenticator { private static final Logger LOG = Log.getLogger(JaspiAuthenticator.class.getName()); - + private final ServerAuthConfig _authConfig; private final Map _authProperties; @@ -67,14 +66,14 @@ public class JaspiAuthenticator extends LoginAuthenticator private final IdentityService _identityService; - - public JaspiAuthenticator(ServerAuthConfig authConfig, Map authProperties, ServletCallbackHandler callbackHandler, Subject serviceSubject, boolean allowLazyAuthentication, IdentityService identityService) { // TODO maybe pass this in via setConfiguration ? - if (callbackHandler == null) throw new NullPointerException("No CallbackHandler"); - if (authConfig == null) throw new NullPointerException("No AuthConfig"); + if (callbackHandler == null) + throw new NullPointerException("No CallbackHandler"); + if (authConfig == null) + throw new NullPointerException("No AuthConfig"); this._authConfig = authConfig; this._authProperties = authProperties; this._callbackHandler = callbackHandler; @@ -102,7 +101,7 @@ public class JaspiAuthenticator extends LoginAuthenticator request.setAttribute("org.eclipse.jetty.security.jaspi.info", info); Authentication a = validateRequest(info); - + //if its not mandatory to authenticate, and the authenticator returned UNAUTHENTICATED, we treat it as authentication deferred if (_allowLazyAuthentication && !info.isAuthMandatory() && a == Authentication.UNAUTHENTICATED) a = new DeferredAuthentication(this); @@ -113,18 +112,18 @@ public class JaspiAuthenticator extends LoginAuthenticator @Override public boolean secureResponse(ServletRequest req, ServletResponse res, boolean mandatory, User validatedUser) throws ServerAuthException { - JaspiMessageInfo info = (JaspiMessageInfo) req.getAttribute("org.eclipse.jetty.security.jaspi.info"); - if (info == null) throw new NullPointerException("MessageInfo from request missing: " + req); + JaspiMessageInfo info = (JaspiMessageInfo)req.getAttribute("org.eclipse.jetty.security.jaspi.info"); + if (info == null) + throw new NullPointerException("MessageInfo from request missing: " + req); return secureResponse(info, validatedUser); } - - /** + /** * @see org.eclipse.jetty.security.authentication.LoginAuthenticator#login(java.lang.String, java.lang.Object, javax.servlet.ServletRequest) */ @Override public UserIdentity login(String username, Object password, ServletRequest request) - { + { UserIdentity user = _loginService.login(username, password, request); if (user != null) { @@ -139,8 +138,6 @@ public class JaspiAuthenticator extends LoginAuthenticator return user; } - - public Authentication validateRequest(JaspiMessageInfo messageInfo) throws ServerAuthException { try @@ -151,8 +148,10 @@ public class JaspiAuthenticator extends LoginAuthenticator AuthStatus authStatus = authContext.validateRequest(messageInfo, clientSubject, _serviceSubject); - if (authStatus == AuthStatus.SEND_CONTINUE) return Authentication.SEND_CONTINUE; - if (authStatus == AuthStatus.SEND_FAILURE) return Authentication.SEND_FAILURE; + if (authStatus == AuthStatus.SEND_CONTINUE) + return Authentication.SEND_CONTINUE; + if (authStatus == AuthStatus.SEND_FAILURE) + return Authentication.SEND_FAILURE; if (authStatus == AuthStatus.SUCCESS) { @@ -165,7 +164,10 @@ public class JaspiAuthenticator extends LoginAuthenticator else { CallerPrincipalCallback principalCallback = _callbackHandler.getThreadCallerPrincipalCallback(); - if (principalCallback == null) { return Authentication.UNAUTHENTICATED; } + if (principalCallback == null) + { + return Authentication.UNAUTHENTICATED; + } Principal principal = principalCallback.getPrincipal(); if (principal == null) { @@ -179,18 +181,21 @@ public class JaspiAuthenticator extends LoginAuthenticator break; } } - if (principal == null) { return Authentication.UNAUTHENTICATED; } + if (principal == null) + { + return Authentication.UNAUTHENTICATED; + } } GroupPrincipalCallback groupPrincipalCallback = _callbackHandler.getThreadGroupPrincipalCallback(); String[] groups = groupPrincipalCallback == null ? null : groupPrincipalCallback.getGroups(); userIdentity = _identityService.newUserIdentity(clientSubject, principal, groups); } - + HttpSession session = ((HttpServletRequest)messageInfo.getRequestMessage()).getSession(false); - Authentication cached = (session == null?null:(SessionAuthentication)session.getAttribute(SessionAuthentication.__J_AUTHENTICATED)); + Authentication cached = (session == null ? null : (SessionAuthentication)session.getAttribute(SessionAuthentication.__J_AUTHENTICATED)); if (cached != null) return cached; - + return new UserAuthentication(getAuthMethod(), userIdentity); } if (authStatus == AuthStatus.SEND_SUCCESS) @@ -200,14 +205,14 @@ public class JaspiAuthenticator extends LoginAuthenticator } if (authStatus == AuthStatus.FAILURE) { - HttpServletResponse response = (HttpServletResponse) messageInfo.getResponseMessage(); + HttpServletResponse response = (HttpServletResponse)messageInfo.getResponseMessage(); response.sendError(HttpServletResponse.SC_FORBIDDEN); return Authentication.SEND_FAILURE; } // should not happen throw new IllegalStateException("No AuthStatus returned"); } - catch (IOException|AuthException e) + catch (IOException | AuthException e) { throw new ServerAuthException(e); } @@ -229,5 +234,4 @@ public class JaspiAuthenticator extends LoginAuthenticator throw new ServerAuthException(e); } } - } diff --git a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/JaspiAuthenticatorFactory.java b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/JaspiAuthenticatorFactory.java index facb0d4d8a7..79535b39b74 100644 --- a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/JaspiAuthenticatorFactory.java +++ b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/JaspiAuthenticatorFactory.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -45,12 +45,10 @@ public class JaspiAuthenticatorFactory extends DefaultAuthenticatorFactory private static final Logger LOG = Log.getLogger(JaspiAuthenticatorFactory.class); private static String MESSAGE_LAYER = "HTTP"; - + private Subject _serviceSubject; private String _serverName; - - /* ------------------------------------------------------------ */ /** * @return the serviceSubject */ @@ -59,7 +57,6 @@ public class JaspiAuthenticatorFactory extends DefaultAuthenticatorFactory return _serviceSubject; } - /* ------------------------------------------------------------ */ /** * @param serviceSubject the serviceSubject to set */ @@ -68,7 +65,6 @@ public class JaspiAuthenticatorFactory extends DefaultAuthenticatorFactory _serviceSubject = serviceSubject; } - /* ------------------------------------------------------------ */ /** * @return the serverName */ @@ -77,7 +73,6 @@ public class JaspiAuthenticatorFactory extends DefaultAuthenticatorFactory return _serverName; } - /* ------------------------------------------------------------ */ /** * @param serverName the serverName to set */ @@ -86,94 +81,100 @@ public class JaspiAuthenticatorFactory extends DefaultAuthenticatorFactory _serverName = serverName; } - /* ------------------------------------------------------------ */ @Override public Authenticator getAuthenticator(Server server, ServletContext context, AuthConfiguration configuration, IdentityService identityService, LoginService loginService) { - Authenticator authenticator=null; - try + Authenticator authenticator = null; + try { AuthConfigFactory authConfigFactory = AuthConfigFactory.getFactory(); - RegistrationListener listener = (layer, appContext) -> {}; + RegistrationListener listener = (layer, appContext) -> + { + }; - Subject serviceSubject=findServiceSubject(server); - String serverName=findServerName(server, serviceSubject); + Subject serviceSubject = findServiceSubject(server); + String serverName = findServerName(server, serviceSubject); - String contextPath=context.getContextPath(); - if (contextPath==null || contextPath.length()==0) - contextPath="/"; + String contextPath = context.getContextPath(); + if (contextPath == null || contextPath.length() == 0) + contextPath = "/"; String appContext = serverName + " " + contextPath; - AuthConfigProvider authConfigProvider = authConfigFactory.getConfigProvider(MESSAGE_LAYER,appContext,listener); - + AuthConfigProvider authConfigProvider = authConfigFactory.getConfigProvider(MESSAGE_LAYER, appContext, listener); + if (authConfigProvider != null) { ServletCallbackHandler servletCallbackHandler = new ServletCallbackHandler(loginService); - ServerAuthConfig serverAuthConfig = authConfigProvider.getServerAuthConfig(MESSAGE_LAYER,appContext,servletCallbackHandler); + ServerAuthConfig serverAuthConfig = authConfigProvider.getServerAuthConfig(MESSAGE_LAYER, appContext, servletCallbackHandler); if (serverAuthConfig != null) { Map map = new HashMap(); for (String key : configuration.getInitParameterNames()) - map.put(key,configuration.getInitParameter(key)); - authenticator= new JaspiAuthenticator(serverAuthConfig,map,servletCallbackHandler, - serviceSubject,true, identityService); + { + map.put(key, configuration.getInitParameter(key)); + } + authenticator = new JaspiAuthenticator(serverAuthConfig, map, servletCallbackHandler, + serviceSubject, true, identityService); } } - } - catch (AuthException e) + } + catch (AuthException e) { LOG.warn(e); } return authenticator; } - /* ------------------------------------------------------------ */ - /** Find a service Subject. - * If {@link #setServiceSubject(Subject)} has not been used to + /** + * Find a service Subject. + * If {@link #setServiceSubject(Subject)} has not been used to * set a subject, then the {@link Server#getBeans(Class)} method is * used to look for a Subject. + * * @param server the server to pull the Subject from * @return the subject */ protected Subject findServiceSubject(Server server) { - if (_serviceSubject!=null) + if (_serviceSubject != null) return _serviceSubject; List subjects = (List)server.getBeans(Subject.class); - if (subjects.size()>0) + if (subjects.size() > 0) return subjects.get(0); return null; } - /* ------------------------------------------------------------ */ - /** Find a servername. + /** + * Find a servername. * If {@link #setServerName(String)} has not been called, then * use the name of the a principal in the service subject. * If not found, return "server". + * * @param server the server to find the name of * @return the server name from the service Subject (or default value if not found in subject or principals) */ protected String findServerName(Server server) { - if (_serverName!=null) + if (_serverName != null) return _serverName; Subject subject = findServiceSubject(server); - if (subject!=null) + if (subject != null) { Set principals = subject.getPrincipals(); - if (principals!=null && !principals.isEmpty()) + if (principals != null && !principals.isEmpty()) return principals.iterator().next().getName(); } - + return "server"; } - /* ------------------------------------------------------------ */ - /** Find a servername. + /** + * Find a servername. * If {@link #setServerName(String)} has not been called, then * use the name of the a principal in the service subject. * If not found, return "server". + * * @param server the server to use * @param subject not used * @return the server name from the subject of the server (or default value if not found in subject or principals) diff --git a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/JaspiMessageInfo.java b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/JaspiMessageInfo.java index 8c755809cf5..7f429a9719d 100644 --- a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/JaspiMessageInfo.java +++ b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/JaspiMessageInfo.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -22,7 +22,6 @@ import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; - import javax.security.auth.message.MessageInfo; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; @@ -81,11 +80,11 @@ public class JaspiMessageInfo implements MessageInfo return map.getAuthMethod(); } - public boolean isAuthMandatory() { + public boolean isAuthMandatory() + { return map.isAuthMandatory(); } - //TODO this has bugs in the view implementations. Changing them will not affect the hardcoded values. private static class MIMap implements Map { @@ -101,9 +100,9 @@ public class JaspiMessageInfo implements MessageInfo @Override public int size() { - return (isMandatory? 1:0) + - (authMethod == null? 0: 1) + - (delegate == null? 0: delegate.size()); + return (isMandatory ? 1 : 0) + + (authMethod == null ? 0 : 1) + + (delegate == null ? 0 : delegate.size()); } @Override @@ -115,25 +114,32 @@ public class JaspiMessageInfo implements MessageInfo @Override public boolean containsKey(Object key) { - if (MANDATORY_KEY.equals(key)) return isMandatory; - if (AUTH_METHOD_KEY.equals(key)) return authMethod != null; + if (MANDATORY_KEY.equals(key)) + return isMandatory; + if (AUTH_METHOD_KEY.equals(key)) + return authMethod != null; return delegate != null && delegate.containsKey(key); } @Override public boolean containsValue(Object value) { - if (isMandatory && "true".equals(value)) return true; - if (authMethod == value || (authMethod != null && authMethod.equals(value))) return true; + if (isMandatory && "true".equals(value)) + return true; + if (authMethod == value || (authMethod != null && authMethod.equals(value))) + return true; return delegate != null && delegate.containsValue(value); } @Override public Object get(Object key) { - if (MANDATORY_KEY.equals(key)) return isMandatory? "true": null; - if (AUTH_METHOD_KEY.equals(key)) return authMethod; - if (delegate == null) return null; + if (MANDATORY_KEY.equals(key)) + return isMandatory ? "true" : null; + if (AUTH_METHOD_KEY.equals(key)) + return authMethod; + if (delegate == null) + return null; return delegate.get(key); } @@ -147,8 +153,9 @@ public class JaspiMessageInfo implements MessageInfo if (AUTH_METHOD_KEY.equals(key)) { String authMethod = this.authMethod; - this.authMethod = (String) value; - if (delegate != null) delegate.put(AUTH_METHOD_KEY, value); + this.authMethod = (String)value; + if (delegate != null) + delegate.put(AUTH_METHOD_KEY, value); return authMethod; } @@ -166,10 +173,12 @@ public class JaspiMessageInfo implements MessageInfo { String authMethod = this.authMethod; this.authMethod = null; - if (delegate != null) delegate.remove(AUTH_METHOD_KEY); + if (delegate != null) + delegate.remove(AUTH_METHOD_KEY); return authMethod; } - if (delegate == null) return null; + if (delegate == null) + return null; return delegate.remove(key); } @@ -178,9 +187,9 @@ public class JaspiMessageInfo implements MessageInfo { if (map != null) { - for (Object o: map.entrySet()) + for (Object o : map.entrySet()) { - Map.Entry entry = (Entry) o; + Map.Entry entry = (Entry)o; put(entry.getKey(), entry.getValue()); } } @@ -213,12 +222,15 @@ public class JaspiMessageInfo implements MessageInfo private Map getDelegate(boolean create) { - if (!create || delegate != null) return delegate; + if (!create || delegate != null) + return delegate; if (create) { delegate = new HashMap(); - if (isMandatory) delegate.put(MANDATORY_KEY, "true"); - if (authMethod != null) delegate.put(AUTH_METHOD_KEY, authMethod); + if (isMandatory) + delegate.put(MANDATORY_KEY, "true"); + if (authMethod != null) + delegate.put(AUTH_METHOD_KEY, authMethod); } return delegate; } diff --git a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/ServletCallbackHandler.java b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/ServletCallbackHandler.java index d81cdcfd74c..f342c6618ed 100644 --- a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/ServletCallbackHandler.java +++ b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/ServletCallbackHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,7 +19,6 @@ package org.eclipse.jetty.security.jaspi; import java.io.IOException; - import javax.security.auth.Subject; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; @@ -61,20 +60,20 @@ public class ServletCallbackHandler implements CallbackHandler // jaspi to server communication if (callback instanceof CallerPrincipalCallback) { - _callerPrincipals.set((CallerPrincipalCallback) callback); + _callerPrincipals.set((CallerPrincipalCallback)callback); } else if (callback instanceof GroupPrincipalCallback) { - _groupPrincipals.set((GroupPrincipalCallback) callback); + _groupPrincipals.set((GroupPrincipalCallback)callback); } else if (callback instanceof PasswordValidationCallback) { - PasswordValidationCallback passwordValidationCallback = (PasswordValidationCallback) callback; + PasswordValidationCallback passwordValidationCallback = (PasswordValidationCallback)callback; Subject subject = passwordValidationCallback.getSubject(); - UserIdentity user = _loginService.login(passwordValidationCallback.getUsername(),passwordValidationCallback.getPassword(), null); - - if (user!=null) + UserIdentity user = _loginService.login(passwordValidationCallback.getUsername(), passwordValidationCallback.getPassword(), null); + + if (user != null) { passwordValidationCallback.setResult(true); passwordValidationCallback.getSubject().getPrincipals().addAll(user.getSubject().getPrincipals()); @@ -83,15 +82,15 @@ public class ServletCallbackHandler implements CallbackHandler } else if (callback instanceof CredentialValidationCallback) { - CredentialValidationCallback credentialValidationCallback = (CredentialValidationCallback) callback; + CredentialValidationCallback credentialValidationCallback = (CredentialValidationCallback)callback; Subject subject = credentialValidationCallback.getSubject(); LoginCallback loginCallback = new LoginCallbackImpl(subject, - credentialValidationCallback.getUsername(), - credentialValidationCallback.getCredential()); + credentialValidationCallback.getUsername(), + credentialValidationCallback.getCredential()); - UserIdentity user = _loginService.login(credentialValidationCallback.getUsername(),credentialValidationCallback.getCredential(), null); + UserIdentity user = _loginService.login(credentialValidationCallback.getUsername(), credentialValidationCallback.getCredential(), null); - if (user!=null) + if (user != null) { loginCallback.setUserPrincipal(user.getUserPrincipal()); credentialValidationCallback.getSubject().getPrivateCredentials().add(loginCallback); @@ -101,18 +100,21 @@ public class ServletCallbackHandler implements CallbackHandler } } // server to jaspi communication - // TODO implement these else if (callback instanceof CertStoreCallback) { + // TODO implement this } else if (callback instanceof PrivateKeyCallback) { + // TODO implement this } else if (callback instanceof SecretKeyCallback) { + // TODO implement this } else if (callback instanceof TrustStoreCallback) { + // TODO implement this } else { diff --git a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/SimpleAuthConfig.java b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/SimpleAuthConfig.java index 59144cf4697..27d623f6ede 100644 --- a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/SimpleAuthConfig.java +++ b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/SimpleAuthConfig.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,7 +19,6 @@ package org.eclipse.jetty.security.jaspi; import java.util.Map; - import javax.security.auth.Subject; import javax.security.auth.message.AuthException; import javax.security.auth.message.MessageInfo; @@ -73,7 +72,7 @@ public class SimpleAuthConfig implements ServerAuthConfig } @Override - public void refresh() + public void refresh() { } } diff --git a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/callback/CredentialValidationCallback.java b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/callback/CredentialValidationCallback.java index 46ef40c413b..e2e1a318901 100644 --- a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/callback/CredentialValidationCallback.java +++ b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/callback/CredentialValidationCallback.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,7 +16,6 @@ // ======================================================================== // - package org.eclipse.jetty.security.jaspi.callback; import javax.security.auth.Subject; @@ -36,44 +35,41 @@ public class CredentialValidationCallback implements Callback private boolean _result; private Subject _subject; private String _userName; - - - public CredentialValidationCallback (Subject subject, String userName, Credential credential) + + public CredentialValidationCallback(Subject subject, String userName, Credential credential) { _subject = subject; _userName = userName; _credential = credential; } - - public Credential getCredential () + + public Credential getCredential() { return _credential; } - - public void clearCredential () + + public void clearCredential() { _credential = null; - } - + } + public boolean getResult() { return _result; } - + public javax.security.auth.Subject getSubject() { return _subject; } - + public java.lang.String getUsername() { - return _userName; + return _userName; } - + public void setResult(boolean result) { _result = result; } - - } diff --git a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/callback/package-info.java b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/callback/package-info.java index 67caf38f201..750d5502692 100644 --- a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/callback/package-info.java +++ b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/callback/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/BaseAuthModule.java b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/BaseAuthModule.java index 4f6c7e0d05c..3a7bf1487a5 100644 --- a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/BaseAuthModule.java +++ b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/BaseAuthModule.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,9 +20,9 @@ package org.eclipse.jetty.security.jaspi.modules; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.util.Base64; import java.util.Map; import java.util.Set; - import javax.security.auth.Subject; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; @@ -41,13 +41,12 @@ import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.security.authentication.LoginCallbackImpl; import org.eclipse.jetty.security.jaspi.JaspiMessageInfo; import org.eclipse.jetty.security.jaspi.callback.CredentialValidationCallback; -import org.eclipse.jetty.util.B64Code; import org.eclipse.jetty.util.security.Credential; import org.eclipse.jetty.util.security.Password; public class BaseAuthModule implements ServerAuthModule, ServerAuthContext { - private static final Class[] SUPPORTED_MESSAGE_TYPES = new Class[] { HttpServletRequest.class, HttpServletResponse.class }; + private static final Class[] SUPPORTED_MESSAGE_TYPES = new Class[]{HttpServletRequest.class, HttpServletResponse.class}; protected static final String LOGIN_SERVICE_KEY = "org.eclipse.jetty.security.jaspi.modules.LoginService"; @@ -110,30 +109,31 @@ public class BaseAuthModule implements ServerAuthModule, ServerAuthContext */ protected boolean isMandatory(MessageInfo messageInfo) { - String mandatory = (String) messageInfo.getMap().get(JaspiMessageInfo.MANDATORY_KEY); - if (mandatory == null) return false; + String mandatory = (String)messageInfo.getMap().get(JaspiMessageInfo.MANDATORY_KEY); + if (mandatory == null) + return false; return Boolean.parseBoolean(mandatory); } - protected boolean login(Subject clientSubject, String credentials, - String authMethod, MessageInfo messageInfo) - throws IOException, UnsupportedCallbackException + protected boolean login(Subject clientSubject, String credentials, + String authMethod, MessageInfo messageInfo) + throws IOException, UnsupportedCallbackException { - credentials = credentials.substring(credentials.indexOf(' ')+1); - credentials = B64Code.decode(credentials, StandardCharsets.ISO_8859_1); + credentials = credentials.substring(credentials.indexOf(' ') + 1); + credentials = new String(Base64.getDecoder().decode(credentials), StandardCharsets.ISO_8859_1); int i = credentials.indexOf(':'); - String userName = credentials.substring(0,i); - String password = credentials.substring(i+1); + String userName = credentials.substring(0, i); + String password = credentials.substring(i + 1); return login(clientSubject, userName, new Password(password), authMethod, messageInfo); } - protected boolean login(Subject clientSubject, String username, - Credential credential, String authMethod, - MessageInfo messageInfo) - throws IOException, UnsupportedCallbackException + protected boolean login(Subject clientSubject, String username, + Credential credential, String authMethod, + MessageInfo messageInfo) + throws IOException, UnsupportedCallbackException { CredentialValidationCallback credValidationCallback = new CredentialValidationCallback(clientSubject, username, credential); - callbackHandler.handle(new Callback[] { credValidationCallback }); + callbackHandler.handle(new Callback[]{credValidationCallback}); if (credValidationCallback.getResult()) { Set loginCallbacks = clientSubject.getPrivateCredentials(LoginCallbackImpl.class); @@ -142,11 +142,10 @@ public class BaseAuthModule implements ServerAuthModule, ServerAuthContext LoginCallbackImpl loginCallback = loginCallbacks.iterator().next(); CallerPrincipalCallback callerPrincipalCallback = new CallerPrincipalCallback(clientSubject, loginCallback.getUserPrincipal()); GroupPrincipalCallback groupPrincipalCallback = new GroupPrincipalCallback(clientSubject, loginCallback.getRoles()); - callbackHandler.handle(new Callback[] { callerPrincipalCallback, groupPrincipalCallback }); + callbackHandler.handle(new Callback[]{callerPrincipalCallback, groupPrincipalCallback}); } messageInfo.getMap().put(JaspiMessageInfo.AUTH_METHOD_KEY, authMethod); } return credValidationCallback.getResult(); - } } diff --git a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/BasicAuthModule.java b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/BasicAuthModule.java index a973dbf3900..16ed2106783 100644 --- a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/BasicAuthModule.java +++ b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/BasicAuthModule.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,7 +20,6 @@ package org.eclipse.jetty.security.jaspi.modules; import java.io.IOException; import java.util.Map; - import javax.security.auth.Subject; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.UnsupportedCallbackException; @@ -41,7 +40,6 @@ public class BasicAuthModule extends BaseAuthModule { private static final Logger LOG = Log.getLogger(BasicAuthModule.class); - private String realmName; private static final String REALM_KEY = "org.eclipse.jetty.security.jaspi.modules.RealmName"; @@ -57,33 +55,39 @@ public class BasicAuthModule extends BaseAuthModule } @Override - public void initialize(MessagePolicy requestPolicy, MessagePolicy responsePolicy, - CallbackHandler handler, Map options) - throws AuthException + public void initialize(MessagePolicy requestPolicy, MessagePolicy responsePolicy, + CallbackHandler handler, Map options) + throws AuthException { super.initialize(requestPolicy, responsePolicy, handler, options); - realmName = (String) options.get(REALM_KEY); + realmName = (String)options.get(REALM_KEY); } @Override - public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, - Subject serviceSubject) - throws AuthException + public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, + Subject serviceSubject) + throws AuthException { - HttpServletRequest request = (HttpServletRequest) messageInfo.getRequestMessage(); - HttpServletResponse response = (HttpServletResponse) messageInfo.getResponseMessage(); + HttpServletRequest request = (HttpServletRequest)messageInfo.getRequestMessage(); + HttpServletResponse response = (HttpServletResponse)messageInfo.getResponseMessage(); String credentials = request.getHeader(HttpHeader.AUTHORIZATION.asString()); try { if (credentials != null) { - if (LOG.isDebugEnabled()) LOG.debug("Credentials: " + credentials); - if (login(clientSubject, credentials, Constraint.__BASIC_AUTH, messageInfo)) { return AuthStatus.SUCCESS; } - + if (LOG.isDebugEnabled()) + LOG.debug("Credentials: " + credentials); + if (login(clientSubject, credentials, Constraint.__BASIC_AUTH, messageInfo)) + { + return AuthStatus.SUCCESS; + } } - if (!isMandatory(messageInfo)) { return AuthStatus.SUCCESS; } + if (!isMandatory(messageInfo)) + { + return AuthStatus.SUCCESS; + } response.setHeader(HttpHeader.WWW_AUTHENTICATE.asString(), "basic realm=\"" + realmName + '"'); response.sendError(HttpServletResponse.SC_UNAUTHORIZED); return AuthStatus.SEND_CONTINUE; @@ -96,6 +100,5 @@ public class BasicAuthModule extends BaseAuthModule { throw new AuthException(e.getMessage()); } - } } diff --git a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/ClientCertAuthModule.java b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/ClientCertAuthModule.java index 097b8d4d780..0e5d8fce815 100644 --- a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/ClientCertAuthModule.java +++ b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/ClientCertAuthModule.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,7 +20,7 @@ package org.eclipse.jetty.security.jaspi.modules; import java.io.IOException; import java.security.Principal; - +import java.util.Base64; import javax.security.auth.Subject; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.UnsupportedCallbackException; @@ -30,7 +30,6 @@ import javax.security.auth.message.MessageInfo; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.eclipse.jetty.util.B64Code; import org.eclipse.jetty.util.security.Constraint; import org.eclipse.jetty.util.security.Password; @@ -48,13 +47,13 @@ public class ClientCertAuthModule extends BaseAuthModule } @Override - public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, - Subject serviceSubject) - throws AuthException + public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, + Subject serviceSubject) + throws AuthException { - HttpServletRequest request = (HttpServletRequest) messageInfo.getRequestMessage(); - HttpServletResponse response = (HttpServletResponse) messageInfo.getResponseMessage(); - java.security.cert.X509Certificate[] certs = (java.security.cert.X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate"); + HttpServletRequest request = (HttpServletRequest)messageInfo.getRequestMessage(); + HttpServletResponse response = (HttpServletResponse)messageInfo.getResponseMessage(); + java.security.cert.X509Certificate[] certs = (java.security.cert.X509Certificate[])request.getAttribute("javax.servlet.request.X509Certificate"); try { @@ -62,19 +61,26 @@ public class ClientCertAuthModule extends BaseAuthModule if (certs == null || certs.length == 0 || certs[0] == null) { response.sendError(HttpServletResponse.SC_FORBIDDEN, - "A client certificate is required for accessing this web application but the server's listener is not configured for mutual authentication (or the client did not provide a certificate)."); + "A client certificate is required for accessing this web application but the server's listener is not configured for mutual authentication (or the client did not provide a certificate)."); return AuthStatus.SEND_FAILURE; } Principal principal = certs[0].getSubjectDN(); - if (principal == null) principal = certs[0].getIssuerDN(); + if (principal == null) + principal = certs[0].getIssuerDN(); final String username = principal == null ? "clientcert" : principal.getName(); // TODO no idea if this is correct - final String password = new String(B64Code.encode(certs[0].getSignature())); + final String password = Base64.getEncoder().encodeToString(certs[0].getSignature()); // TODO is cert_auth correct? - if (login(clientSubject, username, new Password(password), Constraint.__CERT_AUTH, messageInfo)) { return AuthStatus.SUCCESS; } + if (login(clientSubject, username, new Password(password), Constraint.__CERT_AUTH, messageInfo)) + { + return AuthStatus.SUCCESS; + } - if (!isMandatory(messageInfo)) { return AuthStatus.SUCCESS; } + if (!isMandatory(messageInfo)) + { + return AuthStatus.SUCCESS; + } response.sendError(HttpServletResponse.SC_FORBIDDEN, "The provided client certificate does not correspond to a trusted user."); return AuthStatus.SEND_FAILURE; } @@ -86,6 +92,5 @@ public class ClientCertAuthModule extends BaseAuthModule { throw new AuthException(e.getMessage()); } - } } diff --git a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/DigestAuthModule.java b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/DigestAuthModule.java index b7287367e59..a718910cf5f 100644 --- a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/DigestAuthModule.java +++ b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/DigestAuthModule.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -21,8 +21,8 @@ package org.eclipse.jetty.security.jaspi.modules; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; +import java.util.Base64; import java.util.Map; - import javax.security.auth.Subject; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.UnsupportedCallbackException; @@ -34,7 +34,6 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.http.HttpHeader; -import org.eclipse.jetty.util.B64Code; import org.eclipse.jetty.util.QuotedStringTokenizer; import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; @@ -68,21 +67,21 @@ public class DigestAuthModule extends BaseAuthModule } @Override - public void initialize(MessagePolicy requestPolicy, MessagePolicy responsePolicy, - CallbackHandler handler, Map options) - throws AuthException + public void initialize(MessagePolicy requestPolicy, MessagePolicy responsePolicy, + CallbackHandler handler, Map options) + throws AuthException { super.initialize(requestPolicy, responsePolicy, handler, options); - realmName = (String) options.get(REALM_KEY); + realmName = (String)options.get(REALM_KEY); } @Override - public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, - Subject serviceSubject) - throws AuthException + public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, + Subject serviceSubject) + throws AuthException { - HttpServletRequest request = (HttpServletRequest) messageInfo.getRequestMessage(); - HttpServletResponse response = (HttpServletResponse) messageInfo.getResponseMessage(); + HttpServletRequest request = (HttpServletRequest)messageInfo.getRequestMessage(); + HttpServletResponse response = (HttpServletResponse)messageInfo.getResponseMessage(); String credentials = request.getHeader(HttpHeader.AUTHORIZATION.asString()); try @@ -92,7 +91,8 @@ public class DigestAuthModule extends BaseAuthModule long timestamp = System.currentTimeMillis(); if (credentials != null) { - if (LOG.isDebugEnabled()) LOG.debug("Credentials: " + credentials); + if (LOG.isDebugEnabled()) + LOG.debug("Credentials: " + credentials); QuotedStringTokenizer tokenizer = new QuotedStringTokenizer(credentials, "=, ", true, false); final Digest digest = new Digest(request.getMethod()); String last = null; @@ -111,6 +111,7 @@ public class DigestAuthModule extends BaseAuthModule break; case ',': name = null; + break; case ' ': break; @@ -132,7 +133,8 @@ public class DigestAuthModule extends BaseAuthModule digest.qop = tok; else if ("uri".equalsIgnoreCase(name)) digest.uri = tok; - else if ("response".equalsIgnoreCase(name)) digest.response = tok; + else if ("response".equalsIgnoreCase(name)) + digest.response = tok; break; } } @@ -142,22 +144,26 @@ public class DigestAuthModule extends BaseAuthModule if (n > 0) { - if (login(clientSubject, digest.username, digest, Constraint.__DIGEST_AUTH, messageInfo)) { return AuthStatus.SUCCESS; } + if (login(clientSubject, digest.username, digest, Constraint.__DIGEST_AUTH, messageInfo)) + { + return AuthStatus.SUCCESS; + } } - else if (n == 0) stale = true; - + else if (n == 0) + stale = true; } - if (!isMandatory(messageInfo)) { return AuthStatus.SUCCESS; } + if (!isMandatory(messageInfo)) + { + return AuthStatus.SUCCESS; + } String domain = request.getContextPath(); - if (domain == null) domain = "/"; - response.setHeader(HttpHeader.WWW_AUTHENTICATE.asString(), "Digest realm=\"" + realmName - + "\", domain=\"" - + domain - + "\", nonce=\"" - + newNonce(timestamp) - + "\", algorithm=MD5, qop=\"auth\"" - + (useStale ? (" stale=" + stale) : "")); + if (domain == null) + domain = "/"; + response.setHeader(HttpHeader.WWW_AUTHENTICATE.asString(), "Digest realm=\"" + realmName + + "\", domain=\"" + domain + + "\", nonce=\"" + newNonce(timestamp) + + "\", algorithm=MD5, qop=\"auth\"" + (useStale ? (" stale=" + stale) : "")); response.sendError(HttpServletResponse.SC_UNAUTHORIZED); return AuthStatus.SEND_CONTINUE; } @@ -169,7 +175,6 @@ public class DigestAuthModule extends BaseAuthModule { throw new AuthException(e.getMessage()); } - } public String newNonce(long ts) @@ -180,9 +185,9 @@ public class DigestAuthModule extends BaseAuthModule byte[] nounce = new byte[24]; for (int i = 0; i < 8; i++) { - nounce[i] = (byte) (ts & 0xff); + nounce[i] = (byte)(ts & 0xff); ts = ts >> 8; - nounce[8 + i] = (byte) (sk & 0xff); + nounce[8 + i] = (byte)(sk & 0xff); sk = sk >> 8; } @@ -202,10 +207,11 @@ public class DigestAuthModule extends BaseAuthModule for (int i = 0; i < hash.length; i++) { nounce[8 + i] = hash[i]; - if (i == 23) break; + if (i == 23) + break; } - return new String(B64Code.encode(nounce)); + return Base64.getEncoder().encodeToString(nounce); } /** @@ -217,8 +223,9 @@ public class DigestAuthModule extends BaseAuthModule { try { - byte[] n = B64Code.decode(nonce.toCharArray()); - if (n.length != 24) return -1; + byte[] n = Base64.getDecoder().decode(nonce); + if (n.length != 24) + return -1; long ts = 0; long sk = nonceSecret; @@ -226,13 +233,14 @@ public class DigestAuthModule extends BaseAuthModule System.arraycopy(n, 0, n2, 0, 8); for (int i = 0; i < 8; i++) { - n2[8 + i] = (byte) (sk & 0xff); + n2[8 + i] = (byte)(sk & 0xff); sk = sk >> 8; - ts = (ts << 8) + (0xff & (long) n[7 - i]); + ts = (ts << 8) + (0xff & (long)n[7 - i]); } long age = timestamp - ts; - if (LOG.isDebugEnabled()) LOG.debug("age=" + age); + if (LOG.isDebugEnabled()) + LOG.debug("age=" + age); byte[] hash = null; try @@ -248,9 +256,13 @@ public class DigestAuthModule extends BaseAuthModule } for (int i = 0; i < 16; i++) - if (n[i + 8] != hash[i]) return -1; + { + if (n[i + 8] != hash[i]) + return -1; + } - if (maxNonceAge > 0 && (age < 0 || age > maxNonceAge)) return 0; // stale + if (maxNonceAge > 0 && (age < 0 || age > maxNonceAge)) + return 0; // stale return 1; } @@ -275,17 +287,15 @@ public class DigestAuthModule extends BaseAuthModule String uri = null; String response = null; - /* ------------------------------------------------------------ */ Digest(String m) { method = m; } - /* ------------------------------------------------------------ */ @Override public boolean check(Object credentials) { - String password = (credentials instanceof String) ? (String) credentials : credentials.toString(); + String password = (credentials instanceof String) ? (String)credentials : credentials.toString(); try { @@ -296,22 +306,22 @@ public class DigestAuthModule extends BaseAuthModule // Credentials are already a MD5 digest - assume it's in // form user:realm:password (we have no way to know since // it's a digest, alright?) - ha1 = ((Credential.MD5) credentials).getDigest(); + ha1 = ((Credential.MD5)credentials).getDigest(); } else { // calc A1 digest md.update(username.getBytes(StandardCharsets.ISO_8859_1)); - md.update((byte) ':'); + md.update((byte)':'); md.update(realm.getBytes(StandardCharsets.ISO_8859_1)); - md.update((byte) ':'); + md.update((byte)':'); md.update(password.getBytes(StandardCharsets.ISO_8859_1)); ha1 = md.digest(); } // calc A2 digest md.reset(); md.update(method.getBytes(StandardCharsets.ISO_8859_1)); - md.update((byte) ':'); + md.update((byte)':'); md.update(uri.getBytes(StandardCharsets.ISO_8859_1)); byte[] ha2 = md.digest(); @@ -323,15 +333,15 @@ public class DigestAuthModule extends BaseAuthModule // ) > <"> md.update(TypeUtil.toString(ha1, 16).getBytes(StandardCharsets.ISO_8859_1)); - md.update((byte) ':'); + md.update((byte)':'); md.update(nonce.getBytes(StandardCharsets.ISO_8859_1)); - md.update((byte) ':'); + md.update((byte)':'); md.update(nc.getBytes(StandardCharsets.ISO_8859_1)); - md.update((byte) ':'); + md.update((byte)':'); md.update(cnonce.getBytes(StandardCharsets.ISO_8859_1)); - md.update((byte) ':'); + md.update((byte)':'); md.update(qop.getBytes(StandardCharsets.ISO_8859_1)); - md.update((byte) ':'); + md.update((byte)':'); md.update(TypeUtil.toString(ha2, 16).getBytes(StandardCharsets.ISO_8859_1)); byte[] digest = md.digest(); diff --git a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/FormAuthModule.java b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/FormAuthModule.java index 6e7118acfc1..6370c75dfcc 100644 --- a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/FormAuthModule.java +++ b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/FormAuthModule.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -21,7 +21,6 @@ package org.eclipse.jetty.security.jaspi.modules; import java.io.IOException; import java.util.Map; import java.util.Set; - import javax.security.auth.Subject; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.UnsupportedCallbackException; @@ -49,16 +48,15 @@ public class FormAuthModule extends BaseAuthModule { private static final Logger LOG = Log.getLogger(FormAuthModule.class); - /* ------------------------------------------------------------ */ - public final static String __J_URI = "org.eclipse.jetty.util.URI"; + public static final String __J_URI = "org.eclipse.jetty.util.URI"; - public final static String __J_AUTHENTICATED = "org.eclipse.jetty.server.Auth"; + public static final String __J_AUTHENTICATED = "org.eclipse.jetty.server.Auth"; - public final static String __J_SECURITY_CHECK = "/j_security_check"; + public static final String __J_SECURITY_CHECK = "/j_security_check"; - public final static String __J_USERNAME = "j_username"; + public static final String __J_USERNAME = "j_username"; - public final static String __J_PASSWORD = "j_password"; + public static final String __J_PASSWORD = "j_password"; // private String realmName; public static final String LOGIN_PAGE_KEY = "org.eclipse.jetty.security.jaspi.modules.LoginPage"; @@ -75,7 +73,6 @@ public class FormAuthModule extends BaseAuthModule private String _formLoginPath; - public FormAuthModule() { } @@ -87,15 +84,14 @@ public class FormAuthModule extends BaseAuthModule setErrorPage(errorPage); } - @Override - public void initialize(MessagePolicy requestPolicy, MessagePolicy responsePolicy, - CallbackHandler handler, Map options) - throws AuthException + public void initialize(MessagePolicy requestPolicy, MessagePolicy responsePolicy, + CallbackHandler handler, Map options) + throws AuthException { super.initialize(requestPolicy, responsePolicy, handler, options); - setLoginPage((String) options.get(LOGIN_PAGE_KEY)); - setErrorPage((String) options.get(ERROR_PAGE_KEY)); + setLoginPage((String)options.get(LOGIN_PAGE_KEY)); + setErrorPage((String)options.get(ERROR_PAGE_KEY)); } private void setLoginPage(String path) @@ -107,10 +103,10 @@ public class FormAuthModule extends BaseAuthModule } _formLoginPage = path; _formLoginPath = path; - if (_formLoginPath.indexOf('?') > 0) _formLoginPath = _formLoginPath.substring(0, _formLoginPath.indexOf('?')); + if (_formLoginPath.indexOf('?') > 0) + _formLoginPath = _formLoginPath.substring(0, _formLoginPath.indexOf('?')); } - /* ------------------------------------------------------------ */ private void setErrorPage(String path) { if (path == null || path.trim().length() == 0) @@ -128,26 +124,27 @@ public class FormAuthModule extends BaseAuthModule _formErrorPage = path; _formErrorPath = path; - if (_formErrorPath.indexOf('?') > 0) _formErrorPath = _formErrorPath.substring(0, _formErrorPath.indexOf('?')); + if (_formErrorPath.indexOf('?') > 0) + _formErrorPath = _formErrorPath.substring(0, _formErrorPath.indexOf('?')); } } @Override public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, Subject serviceSubject) throws AuthException { - - HttpServletRequest request = (HttpServletRequest) messageInfo.getRequestMessage(); - HttpServletResponse response = (HttpServletResponse) messageInfo.getResponseMessage(); + + HttpServletRequest request = (HttpServletRequest)messageInfo.getRequestMessage(); + HttpServletResponse response = (HttpServletResponse)messageInfo.getResponseMessage(); String uri = request.getRequestURI(); - if (uri==null) - uri=URIUtil.SLASH; - - boolean mandatory = isMandatory(messageInfo); + if (uri == null) + uri = URIUtil.SLASH; + + boolean mandatory = isMandatory(messageInfo); mandatory |= isJSecurityCheck(uri); HttpSession session = request.getSession(mandatory); - + // not mandatory or its the login or login error page don't authenticate - if (!mandatory || isLoginOrErrorPage(URIUtil.addPaths(request.getServletPath(),request.getPathInfo()))) + if (!mandatory || isLoginOrErrorPage(URIUtil.addPaths(request.getServletPath(), request.getPathInfo()))) return AuthStatus.SUCCESS; // TODO return null for do nothing? try @@ -157,33 +154,35 @@ public class FormAuthModule extends BaseAuthModule { final String username = request.getParameter(__J_USERNAME); final String password = request.getParameter(__J_PASSWORD); - + boolean success = tryLogin(messageInfo, clientSubject, response, session, username, new Password(password)); if (success) { // Redirect to original request - String nuri=null; - synchronized(session) + String nuri = null; + synchronized (session) { - nuri = (String) session.getAttribute(__J_URI); + nuri = (String)session.getAttribute(__J_URI); } - + if (nuri == null || nuri.length() == 0) { nuri = request.getContextPath(); - if (nuri.length() == 0) + if (nuri.length() == 0) nuri = URIUtil.SLASH; } - - response.setContentLength(0); + + response.setContentLength(0); response.sendRedirect(response.encodeRedirectURL(nuri)); return AuthStatus.SEND_CONTINUE; } // not authenticated - if (LOG.isDebugEnabled()) LOG.debug("Form authentication FAILED for " + StringUtil.printable(username)); + if (LOG.isDebugEnabled()) + LOG.debug("Form authentication FAILED for " + StringUtil.printable(username)); if (_formErrorPage == null) { - if (response != null) response.sendError(HttpServletResponse.SC_FORBIDDEN); + if (response != null) + response.sendError(HttpServletResponse.SC_FORBIDDEN); } else { @@ -194,12 +193,11 @@ public class FormAuthModule extends BaseAuthModule // that occur? return AuthStatus.SEND_FAILURE; } - - + // Check if the session is already authenticated. SessionAuthentication sessionAuth = (SessionAuthentication)session.getAttribute(SessionAuthentication.__J_AUTHENTICATED); if (sessionAuth != null) - { + { //TODO: ideally we would like the form auth module to be able to invoke the //loginservice.validate() method to check the previously authed user, but it is not visible //to FormAuthModule @@ -213,14 +211,12 @@ public class FormAuthModule extends BaseAuthModule clientSubject.getPrivateCredentials().addAll(credentials); clientSubject.getPrivateCredentials().add(sessionAuth.getUserIdentity()); - return AuthStatus.SUCCESS; + return AuthStatus.SUCCESS; } - // if we can't send challenge if (DeferredAuthentication.isDeferred(response)) - return AuthStatus.SUCCESS; - + return AuthStatus.SUCCESS; // redirect to login page StringBuffer buf = request.getRequestURL(); @@ -231,7 +227,7 @@ public class FormAuthModule extends BaseAuthModule { session.setAttribute(__J_URI, buf.toString()); } - + response.setContentLength(0); response.sendRedirect(response.encodeRedirectURL(URIUtil.addPaths(request.getContextPath(), _formLoginPage))); return AuthStatus.SEND_CONTINUE; @@ -244,33 +240,31 @@ public class FormAuthModule extends BaseAuthModule { throw new AuthException(e.getMessage()); } - } - - /* ------------------------------------------------------------ */ + public boolean isJSecurityCheck(String uri) { int jsc = uri.indexOf(__J_SECURITY_CHECK); - - if (jsc<0) + + if (jsc < 0) return false; - int e=jsc+__J_SECURITY_CHECK.length(); - if (e==uri.length()) + int e = jsc + __J_SECURITY_CHECK.length(); + if (e == uri.length()) return true; char c = uri.charAt(e); - return c==';'||c=='#'||c=='/'||c=='?'; + return c == ';' || c == '#' || c == '/' || c == '?'; } - private boolean tryLogin(MessageInfo messageInfo, Subject clientSubject, - HttpServletResponse response, HttpSession session, - String username, Password password) - throws AuthException, IOException, UnsupportedCallbackException + private boolean tryLogin(MessageInfo messageInfo, Subject clientSubject, + HttpServletResponse response, HttpSession session, + String username, Password password) + throws AuthException, IOException, UnsupportedCallbackException { if (login(clientSubject, username, password, Constraint.__FORM_AUTH, messageInfo)) { char[] pwdChars = password.toString().toCharArray(); Set loginCallbacks = clientSubject.getPrivateCredentials(LoginCallbackImpl.class); - + if (!loginCallbacks.isEmpty()) { LoginCallbackImpl loginCallback = loginCallbacks.iterator().next(); @@ -278,9 +272,9 @@ public class FormAuthModule extends BaseAuthModule if (!userIdentities.isEmpty()) { UserIdentity userIdentity = userIdentities.iterator().next(); - - SessionAuthentication sessionAuth = new SessionAuthentication(Constraint.__FORM_AUTH, userIdentity, password); - session.setAttribute(SessionAuthentication.__J_AUTHENTICATED, sessionAuth); + + SessionAuthentication sessionAuth = new SessionAuthentication(Constraint.__FORM_AUTH, userIdentity, password); + session.setAttribute(SessionAuthentication.__J_AUTHENTICATED, sessionAuth); } } @@ -293,5 +287,4 @@ public class FormAuthModule extends BaseAuthModule { return pathInContext != null && (pathInContext.equals(_formErrorPath) || pathInContext.equals(_formLoginPath)); } - } diff --git a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/UserInfo.java b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/UserInfo.java index 9e7e8aaa6a4..d7c7ea99bfe 100644 --- a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/UserInfo.java +++ b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/UserInfo.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -44,7 +44,7 @@ public class UserInfo public void clearPassword() { - Arrays.fill(password, (char) 0); + Arrays.fill(password, (char)0); password = null; } } diff --git a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/package-info.java b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/package-info.java index 87f4ad3cb74..eae72c4f105 100644 --- a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/package-info.java +++ b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/package-info.java b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/package-info.java index b50f5d0410a..f907bd3fd87 100644 --- a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/package-info.java +++ b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-jaspi/src/test/java/org/eclipse/jetty/security/jaspi/HttpHeaderAuthModule.java b/jetty-jaspi/src/test/java/org/eclipse/jetty/security/jaspi/HttpHeaderAuthModule.java index 1435f40324d..5e86d7cf545 100644 --- a/jetty-jaspi/src/test/java/org/eclipse/jetty/security/jaspi/HttpHeaderAuthModule.java +++ b/jetty-jaspi/src/test/java/org/eclipse/jetty/security/jaspi/HttpHeaderAuthModule.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,7 +19,6 @@ package org.eclipse.jetty.security.jaspi; import java.util.Map; - import javax.security.auth.Subject; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; @@ -43,7 +42,7 @@ public class HttpHeaderAuthModule implements ServerAuthModule * Supported message types. For our case we only need to deal with HTTP servlet request and responses. On Java EE 7 this will handle WebSockets as well. */ private static final Class[] SUPPORTED_MESSAGE_TYPES = new Class[] - { HttpServletRequest.class, HttpServletResponse.class }; + {HttpServletRequest.class, HttpServletResponse.class}; /** * Callback handler that is passed in initialize by the container. This processes the callbacks which are objects that populate the "subject". @@ -67,15 +66,11 @@ public class HttpHeaderAuthModule implements ServerAuthModule /** * Initializes the module. Allows you to pass in options. - * - * @param requestPolicy - * request policy, ignored - * @param responsePolicy - * response policy, ignored - * @param h - * callback handler - * @param options - * options + * + * @param requestPolicy request policy, ignored + * @param responsePolicy response policy, ignored + * @param h callback handler + * @param options options */ @Override public void initialize(final MessagePolicy requestPolicy, MessagePolicy responsePolicy, CallbackHandler h, Map options) throws AuthException @@ -112,8 +107,10 @@ public class HttpHeaderAuthModule implements ServerAuthModule // Store the user name that was in the header and also set a group. handler.handle(new Callback[] - { new CallerPrincipalCallback(client,userName), new GroupPrincipalCallback(client,new String[] - { "users" }) }); + { + new CallerPrincipalCallback(client, userName), new GroupPrincipalCallback(client, new String[] + {"users"}) + }); return AuthStatus.SUCCESS; } catch (final Exception e) @@ -121,5 +118,4 @@ public class HttpHeaderAuthModule implements ServerAuthModule throw new AuthException(e.getMessage()); } } - } diff --git a/jetty-jaspi/src/test/java/org/eclipse/jetty/security/jaspi/JaspiTest.java b/jetty-jaspi/src/test/java/org/eclipse/jetty/security/jaspi/JaspiTest.java index e874681a291..5b0890de3af 100644 --- a/jetty-jaspi/src/test/java/org/eclipse/jetty/security/jaspi/JaspiTest.java +++ b/jetty-jaspi/src/test/java/org/eclipse/jetty/security/jaspi/JaspiTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,13 +18,10 @@ package org.eclipse.jetty.security.jaspi; -import static org.hamcrest.Matchers.startsWith; -import static org.hamcrest.MatcherAssert.assertThat; - import java.io.IOException; +import java.util.Base64; import java.util.HashMap; import java.util.Map; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -38,7 +35,6 @@ import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandlerCollection; -import org.eclipse.jetty.util.B64Code; import org.eclipse.jetty.util.security.Constraint; import org.eclipse.jetty.util.security.Credential; import org.eclipse.jetty.util.security.Password; @@ -47,39 +43,42 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import static java.nio.charset.StandardCharsets.ISO_8859_1; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.startsWith; + public class JaspiTest { Server _server; LocalConnector _connector; + public class TestLoginService extends AbstractLoginService { protected Map _users = new HashMap<>(); protected Map _roles = new HashMap(); - - public TestLoginService(String name) { setName(name); } - public void putUser (String username, Credential credential, String[] roles) + public void putUser(String username, Credential credential, String[] roles) { - UserPrincipal userPrincipal = new UserPrincipal(username,credential); + UserPrincipal userPrincipal = new UserPrincipal(username, credential); _users.put(username, userPrincipal); _roles.put(username, roles); } - - /** + + /** * @see org.eclipse.jetty.security.AbstractLoginService#loadRoleInfo(org.eclipse.jetty.security.AbstractLoginService.UserPrincipal) */ @Override protected String[] loadRoleInfo(UserPrincipal user) { - return _roles.get(user.getName()); + return _roles.get(user.getName()); } - /** + /** * @see org.eclipse.jetty.security.AbstractLoginService#loadUserInfo(java.lang.String) */ @Override @@ -88,109 +87,111 @@ public class JaspiTest return _users.get(username); } } - + @BeforeEach public void before() throws Exception { - System.setProperty("org.apache.geronimo.jaspic.configurationFile","src/test/resources/jaspi.xml"); + System.setProperty("org.apache.geronimo.jaspic.configurationFile", "src/test/resources/jaspi.xml"); _server = new Server(); _connector = new LocalConnector(_server); _server.addConnector(_connector); - + ContextHandlerCollection contexts = new ContextHandlerCollection(); _server.setHandler(contexts); - + TestLoginService loginService = new TestLoginService("TestRealm"); - loginService.putUser("user",new Password("password"),new String[]{"users"}); - loginService.putUser("admin",new Password("secret"),new String[]{"users","admins"}); + loginService.putUser("user", new Password("password"), new String[]{"users"}); + loginService.putUser("admin", new Password("secret"), new String[]{"users", "admins"}); _server.addBean(loginService); - + ContextHandler context = new ContextHandler(); contexts.addHandler(context); context.setContextPath("/ctx"); - + JaspiAuthenticatorFactory jaspiAuthFactory = new JaspiAuthenticatorFactory(); - + ConstraintSecurityHandler security = new ConstraintSecurityHandler(); context.setHandler(security); security.setAuthenticatorFactory(jaspiAuthFactory); // security.setAuthenticator(new BasicAuthenticator()); - - Constraint constraint = new Constraint("All","users"); + + Constraint constraint = new Constraint("All", "users"); constraint.setAuthenticate(true); ConstraintMapping mapping = new ConstraintMapping(); mapping.setPathSpec("/jaspi/*"); mapping.setConstraint(constraint); security.addConstraintMapping(mapping); - + TestHandler handler = new TestHandler(); security.setHandler(handler); - + ContextHandler other = new ContextHandler(); contexts.addHandler(other); other.setContextPath("/other"); ConstraintSecurityHandler securityOther = new ConstraintSecurityHandler(); other.setHandler(securityOther); securityOther.setAuthenticatorFactory(jaspiAuthFactory); - securityOther.addConstraintMapping(mapping); + securityOther.addConstraintMapping(mapping); securityOther.setHandler(new TestHandler()); - + _server.start(); } - + @AfterEach public void after() throws Exception { _server.stop(); } - + @Test public void testNoConstraint() throws Exception { String response = _connector.getResponse("GET /ctx/test HTTP/1.0\n\n"); - assertThat(response,startsWith("HTTP/1.1 200 OK")); + assertThat(response, startsWith("HTTP/1.1 200 OK")); } - + @Test public void testConstraintNoAuth() throws Exception { String response = _connector.getResponse("GET /ctx/jaspi/test HTTP/1.0\n\n"); - assertThat(response,startsWith("HTTP/1.1 401 Unauthorized")); - assertThat(response,Matchers.containsString("WWW-Authenticate: basic realm=\"TestRealm\"")); + assertThat(response, startsWith("HTTP/1.1 401 Unauthorized")); + assertThat(response, Matchers.containsString("WWW-Authenticate: basic realm=\"TestRealm\"")); } - + @Test public void testConstraintWrongAuth() throws Exception { - String response = _connector.getResponse("GET /ctx/jaspi/test HTTP/1.0\n"+ - "Authorization: Basic " + B64Code.encode("user:wrong") + "\n\n"); - assertThat(response,startsWith("HTTP/1.1 401 Unauthorized")); - assertThat(response,Matchers.containsString("WWW-Authenticate: basic realm=\"TestRealm\"")); + String response = _connector.getResponse("GET /ctx/jaspi/test HTTP/1.0\n" + + "Authorization: Basic " + Base64.getEncoder().encodeToString("user:wrong".getBytes(ISO_8859_1)) + + "\n\n"); + assertThat(response, startsWith("HTTP/1.1 401 Unauthorized")); + assertThat(response, Matchers.containsString("WWW-Authenticate: basic realm=\"TestRealm\"")); } - + @Test public void testConstraintAuth() throws Exception { - String response = _connector.getResponse("GET /ctx/jaspi/test HTTP/1.0\n"+ - "Authorization: Basic " + B64Code.encode("user:password") + "\n\n"); - assertThat(response,startsWith("HTTP/1.1 200 OK")); + String response = _connector.getResponse("GET /ctx/jaspi/test HTTP/1.0\n" + + "Authorization: Basic " + Base64.getEncoder().encodeToString("user:password".getBytes(ISO_8859_1)) + + "\n\n"); + assertThat(response, startsWith("HTTP/1.1 200 OK")); } - + @Test public void testOtherNoAuth() throws Exception { String response = _connector.getResponse("GET /other/test HTTP/1.0\n\n"); - assertThat(response,startsWith("HTTP/1.1 403 Forbidden")); + assertThat(response, startsWith("HTTP/1.1 403 Forbidden")); } - + @Test public void testOtherAuth() throws Exception { - String response = _connector.getResponse("GET /other/test HTTP/1.0\n"+ - "X-Forwarded-User: user\n\n"); - assertThat(response,startsWith("HTTP/1.1 200 OK")); + String response = _connector.getResponse("GET /other/test HTTP/1.0\n" + + "X-Forwarded-User: user\n\n"); + assertThat(response, startsWith("HTTP/1.1 200 OK")); } - + public class TestHandler extends AbstractHandler { @@ -201,7 +202,7 @@ public class JaspiTest response.setStatus(200); response.setContentType("text/plain"); response.getWriter().println("All OK"); - response.getWriter().println("requestURI="+request.getRequestURI()); + response.getWriter().println("requestURI=" + request.getRequestURI()); } } } diff --git a/jetty-jmh/pom.xml b/jetty-jmh/pom.xml index 2e4b9719221..a5e23aa7596 100644 --- a/jetty-jmh/pom.xml +++ b/jetty-jmh/pom.xml @@ -2,13 +2,18 @@ org.eclipse.jetty jetty-project - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT + 4.0.0 jetty-jmh Jetty :: Jmh Jmh classes for Jetty - http://www.eclipse.org/jetty + + + ${project.groupId}.jmh + + @@ -39,8 +44,7 @@ ${jmhjar.name} true - + org.openjdk.jmh.Main @@ -72,6 +76,7 @@ + org.eclipse.jetty @@ -88,12 +93,6 @@ jetty-http ${project.version} - - org.eclipse.jetty - jetty-http - ${project.version} - tests - javax.servlet javax.servlet-api diff --git a/jetty-jmh/src/main/java/org/eclipse/jetty/http/jmh/MultiPartBenchmark.java b/jetty-jmh/src/main/java/org/eclipse/jetty/http/jmh/MultiPartBenchmark.java index 63136a3b57b..a6c35d7bdf5 100644 --- a/jetty-jmh/src/main/java/org/eclipse/jetty/http/jmh/MultiPartBenchmark.java +++ b/jetty-jmh/src/main/java/org/eclipse/jetty/http/jmh/MultiPartBenchmark.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,9 +18,33 @@ package org.eclipse.jetty.http.jmh; -import org.eclipse.jetty.http.MultiPartCaptureTest.MultipartExpectations; +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.security.DigestOutputStream; +import java.security.MessageDigest; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Locale; +import java.util.Objects; +import java.util.Random; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; +import javax.servlet.MultipartConfigElement; +import javax.servlet.http.Part; + import org.eclipse.jetty.http.MultiPartFormInputStream; -import org.eclipse.jetty.toolchain.test.IO; +import org.eclipse.jetty.toolchain.test.Hex; +import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.QuotedStringTokenizer; +import org.eclipse.jetty.util.StringUtil; +import org.hamcrest.Matchers; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Level; @@ -38,18 +62,11 @@ import org.openjdk.jmh.runner.RunnerException; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; -import javax.servlet.MultipartConfigElement; -import javax.servlet.http.Part; -import java.io.File; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardOpenOption; -import java.util.ArrayList; -import java.util.List; -import java.util.Random; -import java.util.concurrent.TimeUnit; +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; @State(Scope.Benchmark) @Threads(4) @@ -60,20 +77,19 @@ public class MultiPartBenchmark public static final int MAX_FILE_SIZE = Integer.MAX_VALUE; public static final int MAX_REQUEST_SIZE = Integer.MAX_VALUE; public static final int FILE_SIZE_THRESHOLD = 50; - + public int count = 0; static String _contentType; static File _file; static int _numSections; static int _numBytesPerSection; - - + public static List data = new ArrayList<>(); - + static { // Capture of raw request body contents from various browsers - + // simple form - 2 fields data.add("browser-capture-form1-android-chrome"); data.add("browser-capture-form1-android-firefox"); @@ -83,15 +99,15 @@ public class MultiPartBenchmark data.add("browser-capture-form1-ios-safari"); data.add("browser-capture-form1-msie"); data.add("browser-capture-form1-osx-safari"); - + // form submitted as shift-jis data.add("browser-capture-sjis-form-edge"); data.add("browser-capture-sjis-form-msie"); - + // form submitted as shift-jis (with HTML5 specific hidden _charset_ field) data.add("browser-capture-sjis-charset-form-edge"); data.add("browser-capture-sjis-charset-form-msie"); - + // form submitted with simple file upload data.add("browser-capture-form-fileupload-android-chrome"); data.add("browser-capture-form-fileupload-android-firefox"); @@ -101,7 +117,7 @@ public class MultiPartBenchmark data.add("browser-capture-form-fileupload-ios-safari"); data.add("browser-capture-form-fileupload-msie"); data.add("browser-capture-form-fileupload-safari"); - + // form submitted with 2 files (1 binary, 1 text) and 2 text fields data.add("browser-capture-form-fileupload-alt-chrome"); data.add("browser-capture-form-fileupload-alt-edge"); @@ -109,27 +125,25 @@ public class MultiPartBenchmark data.add("browser-capture-form-fileupload-alt-msie"); data.add("browser-capture-form-fileupload-alt-safari"); } - - + @Param({"UTIL", "HTTP"}) public static String parserType; - + @Setup(Level.Trial) public static void setupTrial() throws Exception { _file = File.createTempFile("test01", null); _file.deleteOnExit(); - + _numSections = 1; _numBytesPerSection = 1024 * 1024 * 10; - + _contentType = "multipart/form-data, boundary=WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW"; String initialBoundary = "--WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW\r\n"; String boundary = "\r\n--WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW\r\n"; String closingBoundary = "\r\n--WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW--\r\n"; String headerStart = "Content-Disposition: form-data; name=\""; - - + for (int i = 0; i < _numSections; i++) { //boundary and headers @@ -137,32 +151,31 @@ public class MultiPartBenchmark Files.write(_file.toPath(), initialBoundary.getBytes(), StandardOpenOption.APPEND); else Files.write(_file.toPath(), boundary.getBytes(), StandardOpenOption.APPEND); - + Files.write(_file.toPath(), headerStart.getBytes(), StandardOpenOption.APPEND); Files.write(_file.toPath(), ("part" + (i + 1)).getBytes(), StandardOpenOption.APPEND); Files.write(_file.toPath(), ("\"\r\n\r\n").getBytes(), StandardOpenOption.APPEND); - + //append random data byte[] data = new byte[_numBytesPerSection]; new Random().nextBytes(data); Files.write(_file.toPath(), data, StandardOpenOption.APPEND); } - + //closing boundary Files.write(_file.toPath(), closingBoundary.getBytes(), StandardOpenOption.APPEND); } - - + @Benchmark @BenchmarkMode({Mode.AverageTime}) @SuppressWarnings("deprecation") public long testLargeGenerated() throws Exception { Path multipartRawFile = _file.toPath(); - Path outputDir = new File("/tmp").toPath(); - + Path outputDir = Files.createTempDirectory("jetty_multipart_benchmark"); + MultipartConfigElement config = newMultipartConfigElement(outputDir); - + try (InputStream in = Files.newInputStream(multipartRawFile)) { switch (parserType) @@ -170,47 +183,56 @@ public class MultiPartBenchmark case "HTTP": { MultiPartFormInputStream parser = new MultiPartFormInputStream(in, _contentType, config, outputDir.toFile()); + parser.setDeleteOnExit(true); if (parser.getParts().size() != _numSections) throw new IllegalStateException("Incorrect Parsing"); for (Part p : parser.getParts()) { count += p.getSize(); + if (p instanceof MultiPartFormInputStream.MultiPart) + ((MultiPartFormInputStream.MultiPart)p).cleanUp(); + else + p.delete(); } + break; } - break; - + case "UTIL": { org.eclipse.jetty.util.MultiPartInputStreamParser parser = new org.eclipse.jetty.util.MultiPartInputStreamParser(in, _contentType, config, outputDir.toFile()); + parser.setDeleteOnExit(true); if (parser.getParts().size() != _numSections) throw new IllegalStateException("Incorrect Parsing"); for (Part p : parser.getParts()) { count += p.getSize(); + if (p instanceof org.eclipse.jetty.util.MultiPartInputStreamParser.MultiPart) + ((org.eclipse.jetty.util.MultiPartInputStreamParser.MultiPart)p).cleanUp(); + else + p.delete(); } + break; } - break; - + default: throw new IllegalStateException("Unknown parserType Parameter"); } } - + IO.delete(outputDir.toFile()); return count; } - - + @TearDown(Level.Trial) public static void stopTrial() throws Exception { _file = null; } - + private MultipartConfigElement newMultipartConfigElement(Path path) { return new MultipartConfigElement(path.toString(), MAX_FILE_SIZE, MAX_REQUEST_SIZE, FILE_SIZE_THRESHOLD); } - + @Benchmark @BenchmarkMode({Mode.AverageTime}) @SuppressWarnings("deprecation") @@ -218,65 +240,259 @@ public class MultiPartBenchmark { for (String multiPart : data) { - //Path multipartRawFile = MavenTestingUtils.getTestResourcePathFile("multipart/" + multiPart + ".raw"); String expectationPath = "multipart/" + multiPart + ".expected.txt"; - //Path expectationPath = MavenTestingUtils.getTestResourcePathFile("multipart/" + multiPart + ".expected.txt"); - File expectationFile = File.createTempFile( expectationPath, ".tmp" ); + File expectationFile = File.createTempFile(expectationPath, ".tmp"); - try(InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(expectationPath); - OutputStream os = Files.newOutputStream( expectationFile.toPath() )) { - IO.copy( inputStream, os ); + try (InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(expectationPath); + // + OutputStream os = Files.newOutputStream(expectationFile.toPath())) + { + IO.copy(inputStream, os); } - Path outputDir = Files.createTempDirectory( "expected_output_jmh_jetty" );// new File("/tmp").toPath(); - + Path outputDir = Files.createTempDirectory("expected_output_jmh_jetty"); + MultipartExpectations multipartExpectations = new MultipartExpectations(expectationFile.toPath()); MultipartConfigElement config = newMultipartConfigElement(outputDir); - - try (InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream( "multipart/" + multiPart + ".raw" )) + + try (InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("multipart/" + multiPart + ".raw")) { switch (parserType) { case "HTTP": { MultiPartFormInputStream parser = new MultiPartFormInputStream(in, multipartExpectations.contentType, config, outputDir.toFile()); + parser.setDeleteOnExit(true); for (Part p : parser.getParts()) { count += p.getSize(); + if (p instanceof MultiPartFormInputStream.MultiPart) + ((MultiPartFormInputStream.MultiPart)p).cleanUp(); + else + p.delete(); } + break; } - break; case "UTIL": { org.eclipse.jetty.util.MultiPartInputStreamParser parser = new org.eclipse.jetty.util.MultiPartInputStreamParser(in, multipartExpectations.contentType, config, outputDir.toFile()); + parser.setDeleteOnExit(true); for (Part p : parser.getParts()) { count += p.getSize(); + if (p instanceof org.eclipse.jetty.util.MultiPartInputStreamParser.MultiPart) + ((org.eclipse.jetty.util.MultiPartInputStreamParser.MultiPart)p).cleanUp(); + else + p.delete(); } + break; } - break; default: throw new IllegalStateException("Unknown parserType Parameter"); } } - + Files.deleteIfExists(expectationFile.toPath()); + IO.delete(outputDir.toFile()); } return count; } - + public static void main(String[] args) throws RunnerException { Options opt = new OptionsBuilder() - .include(MultiPartBenchmark.class.getSimpleName()) - .warmupIterations(20) - .measurementIterations(10) - .forks(1) - .threads(1) - .build(); - + .include(MultiPartBenchmark.class.getSimpleName()) + .warmupIterations(20) + .measurementIterations(10) + .forks(1) + .threads(1) + .build(); + new Runner(opt).run(); } + + public static class MultipartExpectations + { + public final String contentType; + public final int partCount; + public final List partFilenames = new ArrayList<>(); + public final List partSha1sums = new ArrayList<>(); + public final List partContainsContents = new ArrayList<>(); + + public MultipartExpectations(Path expectationsPath) throws IOException + { + String parsedContentType = null; + String parsedPartCount = "-1"; + + try (BufferedReader reader = Files.newBufferedReader(expectationsPath)) + { + String line; + while ((line = reader.readLine()) != null) + { + line = line.trim(); + if (StringUtil.isBlank(line) || line.startsWith("#")) + { + // skip blanks and comments + continue; + } + + String[] split = line.split("\\|"); + switch (split[0]) + { + case "Request-Header": + if (split[1].equalsIgnoreCase("Content-Type")) + { + parsedContentType = split[2]; + } + break; + case "Content-Type": + parsedContentType = split[1]; + break; + case "Parts-Count": + parsedPartCount = split[1]; + break; + case "Part-ContainsContents": + { + NameValue pair = new NameValue(); + pair.name = split[1]; + pair.value = split[2]; + partContainsContents.add(pair); + break; + } + case "Part-Filename": + { + NameValue pair = new NameValue(); + pair.name = split[1]; + pair.value = split[2]; + partFilenames.add(pair); + break; + } + case "Part-Sha1sum": + { + NameValue pair = new NameValue(); + pair.name = split[1]; + pair.value = split[2]; + partSha1sums.add(pair); + break; + } + default: + throw new IOException("Bad Line in " + expectationsPath + ": " + line); + } + } + } + + Objects.requireNonNull(parsedContentType, "Missing required 'Content-Type' declaration: " + expectationsPath); + this.contentType = parsedContentType; + this.partCount = Integer.parseInt(parsedPartCount); + } + + private void checkParts(Collection parts, Function getPart) throws Exception + { + // Evaluate Count + if (partCount >= 0) + { + assertThat("Mulitpart.parts.size", parts.size(), is(partCount)); + } + + String defaultCharset = UTF_8.toString(); + Part charSetPart = getPart.apply("_charset_"); + if (charSetPart != null) + { + defaultCharset = org.eclipse.jetty.util.IO.toString(charSetPart.getInputStream()); + } + + // Evaluate expected Contents + for (NameValue expected : partContainsContents) + { + Part part = getPart.apply(expected.name); + assertThat("Part[" + expected.name + "]", part, is(notNullValue())); + try (InputStream partInputStream = part.getInputStream()) + { + String charset = getCharsetFromContentType(part.getContentType(), defaultCharset); + String contents = org.eclipse.jetty.util.IO.toString(partInputStream, charset); + assertThat("Part[" + expected.name + "].contents", contents, containsString(expected.value)); + } + } + + // Evaluate expected filenames + for (NameValue expected : partFilenames) + { + Part part = getPart.apply(expected.name); + assertThat("Part[" + expected.name + "]", part, is(notNullValue())); + assertThat("Part[" + expected.name + "]", part.getSubmittedFileName(), is(expected.value)); + } + + // Evaluate expected contents checksums + for (NameValue expected : partSha1sums) + { + Part part = getPart.apply(expected.name); + assertThat("Part[" + expected.name + "]", part, is(notNullValue())); + MessageDigest digest = MessageDigest.getInstance("SHA1"); + try (InputStream partInputStream = part.getInputStream(); + NoOpOutputStream noop = new NoOpOutputStream(); + DigestOutputStream digester = new DigestOutputStream(noop, digest)) + { + org.eclipse.jetty.util.IO.copy(partInputStream, digester); + String actualSha1sum = Hex.asHex(digest.digest()).toLowerCase(Locale.US); + assertThat("Part[" + expected.name + "].sha1sum", actualSha1sum, Matchers.equalToIgnoringCase(expected.value)); + } + } + } + + private String getCharsetFromContentType(String contentType, String defaultCharset) + { + if (StringUtil.isBlank(contentType)) + { + return defaultCharset; + } + + QuotedStringTokenizer tok = new QuotedStringTokenizer(contentType, ";", false, false); + while (tok.hasMoreTokens()) + { + String str = tok.nextToken().trim(); + if (str.startsWith("charset=")) + { + return str.substring("charset=".length()); + } + } + + return defaultCharset; + } + } + + static class NoOpOutputStream extends OutputStream + { + @Override + public void write(byte[] b) throws IOException + { + } + + @Override + public void write(byte[] b, int off, int len) throws IOException + { + } + + @Override + public void flush() throws IOException + { + } + + @Override + public void close() throws IOException + { + } + + @Override + public void write(int b) throws IOException + { + } + } + + public static class NameValue + { + public String name; + public String value; + } } diff --git a/jetty-jmh/src/main/java/org/eclipse/jetty/io/jmh/ByteBufferBenchmark.java b/jetty-jmh/src/main/java/org/eclipse/jetty/io/jmh/ByteBufferBenchmark.java new file mode 100644 index 00000000000..ef7390240fd --- /dev/null +++ b/jetty-jmh/src/main/java/org/eclipse/jetty/io/jmh/ByteBufferBenchmark.java @@ -0,0 +1,151 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.io.jmh; + +import java.nio.ByteBuffer; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.TimeUnit; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Threads; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +@State(Scope.Benchmark) +@Threads(4) +@Warmup(iterations = 7, time = 500, timeUnit = TimeUnit.MILLISECONDS) +@Measurement(iterations = 7, time = 500, timeUnit = TimeUnit.MILLISECONDS) +public class ByteBufferBenchmark +{ + public long test(ByteBuffer buffer) + { + buffer.clear(); + while (buffer.hasRemaining()) + { + int size = ThreadLocalRandom.current().nextInt(1024); + byte[] bytes = new byte[size]; + ThreadLocalRandom.current().nextBytes(bytes); + buffer.put(bytes, 0, Math.min(bytes.length, buffer.remaining())); + } + + buffer.flip(); + + long sum = 0; + while (buffer.hasRemaining()) + { + sum += buffer.get(); + } + + return sum; + } + + public long testArray(ByteBuffer buffer) + { + buffer.clear(); + byte[] array = buffer.array(); + int offset = buffer.arrayOffset(); + int end = offset + buffer.remaining(); + while (offset < end) + { + int size = ThreadLocalRandom.current().nextInt(1024); + byte[] bytes = new byte[size]; + ThreadLocalRandom.current().nextBytes(bytes); + System.arraycopy(bytes, 0, array, offset, Math.min(bytes.length, end - offset)); + offset += bytes.length; + } + buffer.position(buffer.limit()); + buffer.flip(); + + long sum = 0; + array = buffer.array(); + offset = buffer.arrayOffset(); + end = offset + buffer.remaining(); + + while (offset < end) + { + sum += array[offset++]; + } + buffer.position(buffer.limit()); + return sum; + } + + @Benchmark + @BenchmarkMode({Mode.Throughput}) + public long testDirect() + { + ByteBuffer buffer = ByteBuffer.allocateDirect(32768); + long sum = 0; + sum ^= test(buffer); + sum ^= test(buffer); + sum ^= test(buffer); + sum ^= test(buffer); + sum ^= test(buffer); + return sum; + } + + @Benchmark + @BenchmarkMode({Mode.Throughput}) + public long testInDirect() + { + ByteBuffer buffer = ByteBuffer.allocate(32768); + long sum = 0; + sum ^= test(buffer); + sum ^= test(buffer); + sum ^= test(buffer); + sum ^= test(buffer); + sum ^= test(buffer); + return sum; + } + + @Benchmark + @BenchmarkMode({Mode.Throughput}) + public long testInDirectArray() + { + ByteBuffer buffer = ByteBuffer.allocate(32768); + long sum = 0; + sum ^= testArray(buffer); + sum ^= testArray(buffer); + sum ^= testArray(buffer); + sum ^= testArray(buffer); + sum ^= testArray(buffer); + return sum; + } + + public static void main(String[] args) throws RunnerException + { + Options opt = new OptionsBuilder() + .include(ByteBufferBenchmark.class.getSimpleName()) + .warmupIterations(20) + .measurementIterations(10) + // .addProfiler(GCProfiler.class) + .forks(1) + .threads(10) + .build(); + + new Runner(opt).run(); + } +} diff --git a/jetty-jmh/src/main/java/org/eclipse/jetty/requestlog/jmh/RequestLogBenchmark.java b/jetty-jmh/src/main/java/org/eclipse/jetty/requestlog/jmh/RequestLogBenchmark.java new file mode 100644 index 00000000000..f8498ae1c3f --- /dev/null +++ b/jetty-jmh/src/main/java/org/eclipse/jetty/requestlog/jmh/RequestLogBenchmark.java @@ -0,0 +1,208 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.requestlog.jmh; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jetty.util.TypeUtil; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Threads; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.profile.GCProfiler; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import static java.lang.invoke.MethodHandles.dropArguments; +import static java.lang.invoke.MethodHandles.foldArguments; +import static java.lang.invoke.MethodType.methodType; + +@State(Scope.Benchmark) +@Threads(4) +@Warmup(iterations = 7, time = 500, timeUnit = TimeUnit.MILLISECONDS) +@Measurement(iterations = 7, time = 500, timeUnit = TimeUnit.MILLISECONDS) +public class RequestLogBenchmark +{ + + public static void append(String s, StringBuilder b) + { + b.append(s); + } + + public static void logURI(StringBuilder b, String request) + { + b.append(request); + } + + public static void logLength(StringBuilder b, String request) + { + b.append(request.length()); + } + + public static void logAddr(StringBuilder b, String request) + { + try + { + TypeUtil.toHex(request.hashCode(), b); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + } + + private ThreadLocal buffers = ThreadLocal.withInitial(() -> new StringBuilder(256)); + MethodHandle logHandle; + Object[] iteratedLog; + + public RequestLogBenchmark() + { + try + { + MethodType logType = methodType(Void.TYPE, StringBuilder.class, String.class); + + MethodHandles.Lookup lookup = MethodHandles.lookup(); + MethodHandle append = lookup.findStatic(RequestLogBenchmark.class, "append", methodType(Void.TYPE, String.class, StringBuilder.class)); + MethodHandle logURI = lookup.findStatic(RequestLogBenchmark.class, "logURI", logType); + MethodHandle logAddr = lookup.findStatic(RequestLogBenchmark.class, "logAddr", logType); + MethodHandle logLength = lookup.findStatic(RequestLogBenchmark.class, "logLength", logType); + + // setup iteration + iteratedLog = new Object[] + { + logURI, + " - ", + logAddr, + " ", + logLength, + "\n" + }; + + // setup methodHandle + logHandle = dropArguments(append.bindTo("\n"), 1, String.class); + logHandle = foldArguments(logHandle, logLength); + logHandle = foldArguments(logHandle, dropArguments(append.bindTo(" "), 1, String.class)); + logHandle = foldArguments(logHandle, logAddr); + logHandle = foldArguments(logHandle, dropArguments(append.bindTo(" - "), 1, String.class)); + logHandle = foldArguments(logHandle, logURI); + } + catch (Throwable th) + { + throw new RuntimeException(th); + } + } + + public String logFixed(String request) + { + StringBuilder b = buffers.get(); + logURI(b, request); + append(" - ", b); + logAddr(b, request); + append(" ", b); + logLength(b, request); + append("\n", b); + String l = b.toString(); + b.setLength(0); + return l; + } + + public String logIterate(String request) + { + try + { + + StringBuilder b = buffers.get(); + for (Object o : iteratedLog) + { + if (o instanceof String) + append((String)o, b); + else if (o instanceof MethodHandle) + ((MethodHandle)o).invoke(b, request); + } + String l = b.toString(); + b.setLength(0); + return l; + } + catch (Throwable th) + { + throw new RuntimeException(th); + } + } + + public String logMethodHandle(String request) + { + try + { + StringBuilder b = buffers.get(); + logHandle.invoke(b, request); + String l = b.toString(); + b.setLength(0); + return l; + } + catch (Throwable th) + { + throw new RuntimeException(th); + } + } + + @Benchmark + @BenchmarkMode({Mode.Throughput}) + public String testFixed() + { + return logFixed(Long.toString(ThreadLocalRandom.current().nextLong())); + } + + @Benchmark + @BenchmarkMode({Mode.Throughput}) + public String testIterate() + { + return logIterate(Long.toString(ThreadLocalRandom.current().nextLong())); + } + + @Benchmark + @BenchmarkMode({Mode.Throughput}) + public String testHandle() + { + return logMethodHandle(Long.toString(ThreadLocalRandom.current().nextLong())); + } + + public static void main(String[] args) throws RunnerException + { + Options opt = new OptionsBuilder() + .include(RequestLogBenchmark.class.getSimpleName()) + .warmupIterations(20) + .measurementIterations(10) + .addProfiler(GCProfiler.class) + .forks(1) + .threads(100) + .build(); + + new Runner(opt).run(); + } +} diff --git a/jetty-jmh/src/main/java/org/eclipse/jetty/server/jmh/DeflaterPoolBenchmark.java b/jetty-jmh/src/main/java/org/eclipse/jetty/server/jmh/DeflaterPoolBenchmark.java index bff91a9325b..04172bb6b8a 100644 --- a/jetty-jmh/src/main/java/org/eclipse/jetty/server/jmh/DeflaterPoolBenchmark.java +++ b/jetty-jmh/src/main/java/org/eclipse/jetty/server/jmh/DeflaterPoolBenchmark.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -21,7 +21,7 @@ package org.eclipse.jetty.server.jmh; import java.util.concurrent.TimeUnit; import java.util.zip.Deflater; -import org.eclipse.jetty.server.DeflaterPool; +import org.eclipse.jetty.util.compression.DeflaterPool; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Level; @@ -87,7 +87,6 @@ public class DeflaterPoolBenchmark { } - @Benchmark @BenchmarkMode({Mode.Throughput}) @SuppressWarnings("deprecation") @@ -97,7 +96,7 @@ public class DeflaterPoolBenchmark deflater.setInput(COMPRESSION_STRING.getBytes()); deflater.finish(); - byte[] output = new byte[COMPRESSION_STRING.length()+1]; + byte[] output = new byte[COMPRESSION_STRING.length() + 1]; int compressedDataLength = deflater.deflate(output); _pool.release(deflater); @@ -107,13 +106,13 @@ public class DeflaterPoolBenchmark public static void main(String[] args) throws RunnerException { Options opt = new OptionsBuilder() - .include(DeflaterPoolBenchmark.class.getSimpleName()) - .warmupIterations(20) - .measurementIterations(10) - .addProfiler(GCProfiler.class) - .forks(1) - .threads(100) - .build(); + .include(DeflaterPoolBenchmark.class.getSimpleName()) + .warmupIterations(20) + .measurementIterations(10) + .addProfiler(GCProfiler.class) + .forks(1) + .threads(100) + .build(); new Runner(opt).run(); } diff --git a/jetty-jmh/src/main/java/org/eclipse/jetty/server/jmh/ForwardBenchmark.java b/jetty-jmh/src/main/java/org/eclipse/jetty/server/jmh/ForwardBenchmark.java new file mode 100644 index 00000000000..8a76f5fd8af --- /dev/null +++ b/jetty-jmh/src/main/java/org/eclipse/jetty/server/jmh/ForwardBenchmark.java @@ -0,0 +1,176 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.server.jmh; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.Arrays; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.util.ArrayTrie; +import org.eclipse.jetty.util.Trie; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Threads; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.profile.GCProfiler; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import static java.lang.invoke.MethodType.methodType; + +@State(Scope.Benchmark) +@Threads(4) +@Warmup(iterations = 7, time = 500, timeUnit = TimeUnit.MILLISECONDS) +@Measurement(iterations = 7, time = 500, timeUnit = TimeUnit.MILLISECONDS) +public class ForwardBenchmark +{ + static HttpFields __fields = new HttpFields(); + + static + { + Arrays.stream(new String[][] + { + {"accept", "*/*"}, + {"accept-encoding", "gzip, deflate, br"}, + {"accept-language", "en,en-AU;q=0.9,it;q=0.8"}, + {"content-length", "0"}, + {"content-type", "text/plain;charset=UTF-8"}, + {"cookie", "S=maestro=cH6W-eZ0JweknIgCwBxWD4FxQk647Uru:sso=HEiTd0qT5KdU7X6eL1m8snK1jNHwVJ9d"}, + {"origin", "https://www.google.com"}, + {"referer", "https://www.google.com/"}, + {"user-agent", "Mozilla/5.0"}, + {"x-client-data", "CLK1yQEIkLbJAQiltskBCKmdygEIoZ7KAQioo8oBCL+nygEI4qjKAQ=="}, + {"Forwarded", "for=192.0.2.43,for=198.51.100.17;by=203.0.113.60;proto=http;host=example.com"} + }).map(a -> new HttpField(a[0], a[1])).forEach(__fields::add); + } + + public ForwardBenchmark() + { + } + + @Benchmark + @BenchmarkMode({Mode.Throughput}) + public String testStringCompare() + { + String forwardedFor = null; + String forwardedHost = null; + String forwardedServer = null; + String forwarded = null; + + for (HttpField field : __fields) + { + String name = field.getName(); + if (HttpHeader.X_FORWARDED_FOR.asString().equalsIgnoreCase(name)) + forwardedFor = field.getValue(); + else if (HttpHeader.X_FORWARDED_HOST.asString().equalsIgnoreCase(name)) + forwardedHost = field.getValue(); + else if (HttpHeader.X_FORWARDED_SERVER.asString().equalsIgnoreCase(name)) + forwardedServer = field.getValue(); + else if (HttpHeader.FORWARDED.asString().equalsIgnoreCase(name)) + forwardedServer = field.getValue(); + } + + if (forwardedFor != null) + return forwardedFor; + if (forwardedHost != null) + return forwardedHost; + if (forwardedServer != null) + return forwardedServer; + return forwarded; + } + + static class Forwarded + { + String host; + + public void getHost(HttpField field) + { + if (host == null) + host = field.getValue(); + } + } + + static Trie __handles = new ArrayTrie<>(1024); + + static + { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + MethodType type = methodType(Void.TYPE, HttpField.class); + + try + { + __handles.put(HttpHeader.X_FORWARDED_FOR.asString(), lookup.findVirtual(Forwarded.class, "getHost", type)); + __handles.put(HttpHeader.X_FORWARDED_HOST.asString(), lookup.findVirtual(Forwarded.class, "getHost", type)); + __handles.put(HttpHeader.X_FORWARDED_SERVER.asString(), lookup.findVirtual(Forwarded.class, "getHost", type)); + __handles.put(HttpHeader.FORWARDED.asString(), lookup.findVirtual(Forwarded.class, "getHost", type)); + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + @Benchmark + @BenchmarkMode({Mode.Throughput}) + public String testTrieMethodHandle() + { + Forwarded forwarded = new Forwarded(); + + try + { + for (HttpField field : __fields) + { + MethodHandle handle = __handles.get(field.getName()); + if (handle != null) + handle.invoke(forwarded, field); + } + } + catch (Throwable e) + { + e.printStackTrace(); + } + + return forwarded.host; + } + + public static void main(String[] args) throws RunnerException + { + Options opt = new OptionsBuilder() + .include(ForwardBenchmark.class.getSimpleName()) + .warmupIterations(20) + .measurementIterations(10) + .addProfiler(GCProfiler.class) + .forks(1) + .threads(100) + .build(); + + new Runner(opt).run(); + } +} diff --git a/jetty-jmh/src/main/java/org/eclipse/jetty/server/jmh/ListVsMapBenchmark.java b/jetty-jmh/src/main/java/org/eclipse/jetty/server/jmh/ListVsMapBenchmark.java new file mode 100644 index 00000000000..001314781e5 --- /dev/null +++ b/jetty-jmh/src/main/java/org/eclipse/jetty/server/jmh/ListVsMapBenchmark.java @@ -0,0 +1,352 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.server.jmh; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Random; +import java.util.concurrent.TimeUnit; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Threads; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +@State(Scope.Benchmark) +@Threads(1) +@Warmup(iterations = 6, time = 2000, timeUnit = TimeUnit.MILLISECONDS) +@Measurement(iterations = 3, time = 2000, timeUnit = TimeUnit.MILLISECONDS) +public class ListVsMapBenchmark +{ + @Param({"12"}) // Chrome has 12 for HTTP/1.1 and 16 for HTTP/2 (including meta headers) + public static int size; + + @Param({"11"}) // average length of known headers in HttpHeader + public static int length; + + @Param({"1", "10", "20", "30"}) + public static int lookups; + + @Param({"hits", "misses", "iterate"}) + public static String mostly; + + static final String base = "This-is-the-base-of-All-key-names-and-is-long".substring(0, length); + static final String miss = "X-" + base; + static final List trials = new ArrayList<>(); + static final Random random = new Random(); + + @Setup(Level.Trial) + public void setup() + { + int hits = 1; + int misses = 1; + switch (mostly) + { + case "hits": + hits = lookups; + break; + case "misses": + misses = lookups; + break; + case "iterate": + hits = lookups / 2; + misses = lookups - hits; + break; + default: + throw new IllegalStateException(); + } + + for (int h = hits; h-- > 0; ) + { + trials.add(base + "-" + (h % size)); + } + + for (int m = misses; m-- > 0; ) + { + trials.add(miss); + } + + Collections.shuffle(trials); + } + + static class Pair + { + final String key; + final String value; + + public Pair(String key, String value) + { + this.key = key; + this.value = value; + } + } + + interface Fill + { + void put(Pair p); + } + + interface Lookup + { + Pair get(String key); + + Iterator iterate(); + } + + private void fill(Fill fill) + { + for (int i = 0; i < size - 1; i++) + { + String key = base + "-" + i; + Pair pair = new Pair(key, Long.toString(random.nextLong(), 8)); + fill.put(pair); + } + + // double up on header 0 + String key = base + "-0"; + Pair pair = new Pair(key, Long.toString(random.nextLong(), 8)); + fill.put(pair); + } + + private long test(Lookup lookup) + { + long result = 0; + if ("iterate".equals(mostly)) + { + Iterator t = trials.iterator(); + while (t.hasNext()) + { + // Look for 4 headers at once because that is what the common case of a + // ResourceService does + String one = t.hasNext() ? t.next() : null; + String two = t.hasNext() ? t.next() : null; + String three = t.hasNext() ? t.next() : null; + String four = t.hasNext() ? t.next() : null; + + Iterator i = lookup.iterate(); + while (i.hasNext()) + { + Pair p = i.next(); + String k = p.key; + if (one != null && one.equals(k)) + result ^= p.value.hashCode(); + else if (two != null && two.equals(k)) + result ^= p.value.hashCode(); + else if (three != null && three.equals(k)) + result ^= p.value.hashCode(); + else if (four != null && four.equals(k)) + result ^= p.value.hashCode(); + } + } + } + else + { + for (String t : trials) + { + Pair p = lookup.get(t); + if (p != null) + result ^= p.value.hashCode(); + } + } + + return result; + } + + private long listLookup(List list) + { + return test(new Lookup() + { + @Override + public Pair get(String k) + { + for (int i = 0; i < list.size(); i++) + { + Pair p = list.get(i); + if (p.key.equalsIgnoreCase(k)) + return p; + } + return null; + } + + @Override + public Iterator iterate() + { + return list.iterator(); + } + }); + } + + @Benchmark + @BenchmarkMode({Mode.Throughput}) + public long testArrayList() throws Exception + { + List list = new ArrayList<>(size); + fill(list::add); + return listLookup(list); + } + + @Benchmark + @BenchmarkMode({Mode.Throughput}) + public long testLinkedList() throws Exception + { + List list = new LinkedList<>(); + fill(list::add); + return listLookup(list); + } + + @Benchmark + @BenchmarkMode({Mode.Throughput}) + public long testLinkedHashMap() throws Exception + { + // This loses the true ordering of fields + Map> map = new LinkedHashMap<>(size); + fill(p -> + { + List list = new LinkedList<>(); + list.add(p); + map.put(p.key.toLowerCase(), list); + }); + return test(new Lookup() + { + @Override + public Pair get(String k) + { + List list = map.get(k.toLowerCase()); + if (list == null || list.isEmpty()) + return null; + return list.get(0); + } + + @Override + public Iterator iterate() + { + Iterator> iter = map.values().iterator(); + + return new Iterator() + { + Iterator current; + + @Override + public boolean hasNext() + { + if ((current == null || !current.hasNext()) && iter.hasNext()) + current = iter.next().iterator(); + return current != null && current.hasNext(); + } + + @Override + public Pair next() + { + if (hasNext()) + return current.next(); + throw new NoSuchElementException(); + } + }; + } + }); + } + + @Benchmark + @BenchmarkMode({Mode.Throughput}) + public long testHashMapAndLinkedList() throws Exception + { + // This keeps the true ordering of fields + Map> map = new HashMap<>(size); + List order = new LinkedList<>(); + + fill(p -> + { + List list = new LinkedList<>(); + list.add(p); + map.put(p.key.toLowerCase(), list); + order.add(p); + }); + return mapLookup(map, order); + } + + @Benchmark + @BenchmarkMode({Mode.Throughput}) + public long testHashMapAndArrayList() throws Exception + { + // This keeps the true ordering of fields + Map> map = new HashMap<>(size); + List order = new ArrayList<>(); + + fill(p -> + { + List list = new ArrayList<>(2); + list.add(p); + map.put(p.key.toLowerCase(), list); + order.add(p); + }); + return mapLookup(map, order); + } + + private long mapLookup(Map> map, List order) + { + return test(new Lookup() + { + @Override + public Pair get(String k) + { + List list = map.get(k.toLowerCase()); + if (list == null || list.isEmpty()) + return null; + return list.get(0); + } + + @Override + public Iterator iterate() + { + return order.iterator(); + } + }); + } + + public static void main(String[] args) throws RunnerException + { + Options opt = new OptionsBuilder() + .include(ListVsMapBenchmark.class.getSimpleName()) + // .addProfiler(GCProfiler.class) + .forks(1) + .build(); + + new Runner(opt).run(); + } +} + + diff --git a/jetty-jmh/src/main/java/org/eclipse/jetty/util/StringIsEmptyBenchmark.java b/jetty-jmh/src/main/java/org/eclipse/jetty/util/StringIsEmptyBenchmark.java new file mode 100644 index 00000000000..de0c46ad91d --- /dev/null +++ b/jetty-jmh/src/main/java/org/eclipse/jetty/util/StringIsEmptyBenchmark.java @@ -0,0 +1,65 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.util.concurrent.TimeUnit; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Threads; +import org.openjdk.jmh.annotations.Warmup; + +@State(Scope.Benchmark) +@Threads(4) +@Warmup(iterations = 7, time = 500, timeUnit = TimeUnit.MILLISECONDS) +@Measurement(iterations = 9, time = 800, timeUnit = TimeUnit.MILLISECONDS) +public class StringIsEmptyBenchmark +{ + + private static final String SHORT = "beer.com/foo"; + + private static final String MEDIUM = "beer.com/foobarbeeerbe/bebbebbebebbe/bebbeghdegde/foobarbeeerbe/bebbebbebebbe/bebbeghdegde"; + + private static final String LONG = "beer.com/foobarbeeerbe/bebbebbebebbe/bebbeghdegde/foobarbeeerbe/bebbebbebebbe/bebbeghdegde/foobarbeeerbe/bebbebbebebbe/bebbeghdegde/foobarbeeerbe/bebbebbebebbe/bebbeghdegde/foobarbeeerbe/bebbebbebebbe/bebbeghdegde/foobarbeeerbe/bebbebbebebbe/bebbeghdegde/foobarbeeerbe/bebbebbebebbe/bebbeghdegde"; + + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void shortIsEmpty() + { + StringUtil.isEmpty(SHORT); + } + + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void mediumIsEmpty() + { + StringUtil.isEmpty(MEDIUM); + } + + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void longIsEmpty() + { + StringUtil.isEmpty(LONG); + } +} diff --git a/jetty-jmh/src/main/java/org/eclipse/jetty/util/StringReplaceBenchmark.java b/jetty-jmh/src/main/java/org/eclipse/jetty/util/StringReplaceBenchmark.java new file mode 100644 index 00000000000..61419271778 --- /dev/null +++ b/jetty-jmh/src/main/java/org/eclipse/jetty/util/StringReplaceBenchmark.java @@ -0,0 +1,119 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.util.concurrent.TimeUnit; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +@Fork(value = 3) +@State(Scope.Benchmark) +@Warmup(iterations = 4, time = 1, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 4, time = 1, timeUnit = TimeUnit.SECONDS) +public class StringReplaceBenchmark +{ + @Param({"3", "100", "1000"}) + int size; + + @Param({"0", "1", "3", "50"}) + int matches; + + String input; + + @Setup(Level.Trial) + public void setupTrial() throws Exception + { + String pattern = "abc"; + StringBuilder str = new StringBuilder(); + while (str.length() < size) + { + str.append(pattern); + } + + if (matches > 0) + { + int partSize = (int)((double)str.length() / (double)matches); + for (int i = 0; i < matches; i++) + { + str.insert((i * partSize), "'"); + } + } + input = str.toString(); + } + + @Benchmark + public void testJavaStringReplace_Growth(Blackhole blackhole) + { + blackhole.consume(input.replace("'", "FOOBAR")); + } + + @Benchmark + public void testJavaStringReplace_Same(Blackhole blackhole) + { + blackhole.consume(input.replace("'", "X")); + } + + @Benchmark + public void testJavaStringReplace_Reduce(Blackhole blackhole) + { + blackhole.consume(input.replace("'", "")); + } + + @Benchmark + public void testJettyStringUtilReplace_Growth(Blackhole blackhole) + { + blackhole.consume(StringUtil.replace(input, "'", "FOOBAR")); + } + + @Benchmark + public void testJettyStringUtilReplace_Same(Blackhole blackhole) + { + blackhole.consume(StringUtil.replace(input, "'", "X")); + } + + @Benchmark + public void testJettyStringUtilReplace_Reduce(Blackhole blackhole) + { + blackhole.consume(StringUtil.replace(input, "'", "")); + } + + public static void main(String[] args) throws RunnerException + { + Options opt = new OptionsBuilder() + .include(StringReplaceBenchmark.class.getSimpleName()) +// .addProfiler(GCProfiler.class) + .forks(1) + .build(); + + new Runner(opt).run(); + } +} diff --git a/jetty-jmh/src/main/java/org/eclipse/jetty/util/jmh/B64CodeBenchmark.java b/jetty-jmh/src/main/java/org/eclipse/jetty/util/jmh/B64CodeBenchmark.java new file mode 100644 index 00000000000..329cf7ee539 --- /dev/null +++ b/jetty-jmh/src/main/java/org/eclipse/jetty/util/jmh/B64CodeBenchmark.java @@ -0,0 +1,116 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.jmh; + +import java.util.Base64; +import java.util.Random; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jetty.util.B64Code; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Threads; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.profile.GCProfiler; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +@State(Scope.Benchmark) +@Threads(4) +@Warmup(iterations = 4, time = 1, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 4, time = 1, timeUnit = TimeUnit.SECONDS) +public class B64CodeBenchmark +{ + @Param({"200", "2000", "20000", "200000"}) + int size; + + Base64.Encoder javaEncoder; + Base64.Decoder javaDecoder; + byte[] rawBuffer; + String rawEncodedBuffer; + + @Setup(Level.Trial) + public void setupTrial() throws Exception + { + rawBuffer = new byte[size]; + Random random = new Random(); + random.setSeed(8080); + random.nextBytes(rawBuffer); + + javaEncoder = Base64.getEncoder(); + javaDecoder = Base64.getDecoder(); + + // prepare encoded buffer for Decode benchmarks + rawEncodedBuffer = Base64.getEncoder().encodeToString(rawBuffer); + } + + @TearDown(Level.Trial) + public static void stopTrial() throws Exception + { + } + + @Benchmark + @BenchmarkMode({Mode.Throughput}) + public char[] testJettyEncode() throws Exception + { + return B64Code.encode(rawBuffer); + } + + @Benchmark + @BenchmarkMode({Mode.Throughput}) + public byte[] testJettyDecode() throws Exception + { + return B64Code.decode(rawEncodedBuffer); + } + + @Benchmark + @BenchmarkMode({Mode.Throughput}) + public byte[] testJavaEncode() + { + return javaEncoder.encode(rawBuffer); + } + + @Benchmark + @BenchmarkMode({Mode.Throughput}) + public byte[] testJavaDecode() + { + return javaDecoder.decode(rawEncodedBuffer); + } + + public static void main(String[] args) throws RunnerException + { + Options opt = new OptionsBuilder() + .include(B64CodeBenchmark.class.getSimpleName()) + .addProfiler(GCProfiler.class) + .forks(1) + .build(); + + new Runner(opt).run(); + } +} diff --git a/jetty-jmh/src/main/java/org/eclipse/jetty/util/jmh/DateCacheBenchmark.java b/jetty-jmh/src/main/java/org/eclipse/jetty/util/jmh/DateCacheBenchmark.java index aa11e93a3cc..ccceae86139 100644 --- a/jetty-jmh/src/main/java/org/eclipse/jetty/util/jmh/DateCacheBenchmark.java +++ b/jetty-jmh/src/main/java/org/eclipse/jetty/util/jmh/DateCacheBenchmark.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,6 +18,10 @@ package org.eclipse.jetty.util.jmh; +import java.time.Instant; +import java.util.Date; +import java.util.concurrent.TimeUnit; + import org.eclipse.jetty.util.DateCache; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -33,10 +37,6 @@ import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; import org.openjdk.jmh.runner.options.TimeValue; -import java.time.Instant; -import java.util.Date; -import java.util.concurrent.TimeUnit; - @State(Scope.Benchmark) @Threads(4) @Warmup(iterations = 7, time = 500, timeUnit = TimeUnit.MILLISECONDS) @@ -68,24 +68,24 @@ public class DateCacheBenchmark dateCache.formatNow(System.currentTimeMillis()); } - public static void main(String[] args) throws RunnerException + public static void main(String[] args) throws RunnerException { Options opt = new OptionsBuilder() - .include(DateCacheBenchmark.class.getSimpleName()) - .warmupIterations(2) - .measurementIterations(3) - .forks(1) - .threads(400) - // .syncIterations(true) // Don't start all threads at same time - .warmupTime(new TimeValue(10000,TimeUnit.MILLISECONDS)) - .measurementTime(new TimeValue(10000,TimeUnit.MILLISECONDS)) - // .addProfiler(CompilerProfiler.class) - // .addProfiler(LinuxPerfProfiler.class) - // .addProfiler(LinuxPerfNormProfiler.class) - // .addProfiler(LinuxPerfAsmProfiler.class) - // .resultFormat(ResultFormatType.CSV) - .build(); - + .include(DateCacheBenchmark.class.getSimpleName()) + .warmupIterations(2) + .measurementIterations(3) + .forks(1) + .threads(400) + // .syncIterations(true) // Don't start all threads at same time + .warmupTime(new TimeValue(10000, TimeUnit.MILLISECONDS)) + .measurementTime(new TimeValue(10000, TimeUnit.MILLISECONDS)) + // .addProfiler(CompilerProfiler.class) + // .addProfiler(LinuxPerfProfiler.class) + // .addProfiler(LinuxPerfNormProfiler.class) + // .addProfiler(LinuxPerfAsmProfiler.class) + // .resultFormat(ResultFormatType.CSV) + .build(); + new Runner(opt).run(); } -} \ No newline at end of file +} diff --git a/jetty-jmh/src/main/java/org/eclipse/jetty/util/jmh/DateCacheNoTick.java b/jetty-jmh/src/main/java/org/eclipse/jetty/util/jmh/DateCacheNoTick.java index 0b224055f39..e24baa99f31 100644 --- a/jetty-jmh/src/main/java/org/eclipse/jetty/util/jmh/DateCacheNoTick.java +++ b/jetty-jmh/src/main/java/org/eclipse/jetty/util/jmh/DateCacheNoTick.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -32,7 +32,7 @@ import java.util.TimeZone; * the results so that subsequent requests within the same second * will be fast. * - * Only format strings that contain either "ss". Sub second formatting is + * Only format strings that contain either "ss". Sub second formatting is * not handled. * * The timezone of the date may be included as an ID with the "zzz" @@ -43,7 +43,7 @@ import java.util.TimeZone; */ public class DateCacheNoTick { - public static final String DEFAULT_FORMAT="EEE MMM dd HH:mm:ss zzz yyyy"; + public static final String DEFAULT_FORMAT = "EEE MMM dd HH:mm:ss zzz yyyy"; private final String _formatString; private final String _tzFormatString; @@ -51,8 +51,8 @@ public class DateCacheNoTick private final Locale _locale; private final ZoneId _zoneId; - /* ------------------------------------------------------------ */ - /** Constructor. + /** + * Constructor. * Make a DateCache that will use a default format. The default format * generates the same results as Date.toString(). */ @@ -61,135 +61,130 @@ public class DateCacheNoTick this(DEFAULT_FORMAT); } - /* ------------------------------------------------------------ */ - /** Constructor. + /** + * Constructor. * Make a DateCache that will use the given format + * * @param format the format to use */ - public DateCacheNoTick( String format) + public DateCacheNoTick(String format) { - this(format,null,TimeZone.getDefault()); + this(format, null, TimeZone.getDefault()); } - /* ------------------------------------------------------------ */ - public DateCacheNoTick( String format, Locale l) + public DateCacheNoTick(String format, Locale l) { - this(format,l,TimeZone.getDefault()); + this(format, l, TimeZone.getDefault()); } - /* ------------------------------------------------------------ */ - public DateCacheNoTick( String format, Locale l, String tz) + public DateCacheNoTick(String format, Locale l, String tz) { - this(format,l,TimeZone.getTimeZone(tz)); + this(format, l, TimeZone.getTimeZone(tz)); } - /* ------------------------------------------------------------ */ - public DateCacheNoTick( String format, Locale l, TimeZone tz) + public DateCacheNoTick(String format, Locale l, TimeZone tz) { - _formatString=format; + _formatString = format; _locale = l; - - int zIndex = _formatString.indexOf( "ZZZ" ); - if( zIndex >= 0 ) + int zIndex = _formatString.indexOf("ZZZ"); + if (zIndex >= 0) { - String ss1 = _formatString.substring( 0, zIndex ); - String ss2 = _formatString.substring( zIndex+3 ); + String ss1 = _formatString.substring(0, zIndex); + String ss2 = _formatString.substring(zIndex + 3); int tzOffset = tz.getRawOffset(); - - StringBuilder sb = new StringBuilder(_formatString.length()+10); + + StringBuilder sb = new StringBuilder(_formatString.length() + 10); sb.append(ss1); sb.append("'"); - if( tzOffset >= 0 ) - sb.append( '+' ); + if (tzOffset >= 0) + sb.append('+'); else { tzOffset = -tzOffset; - sb.append( '-' ); + sb.append('-'); } - - int raw = tzOffset / (1000*60); // Convert to seconds + + int raw = tzOffset / (1000 * 60); // Convert to seconds int hr = raw / 60; int min = raw % 60; - - if( hr < 10 ) - sb.append( '0' ); - sb.append( hr ); - if( min < 10 ) - sb.append( '0' ); - sb.append( min ); - sb.append( '\'' ); - + + if (hr < 10) + sb.append('0'); + sb.append(hr); + if (min < 10) + sb.append('0'); + sb.append(min); + sb.append('\''); + sb.append(ss2); - _tzFormatString=sb.toString(); + _tzFormatString = sb.toString(); } else - _tzFormatString=_formatString; - - if( _locale != null ) + _tzFormatString = _formatString; + + if (_locale != null) { - _tzFormat=DateTimeFormatter.ofPattern(_tzFormatString,_locale); + _tzFormat = DateTimeFormatter.ofPattern(_tzFormatString, _locale); } - else + else { - _tzFormat=DateTimeFormatter.ofPattern(_tzFormatString); + _tzFormat = DateTimeFormatter.ofPattern(_tzFormatString); } _zoneId = tz.toZoneId(); _tzFormat.withZone(_zoneId); } - - /* ------------------------------------------------------------ */ public TimeZone getTimeZone() { return TimeZone.getTimeZone(_zoneId); } - - /* ------------------------------------------------------------ */ - /** Format a date according to our stored formatter. + /** + * Format a date according to our stored formatter. + * * @param inDate the Date * @return Formatted date */ public String format(Date inDate) { - return ZonedDateTime.ofInstant(inDate.toInstant(),_zoneId).format( _tzFormat ); + return ZonedDateTime.ofInstant(inDate.toInstant(), _zoneId).format(_tzFormat); } - - /* ------------------------------------------------------------ */ - /** Format a date according to our stored formatter. + + /** + * Format a date according to our stored formatter. * If it happens to be in the same second as the last formatNow * call, then the format is reused. - * @param inDate the date in milliseconds since unix epoch + * + * @param inDate the date in milliseconds since unix epoch * @return Formatted date */ public String format(long inDate) { - return ZonedDateTime.ofInstant(Instant.ofEpochMilli(inDate),_zoneId).format( _tzFormat ); + return ZonedDateTime.ofInstant(Instant.ofEpochMilli(inDate), _zoneId).format(_tzFormat); } - - /* ------------------------------------------------------------ */ - /** Format a date according to our stored formatter. - * The passed time is expected to be close to the current time, so it is + + /** + * Format a date according to our stored formatter. + * The passed time is expected to be close to the current time, so it is * compared to the last value passed and if it is within the same second, * the format is reused. Otherwise a new cached format is created. - * @param now the milliseconds since unix epoch + * + * @param now the milliseconds since unix epoch * @return Formatted date */ public String formatNow(long now) { return format(now); } - - /* ------------------------------------------------------------ */ + public String now() { return formatNow(System.currentTimeMillis()); } - /* ------------------------------------------------------------ */ public String getFormatString() { return _formatString; - } + } } diff --git a/jetty-jmh/src/main/java/org/eclipse/jetty/util/jmh/DateCacheNoTickBenchmark.java b/jetty-jmh/src/main/java/org/eclipse/jetty/util/jmh/DateCacheNoTickBenchmark.java index 6fb8781ca93..cfcbd907704 100644 --- a/jetty-jmh/src/main/java/org/eclipse/jetty/util/jmh/DateCacheNoTickBenchmark.java +++ b/jetty-jmh/src/main/java/org/eclipse/jetty/util/jmh/DateCacheNoTickBenchmark.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,6 +18,10 @@ package org.eclipse.jetty.util.jmh; +import java.time.Instant; +import java.util.Date; +import java.util.concurrent.TimeUnit; + import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Measurement; @@ -32,10 +36,6 @@ import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; import org.openjdk.jmh.runner.options.TimeValue; -import java.time.Instant; -import java.util.Date; -import java.util.concurrent.TimeUnit; - @State(Scope.Benchmark) @Threads(4) @Warmup(iterations = 7, time = 500, timeUnit = TimeUnit.MILLISECONDS) @@ -67,24 +67,24 @@ public class DateCacheNoTickBenchmark dateCache.formatNow(System.currentTimeMillis()); } - public static void main(String[] args) throws RunnerException + public static void main(String[] args) throws RunnerException { Options opt = new OptionsBuilder() - .include(DateCacheNoTickBenchmark.class.getSimpleName()) - .warmupIterations(2) - .measurementIterations(3) - .forks(1) - .threads(400) - // .syncIterations(true) // Don't start all threads at same time - .warmupTime(new TimeValue(10000,TimeUnit.MILLISECONDS)) - .measurementTime(new TimeValue(10000,TimeUnit.MILLISECONDS)) - // .addProfiler(CompilerProfiler.class) - // .addProfiler(LinuxPerfProfiler.class) - // .addProfiler(LinuxPerfNormProfiler.class) - // .addProfiler(LinuxPerfAsmProfiler.class) - // .resultFormat(ResultFormatType.CSV) - .build(); - + .include(DateCacheNoTickBenchmark.class.getSimpleName()) + .warmupIterations(2) + .measurementIterations(3) + .forks(1) + .threads(400) + // .syncIterations(true) // Don't start all threads at same time + .warmupTime(new TimeValue(10000, TimeUnit.MILLISECONDS)) + .measurementTime(new TimeValue(10000, TimeUnit.MILLISECONDS)) + // .addProfiler(CompilerProfiler.class) + // .addProfiler(LinuxPerfProfiler.class) + // .addProfiler(LinuxPerfNormProfiler.class) + // .addProfiler(LinuxPerfAsmProfiler.class) + // .resultFormat(ResultFormatType.CSV) + .build(); + new Runner(opt).run(); } -} \ No newline at end of file +} diff --git a/jetty-jmh/src/main/java/org/eclipse/jetty/util/jmh/DateCacheSimpleDateFormat.java b/jetty-jmh/src/main/java/org/eclipse/jetty/util/jmh/DateCacheSimpleDateFormat.java index 8c9826e442a..d6598d8f831 100644 --- a/jetty-jmh/src/main/java/org/eclipse/jetty/util/jmh/DateCacheSimpleDateFormat.java +++ b/jetty-jmh/src/main/java/org/eclipse/jetty/util/jmh/DateCacheSimpleDateFormat.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -23,7 +23,8 @@ import java.util.Date; import java.util.Locale; import java.util.TimeZone; -/** Date Format Cache. +/** + * Date Format Cache. * Computes String representations of Dates and caches * the results so that subsequent requests within the same second * will be fast. @@ -40,21 +41,20 @@ import java.util.TimeZone; public class DateCacheSimpleDateFormat { - public static final String DEFAULT_FORMAT="EEE MMM dd HH:mm:ss zzz yyyy"; + public static final String DEFAULT_FORMAT = "EEE MMM dd HH:mm:ss zzz yyyy"; private final String _formatString; private final String _tzFormatString; private final SimpleDateFormat _tzFormat; - private final Locale _locale ; + private final Locale _locale; private volatile Tick _tick; - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ public static class Tick { final long _seconds; final String _string; + public Tick(long seconds, String string) { _seconds = seconds; @@ -62,8 +62,8 @@ public class DateCacheSimpleDateFormat } } - /* ------------------------------------------------------------ */ - /** Constructor. + /** + * Constructor. * Make a DateCache that will use a default format. The default format * generates the same results as Date.toString(). */ @@ -72,94 +72,89 @@ public class DateCacheSimpleDateFormat this(DEFAULT_FORMAT); } - /* ------------------------------------------------------------ */ - /** Constructor. + /** + * Constructor. * Make a DateCache that will use the given format + * * @param format the format to use */ public DateCacheSimpleDateFormat(String format) { - this( format, null, TimeZone.getDefault()); + this(format, null, TimeZone.getDefault()); } - /* ------------------------------------------------------------ */ - public DateCacheSimpleDateFormat(String format,Locale l) + public DateCacheSimpleDateFormat(String format, Locale l) { - this(format,l,TimeZone.getDefault()); + this(format, l, TimeZone.getDefault()); } - /* ------------------------------------------------------------ */ - public DateCacheSimpleDateFormat(String format,Locale l,String tz) + public DateCacheSimpleDateFormat(String format, Locale l, String tz) { - this(format,l,TimeZone.getTimeZone(tz)); + this(format, l, TimeZone.getTimeZone(tz)); } - /* ------------------------------------------------------------ */ - public DateCacheSimpleDateFormat(String format,Locale l,TimeZone tz) + public DateCacheSimpleDateFormat(String format, Locale l, TimeZone tz) { - _formatString=format; + _formatString = format; _locale = l; - - int zIndex = _formatString.indexOf( "ZZZ" ); - if( zIndex >= 0 ) + int zIndex = _formatString.indexOf("ZZZ"); + if (zIndex >= 0) { - String ss1 = _formatString.substring( 0, zIndex ); - String ss2 = _formatString.substring( zIndex+3 ); + String ss1 = _formatString.substring(0, zIndex); + String ss2 = _formatString.substring(zIndex + 3); int tzOffset = tz.getRawOffset(); - StringBuilder sb = new StringBuilder(_formatString.length()+10); + StringBuilder sb = new StringBuilder(_formatString.length() + 10); sb.append(ss1); sb.append("'"); - if( tzOffset >= 0 ) - sb.append( '+' ); + if (tzOffset >= 0) + sb.append('+'); else { tzOffset = -tzOffset; - sb.append( '-' ); + sb.append('-'); } - int raw = tzOffset / (1000*60); // Convert to seconds + int raw = tzOffset / (1000 * 60); // Convert to seconds int hr = raw / 60; int min = raw % 60; - if( hr < 10 ) - sb.append( '0' ); - sb.append( hr ); - if( min < 10 ) - sb.append( '0' ); - sb.append( min ); - sb.append( '\'' ); + if (hr < 10) + sb.append('0'); + sb.append(hr); + if (min < 10) + sb.append('0'); + sb.append(min); + sb.append('\''); sb.append(ss2); - _tzFormatString=sb.toString(); + _tzFormatString = sb.toString(); } else - _tzFormatString=_formatString; + _tzFormatString = _formatString; - if( _locale != null ) + if (_locale != null) { - _tzFormat=new SimpleDateFormat(_tzFormatString,_locale); + _tzFormat = new SimpleDateFormat(_tzFormatString, _locale); } else { - _tzFormat=new SimpleDateFormat(_tzFormatString); + _tzFormat = new SimpleDateFormat(_tzFormatString); } _tzFormat.setTimeZone(tz); - _tick=null; + _tick = null; } - - /* ------------------------------------------------------------ */ public TimeZone getTimeZone() { return _tzFormat.getTimeZone(); } - - /* ------------------------------------------------------------ */ - /** Format a date according to our stored formatter. + /** + * Format a date according to our stored formatter. + * * @param inDate the Date * @return Formatted date */ @@ -167,10 +162,10 @@ public class DateCacheSimpleDateFormat { long seconds = inDate.getTime() / 1000; - Tick tick=_tick; + Tick tick = _tick; // Is this the cached time - if (tick==null || seconds!=tick._seconds) + if (tick == null || seconds != tick._seconds) { // It's a cache miss synchronized (this) @@ -182,10 +177,11 @@ public class DateCacheSimpleDateFormat return tick._string; } - /* ------------------------------------------------------------ */ - /** Format a date according to our stored formatter. + /** + * Format a date according to our stored formatter. * If it happens to be in the same second as the last formatNow * call, then the format is reused. + * * @param inDate the date in milliseconds since unix epoch * @return Formatted date */ @@ -193,10 +189,10 @@ public class DateCacheSimpleDateFormat { long seconds = inDate / 1000; - Tick tick=_tick; + Tick tick = _tick; // Is this the cached time - if (tick==null || seconds!=tick._seconds) + if (tick == null || seconds != tick._seconds) { // It's a cache miss Date d = new Date(inDate); @@ -209,11 +205,12 @@ public class DateCacheSimpleDateFormat return tick._string; } - /* ------------------------------------------------------------ */ - /** Format a date according to our stored formatter. + /** + * Format a date according to our stored formatter. * The passed time is expected to be close to the current time, so it is * compared to the last value passed and if it is within the same second, * the format is reused. Otherwise a new cached format is created. + * * @param now the milliseconds since unix epoch * @return Formatted date */ @@ -221,27 +218,24 @@ public class DateCacheSimpleDateFormat { long seconds = now / 1000; - Tick tick=_tick; + Tick tick = _tick; // Is this the cached time - if (tick!=null && tick._seconds==seconds) + if (tick != null && tick._seconds == seconds) return tick._string; return formatTick(now)._string; } - /* ------------------------------------------------------------ */ public String now() { return formatNow(System.currentTimeMillis()); } - /* ------------------------------------------------------------ */ public Tick tick() { return formatTick(System.currentTimeMillis()); } - /* ------------------------------------------------------------ */ protected Tick formatTick(long now) { long seconds = now / 1000; @@ -250,19 +244,17 @@ public class DateCacheSimpleDateFormat synchronized (this) { // recheck the tick, to save multiple formats - if (_tick==null || _tick._seconds!=seconds) + if (_tick == null || _tick._seconds != seconds) { - String s= _tzFormat.format(new Date(now)); - return _tick=new Tick(seconds,s); + String s = _tzFormat.format(new Date(now)); + return _tick = new Tick(seconds, s); } return _tick; } } - /* ------------------------------------------------------------ */ public String getFormatString() { return _formatString; } - } diff --git a/jetty-jmh/src/main/java/org/eclipse/jetty/util/jmh/DateCacheSimpleDateFormatBenchmark.java b/jetty-jmh/src/main/java/org/eclipse/jetty/util/jmh/DateCacheSimpleDateFormatBenchmark.java index 3006bddd892..edb205337c0 100644 --- a/jetty-jmh/src/main/java/org/eclipse/jetty/util/jmh/DateCacheSimpleDateFormatBenchmark.java +++ b/jetty-jmh/src/main/java/org/eclipse/jetty/util/jmh/DateCacheSimpleDateFormatBenchmark.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,6 +18,10 @@ package org.eclipse.jetty.util.jmh; +import java.time.Instant; +import java.util.Date; +import java.util.concurrent.TimeUnit; + import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Measurement; @@ -32,10 +36,6 @@ import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; import org.openjdk.jmh.runner.options.TimeValue; -import java.time.Instant; -import java.util.Date; -import java.util.concurrent.TimeUnit; - @State(Scope.Benchmark) @Threads(4) @Warmup(iterations = 7, time = 500, timeUnit = TimeUnit.MILLISECONDS) @@ -67,24 +67,24 @@ public class DateCacheSimpleDateFormatBenchmark dateCache.formatNow(System.currentTimeMillis()); } - public static void main(String[] args) throws RunnerException + public static void main(String[] args) throws RunnerException { Options opt = new OptionsBuilder() - .include(DateCacheSimpleDateFormatBenchmark.class.getSimpleName()) - .warmupIterations(2) - .measurementIterations(3) - .forks(1) - .threads(400) - // .syncIterations(true) // Don't start all threads at same time - .warmupTime(new TimeValue(10000,TimeUnit.MILLISECONDS)) - .measurementTime(new TimeValue(10000,TimeUnit.MILLISECONDS)) - // .addProfiler(CompilerProfiler.class) - // .addProfiler(LinuxPerfProfiler.class) - // .addProfiler(LinuxPerfNormProfiler.class) - // .addProfiler(LinuxPerfAsmProfiler.class) - // .resultFormat(ResultFormatType.CSV) - .build(); - + .include(DateCacheSimpleDateFormatBenchmark.class.getSimpleName()) + .warmupIterations(2) + .measurementIterations(3) + .forks(1) + .threads(400) + // .syncIterations(true) // Don't start all threads at same time + .warmupTime(new TimeValue(10000, TimeUnit.MILLISECONDS)) + .measurementTime(new TimeValue(10000, TimeUnit.MILLISECONDS)) + // .addProfiler(CompilerProfiler.class) + // .addProfiler(LinuxPerfProfiler.class) + // .addProfiler(LinuxPerfNormProfiler.class) + // .addProfiler(LinuxPerfAsmProfiler.class) + // .resultFormat(ResultFormatType.CSV) + .build(); + new Runner(opt).run(); } -} \ No newline at end of file +} diff --git a/jetty-jmh/src/main/java/org/eclipse/jetty/util/log/LogCondensePackageStringBenchmark.java b/jetty-jmh/src/main/java/org/eclipse/jetty/util/log/LogCondensePackageStringBenchmark.java new file mode 100644 index 00000000000..3bdb92ffafc --- /dev/null +++ b/jetty-jmh/src/main/java/org/eclipse/jetty/util/log/LogCondensePackageStringBenchmark.java @@ -0,0 +1,65 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.log; + +import java.util.concurrent.TimeUnit; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; +import org.openjdk.jmh.profile.GCProfiler; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +@Fork(value = 5) +@State(Scope.Benchmark) + +@Warmup(iterations = 4, time = 5, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 4, time = 5, timeUnit = TimeUnit.SECONDS) +public class LogCondensePackageStringBenchmark +{ + @Param({ + "com.acme.Dump", + "org.eclipse.jetty.websocket.common.extensions.compress.DeflateFrameExtension$Pool" + }) + String fqClassName; + + @Benchmark + public void testCondensePackage(Blackhole blackhole) + { + blackhole.consume(AbstractLogger.condensePackageString(fqClassName)); + } + + public static void main(String[] args) throws RunnerException + { + Options opt = new OptionsBuilder() + .include(LogCondensePackageStringBenchmark.class.getSimpleName()) + .addProfiler(GCProfiler.class) + .build(); + + new Runner(opt).run(); + } +} diff --git a/jetty-jmh/src/main/java/org/eclipse/jetty/util/thread/jmh/ThreadPoolBenchmark.java b/jetty-jmh/src/main/java/org/eclipse/jetty/util/thread/jmh/ThreadPoolBenchmark.java index c5c70ace7b8..2254a4e7748 100644 --- a/jetty-jmh/src/main/java/org/eclipse/jetty/util/thread/jmh/ThreadPoolBenchmark.java +++ b/jetty-jmh/src/main/java/org/eclipse/jetty/util/thread/jmh/ThreadPoolBenchmark.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,11 +18,12 @@ package org.eclipse.jetty.util.thread.jmh; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; +import org.eclipse.jetty.util.BlockingArrayQueue; import org.eclipse.jetty.util.component.LifeCycle; import org.eclipse.jetty.util.thread.ExecutorThreadPool; import org.eclipse.jetty.util.thread.QueuedThreadPool; @@ -38,31 +39,25 @@ import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.TearDown; import org.openjdk.jmh.annotations.Threads; import org.openjdk.jmh.annotations.Warmup; -import org.openjdk.jmh.infra.Blackhole; import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.RunnerException; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; -import org.openjdk.jmh.runner.options.TimeValue; @State(Scope.Benchmark) -@Threads(4) -@Warmup(iterations = 7, time = 500, timeUnit = TimeUnit.MILLISECONDS) -@Measurement(iterations = 7, time = 500, timeUnit = TimeUnit.MILLISECONDS) +@Warmup(iterations = 8, time = 1000, timeUnit = TimeUnit.MILLISECONDS) +@Measurement(iterations = 3, time = 1000, timeUnit = TimeUnit.MILLISECONDS) public class ThreadPoolBenchmark { public enum Type { - QTP, ETP; + QTP, ETP, LQTP, LETP, AQTP, AETP } - @Param({ "QTP", "ETP"}) + @Param({"QTP", "ETP" /*, "LQTP", "LETP", "AQTP", "AETP" */}) Type type; - @Param({ "50"}) - int tasks; - - @Param({ "200", "2000"}) + @Param({"200"}) int size; ThreadPool pool; @@ -70,14 +65,42 @@ public class ThreadPoolBenchmark @Setup // (Level.Iteration) public void buildPool() { - switch(type) + switch (type) { case QTP: - pool = new QueuedThreadPool(size); + { + QueuedThreadPool qtp = new QueuedThreadPool(size, size, new BlockingArrayQueue<>(32768, 32768)); + qtp.setReservedThreads(0); + pool = qtp; break; - + } + case ETP: - pool = new ExecutorThreadPool(size); + pool = new ExecutorThreadPool(size, size, new BlockingArrayQueue<>(32768, 32768)); + break; + + case LQTP: + { + QueuedThreadPool qtp = new QueuedThreadPool(size, size, new LinkedBlockingQueue<>()); + qtp.setReservedThreads(0); + pool = qtp; + break; + } + + case LETP: + pool = new ExecutorThreadPool(size, size, new LinkedBlockingQueue<>()); + break; + + case AQTP: + { + QueuedThreadPool qtp = new QueuedThreadPool(size, size, new ArrayBlockingQueue<>(32768)); + qtp.setReservedThreads(0); + pool = qtp; + break; + } + + case AETP: + pool = new ExecutorThreadPool(size, size, new ArrayBlockingQueue<>(32768)); break; } LifeCycle.start(pool); @@ -85,9 +108,26 @@ public class ThreadPoolBenchmark @Benchmark @BenchmarkMode(Mode.Throughput) - public void testPool() + @Threads(1) + public void testFew() throws Exception { - doWork().join(); + doJob(); + } + + @Benchmark + @BenchmarkMode(Mode.Throughput) + @Threads(4) + public void testSome() throws Exception + { + doJob(); + } + + @Benchmark + @BenchmarkMode(Mode.Throughput) + @Threads(200) + public void testMany() throws Exception + { + doJob(); } @TearDown // (Level.Iteration) @@ -97,40 +137,27 @@ public class ThreadPoolBenchmark pool = null; } - CompletableFuture doWork() + void doJob() throws Exception { - List> futures = new ArrayList<>(); - for (int i = 0; i < tasks; i++) - { - final CompletableFuture f = new CompletableFuture(); - futures.add(f); - pool.execute(() -> { - Blackhole.consumeCPU(64); - f.complete(null); - }); - } - - return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])); + CountDownLatch latch = new CountDownLatch(1); + pool.execute(latch::countDown); + latch.await(); } - public static void main(String[] args) throws RunnerException + public static void main(String[] args) throws RunnerException { Options opt = new OptionsBuilder() - .include(ThreadPoolBenchmark.class.getSimpleName()) - .warmupIterations(2) - .measurementIterations(3) - .forks(1) - .threads(400) - // .syncIterations(true) // Don't start all threads at same time - .warmupTime(new TimeValue(10000,TimeUnit.MILLISECONDS)) - .measurementTime(new TimeValue(10000,TimeUnit.MILLISECONDS)) - // .addProfiler(CompilerProfiler.class) - // .addProfiler(LinuxPerfProfiler.class) - // .addProfiler(LinuxPerfNormProfiler.class) - // .addProfiler(LinuxPerfAsmProfiler.class) - // .resultFormat(ResultFormatType.CSV) - .build(); - + .include(ThreadPoolBenchmark.class.getSimpleName()) + .forks(1) + // .threads(400) + // .syncIterations(true) // Don't start all threads at same time + // .addProfiler(CompilerProfiler.class) + // .addProfiler(LinuxPerfProfiler.class) + // .addProfiler(LinuxPerfNormProfiler.class) + // .addProfiler(LinuxPerfAsmProfiler.class) + // .resultFormat(ResultFormatType.CSV) + .build(); + new Runner(opt).run(); } -} \ No newline at end of file +} diff --git a/jetty-jmh/src/main/java/org/eclipse/jetty/util/thread/strategy/jmh/EWYKBenchmark.java b/jetty-jmh/src/main/java/org/eclipse/jetty/util/thread/strategy/jmh/EWYKBenchmark.java index 2d8211e664f..37343ffa0a9 100644 --- a/jetty-jmh/src/main/java/org/eclipse/jetty/util/thread/strategy/jmh/EWYKBenchmark.java +++ b/jetty-jmh/src/main/java/org/eclipse/jetty/util/thread/strategy/jmh/EWYKBenchmark.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,18 +19,21 @@ package org.eclipse.jetty.util.thread.strategy.jmh; import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; +import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.component.LifeCycle; import org.eclipse.jetty.util.thread.ExecutionStrategy; import org.eclipse.jetty.util.thread.Invocable; import org.eclipse.jetty.util.thread.ReservedThreadExecutor; import org.eclipse.jetty.util.thread.strategy.EatWhatYouKill; -import org.eclipse.jetty.util.thread.strategy.ProduceExecuteConsume; import org.eclipse.jetty.util.thread.strategy.ProduceConsume; +import org.eclipse.jetty.util.thread.strategy.ProduceExecuteConsume; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Level; @@ -47,79 +50,82 @@ import org.openjdk.jmh.runner.options.OptionsBuilder; import org.openjdk.jmh.runner.options.TimeValue; @State(Scope.Benchmark) -public class EWYKBenchmark +public class EWYKBenchmark { static TestServer server; static ReservedThreadExecutor reserved; - static File directory; + static Path directory; - @Param({"PC","PEC","EWYK"}) + @Param({"PC", "PEC", "EWYK"}) public static String strategyName; - - @Param({"true","false"}) + + @Param({"true", "false"}) public static boolean sleeping; - - @Param({"true","false"}) + + @Param({"true", "false"}) public static boolean nonBlocking; - + @Setup(Level.Trial) public static void setupServer() throws Exception { // Make a test directory - directory = File.createTempFile("ewyk","dir"); - if (directory.exists()) - directory.delete(); - directory.mkdir(); - directory.deleteOnExit(); - + directory = Files.createTempDirectory("ewyk"); + // Make some test files - for (int i=0;i<75;i++) + for (int i = 0; i < 75; i++) { - File file =new File(directory,i+".txt"); - file.createNewFile(); - file.deleteOnExit(); + File.createTempFile("ewyk_benchmark", i + ".txt", directory.toFile()); } - - server=new TestServer(directory); + + server = new TestServer(directory.toFile()); server.start(); - reserved = new ReservedThreadExecutor(server,20); + reserved = new ReservedThreadExecutor(server, 20); reserved.start(); } - + @TearDown(Level.Trial) public static void stopServer() throws Exception { + try + { + IO.delete(directory.toFile()); + } + catch (Exception e) + { + System.out.println("cannot delete directory:" + directory); + } reserved.stop(); server.stop(); } - + @State(Scope.Thread) public static class ThreadState implements Runnable { - final TestConnection connection=new TestConnection(server,sleeping); + final TestConnection connection = new TestConnection(server, sleeping); final ExecutionStrategy strategy; + { - switch(strategyName) + switch (strategyName) { case "PC": - strategy = new ProduceConsume(connection,server); + strategy = new ProduceConsume(connection, server); break; - + case "PEC": - strategy = new ProduceExecuteConsume(connection,server); + strategy = new ProduceExecuteConsume(connection, server); break; - + case "EWYK": - strategy = new EatWhatYouKill(connection,server); + strategy = new EatWhatYouKill(connection, server); break; - + default: throw new IllegalStateException(); } - + LifeCycle.start(strategy); } - + @Override public void run() { @@ -132,7 +138,7 @@ public class EWYKBenchmark public long testStrategy(ThreadState state) throws Exception { int r; - switch(server.getRandom(8)) + switch (server.getRandom(8)) { case 0: r = 4; @@ -147,43 +153,45 @@ public class EWYKBenchmark } List> results = new ArrayList<>(r); - for (int i=0;i result = new CompletableFuture(); results.add(result); state.connection.submit(result); } - + if (nonBlocking) Invocable.invokeNonBlocking(state); else state.run(); - + long hash = 0; for (CompletableFuture result : results) + { hash ^= result.get().hashCode(); - + } + return hash; } - public static void main(String[] args) throws RunnerException + public static void main(String[] args) throws RunnerException { Options opt = new OptionsBuilder() - .include(EWYKBenchmark.class.getSimpleName()) - .warmupIterations(2) - .measurementIterations(3) - .forks(1) - .threads(400) - // .syncIterations(true) // Don't start all threads at same time - .warmupTime(new TimeValue(10000,TimeUnit.MILLISECONDS)) - .measurementTime(new TimeValue(10000,TimeUnit.MILLISECONDS)) - // .addProfiler(CompilerProfiler.class) - // .addProfiler(LinuxPerfProfiler.class) - // .addProfiler(LinuxPerfNormProfiler.class) - // .addProfiler(LinuxPerfAsmProfiler.class) - // .resultFormat(ResultFormatType.CSV) - .build(); - + .include(EWYKBenchmark.class.getSimpleName()) + .warmupIterations(2) + .measurementIterations(3) + .forks(1) + .threads(400) + // .syncIterations(true) // Don't start all threads at same time + .warmupTime(new TimeValue(10000, TimeUnit.MILLISECONDS)) + .measurementTime(new TimeValue(10000, TimeUnit.MILLISECONDS)) + // .addProfiler(CompilerProfiler.class) + // .addProfiler(LinuxPerfProfiler.class) + // .addProfiler(LinuxPerfNormProfiler.class) + // .addProfiler(LinuxPerfAsmProfiler.class) + // .resultFormat(ResultFormatType.CSV) + .build(); + new Runner(opt).run(); } } diff --git a/jetty-jmh/src/main/java/org/eclipse/jetty/util/thread/strategy/jmh/TestConnection.java b/jetty-jmh/src/main/java/org/eclipse/jetty/util/thread/strategy/jmh/TestConnection.java index 3a5d1853596..0f458fe95a1 100644 --- a/jetty-jmh/src/main/java/org/eclipse/jetty/util/thread/strategy/jmh/TestConnection.java +++ b/jetty-jmh/src/main/java/org/eclipse/jetty/util/thread/strategy/jmh/TestConnection.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -25,53 +25,54 @@ import java.util.Queue; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentLinkedQueue; +import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.thread.ExecutionStrategy.Producer; import org.eclipse.jetty.util.thread.Invocable; import org.openjdk.jmh.infra.Blackhole; - public class TestConnection implements Producer { private final TestServer _server; private final String _sessionid; private final boolean _sleeping; private final Queue> _queue = new ConcurrentLinkedQueue<>(); - + public TestConnection(TestServer server, boolean sleeping) { _server = server; - _sessionid = "SESSION-"+server.getRandom(100000000); + _sessionid = "SESSION-" + server.getRandom(100000000); _sleeping = sleeping; } - + @Override public Runnable produce() { CompletableFuture futureResult = _queue.poll(); - if (futureResult==null) + if (futureResult == null) return null; - + // The map will represent the request object - Map request = new HashMap<>(); - request.put("sessionid",_sessionid); - + Map request = new HashMap<>(); + request.put("sessionid", _sessionid); + int random = _server.getRandom(1000); - int uri = random%100; - boolean blocking = (random/10)>2; - int delay = (blocking && uri%4==1)?random/2:0; - request.put("uri",uri+".txt"); // one of 100 resources on server - request.put("blocking",blocking?"True":"False"); // one of 100 resources on server - request.put("delay",Integer.toString(delay)); // random processing delay 0-100ms on 25% of requests + int uri = random % 100; + boolean blocking = (random / 10) > 2; + int delay = (blocking && uri % 4 == 1) ? random / 2 : 0; + request.put("uri", uri + ".txt"); // one of 100 resources on server + request.put("blocking", blocking ? "True" : "False"); // one of 100 resources on server + request.put("delay", Integer.toString(delay)); // random processing delay 0-100ms on 25% of requests Blackhole.consumeCPU(_server.getRandom(500)); // random CPU - Handler handler = new Handler(request,futureResult); + Handler handler = new Handler(request, futureResult); return handler; } private class Handler implements Runnable, Invocable { - private final Map _request; + private final Map _request; private final CompletableFuture _futureResult; private final boolean _blocking; + public Handler(Map request, CompletableFuture futureResult) { _request = request; @@ -82,7 +83,7 @@ public class TestConnection implements Producer @Override public InvocationType getInvocationType() { - return _blocking?InvocationType.BLOCKING:InvocationType.NON_BLOCKING; + return _blocking ? InvocationType.BLOCKING : InvocationType.NON_BLOCKING; } @Override @@ -90,14 +91,14 @@ public class TestConnection implements Producer { // Build a response StringBuilder response = new StringBuilder(4096); - + try { // Get the request String uri = _request.get("uri"); - + // Obtain the session - Map session = _server.getSession(_request.get("sessionid")); + Map session = _server.getSession(_request.get("sessionid")); // Check we are authenticated String userid; @@ -105,30 +106,32 @@ public class TestConnection implements Producer { userid = session.get("userid"); Blackhole.consumeCPU(100); - if (userid==null) + if (userid == null) { - userid="USER-"+Math.abs(session.hashCode()); - session.put("userid",userid); + userid = "USER-" + Math.abs(session.hashCode()); + session.put("userid", userid); } } // simulate processing delay, blocking, etc. int delay = Integer.parseInt(_request.get("delay")); - if (delay>0) + if (delay > 0) { if (_sleeping) { try { - Thread.sleep(delay/8); + Thread.sleep(delay / 8); } - catch(InterruptedException e) - {} - } + catch (InterruptedException e) + { + Log.getLogger(TestConnection.class).ignore(e); + } + } else - Blackhole.consumeCPU(delay*150); + Blackhole.consumeCPU(delay * 150); } - + // get the uri response.append("URI: ").append(uri).append(System.lineSeparator()); @@ -137,29 +140,29 @@ public class TestConnection implements Producer if (file.exists()) { response.append("contentType: ").append("file").append(System.lineSeparator()); - response.append("lastModified: ").append(Long.toString(file.lastModified())).append(System.lineSeparator()); - response.append("contentLength: ").append(Long.toString(file.length())).append(System.lineSeparator()); + response.append("lastModified: ").append(file.lastModified()).append(System.lineSeparator()); + response.append("contentLength: ").append(file.length()).append(System.lineSeparator()); response.append("content: ").append("This should be content from a file, but lets pretend it was cached").append(System.lineSeparator()); } else { response.append("contentType: ").append("dynamic").append(System.lineSeparator()); response.append("This is content for ").append(uri) - .append(" generated for ").append(userid) - .append(" with session ").append(_request.get("sessionid")) - .append(" for user ").append(userid) - .append(" on thread ").append(Thread.currentThread()); + .append(" generated for ").append(userid) + .append(" with session ").append(_request.get("sessionid")) + .append(" for user ").append(userid) + .append(" on thread ").append(Thread.currentThread()); } - + Blackhole.consumeCPU(1000); } finally { _futureResult.complete(response.toString()); } - } + } } - + public void submit(CompletableFuture futureResult) { _queue.offer(futureResult); diff --git a/jetty-jmh/src/main/java/org/eclipse/jetty/util/thread/strategy/jmh/TestServer.java b/jetty-jmh/src/main/java/org/eclipse/jetty/util/thread/strategy/jmh/TestServer.java index 9a4f9b29258..63b39beff68 100644 --- a/jetty-jmh/src/main/java/org/eclipse/jetty/util/thread/strategy/jmh/TestServer.java +++ b/jetty-jmh/src/main/java/org/eclipse/jetty/util/thread/strategy/jmh/TestServer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -29,39 +29,37 @@ import java.util.concurrent.ThreadLocalRandom; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.eclipse.jetty.util.thread.TryExecutor; - public class TestServer implements Executor, TryExecutor { - private final ConcurrentMap> _sessions= new ConcurrentHashMap<>(); + private final ConcurrentMap> _sessions = new ConcurrentHashMap<>(); private final QueuedThreadPool _threadpool = new QueuedThreadPool(200); private final File _docroot; TestServer(File docroot) { _threadpool.setReservedThreads(20); - _docroot=docroot; + _docroot = docroot; } - + TestServer() { - this(new File("/tmp/")); + this(new File(System.getProperty("java.io.tmpdir"))); } - - - public Map getSession(String sessionid) + + public Map getSession(String sessionid) { - Map session = _sessions.get(sessionid); - if (session==null) + Map session = _sessions.get(sessionid); + if (session == null) { session = new HashMap<>(); - session.put("id",sessionid); - Map s =_sessions.putIfAbsent(sessionid,session); - if (s!=null) - session=s; + session.put("id", sessionid); + Map s = _sessions.putIfAbsent(sessionid, session); + if (s != null) + session = s; } return session; } - + public int getRandom(int max) { return ThreadLocalRandom.current().nextInt(max); @@ -78,7 +76,7 @@ public class TestServer implements Executor, TryExecutor { return _threadpool.tryExecute(task); } - + public void start() throws Exception { _threadpool.start(); @@ -88,10 +86,9 @@ public class TestServer implements Executor, TryExecutor { _threadpool.stop(); } - + public File getFile(String path) { - return new File(_docroot,path); + return new File(_docroot, path); } - } diff --git a/jetty-jmx/pom.xml b/jetty-jmx/pom.xml index f7722c06714..bd7f24d4758 100644 --- a/jetty-jmx/pom.xml +++ b/jetty-jmx/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 jetty-jmx diff --git a/jetty-jmx/src/main/config/etc/jetty-jmx-remote.xml b/jetty-jmx/src/main/config/etc/jetty-jmx-remote.xml index 1003ad7e261..f1c9b212462 100644 --- a/jetty-jmx/src/main/config/etc/jetty-jmx-remote.xml +++ b/jetty-jmx/src/main/config/etc/jetty-jmx-remote.xml @@ -1,5 +1,4 @@ - - + diff --git a/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ConnectorServer.java b/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ConnectorServer.java index 4e45f8973a5..2d8b10f29eb 100644 --- a/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ConnectorServer.java +++ b/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ConnectorServer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -33,7 +33,6 @@ import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.function.IntConsumer; - import javax.management.MBeanServer; import javax.management.ObjectName; import javax.management.remote.JMXConnectorServer; @@ -53,10 +52,10 @@ import org.eclipse.jetty.util.thread.ShutdownThread; *

        LifeCycle wrapper for JMXConnectorServer.

        *

        This class provides the following facilities:

        *
          - *
        • participates in the {@code Server} lifecycle
        • - *
        • starts the RMI registry if not there already
        • - *
        • allows to bind the RMI registry and the RMI server to the loopback interface
        • - *
        • makes it easy to use TLS for the JMX communication
        • + *
        • participates in the {@code Server} lifecycle
        • + *
        • starts the RMI registry if not there already
        • + *
        • allows to bind the RMI registry and the RMI server to the loopback interface
        • + *
        • makes it easy to use TLS for the JMX communication
        • *
        */ public class ConnectorServer extends AbstractLifeCycle @@ -77,7 +76,7 @@ public class ConnectorServer extends AbstractLifeCycle * Constructs a ConnectorServer * * @param serviceURL the address of the new ConnectorServer - * @param name object name string to be assigned to ConnectorServer bean + * @param name object name string to be assigned to ConnectorServer bean */ public ConnectorServer(JMXServiceURL serviceURL, String name) { @@ -87,12 +86,12 @@ public class ConnectorServer extends AbstractLifeCycle /** * Constructs a ConnectorServer * - * @param svcUrl the address of the new ConnectorServer + * @param svcUrl the address of the new ConnectorServer * @param environment a set of attributes to control the new ConnectorServer's behavior. - * This parameter can be null. Keys in this map must - * be Strings. The appropriate type of each associated value depends on - * the attribute. The contents of environment are not changed by this call. - * @param name object name string to be assigned to ConnectorServer bean + * This parameter can be null. Keys in this map must + * be Strings. The appropriate type of each associated value depends on + * the attribute. The contents of environment are not changed by this call. + * @param name object name string to be assigned to ConnectorServer bean */ public ConnectorServer(JMXServiceURL svcUrl, Map environment, String name) { diff --git a/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/MBeanContainer.java b/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/MBeanContainer.java index 950251b1e49..2ce8320c156 100644 --- a/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/MBeanContainer.java +++ b/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/MBeanContainer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,18 +19,27 @@ package org.eclipse.jetty.jmx; import java.io.IOException; +import java.lang.reflect.Constructor; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicInteger; - +import java.util.stream.Collectors; import javax.management.InstanceNotFoundException; +import javax.management.MBeanInfo; import javax.management.MBeanRegistrationException; import javax.management.MBeanServer; import javax.management.ObjectName; +import javax.management.modelmbean.ModelMBean; +import org.eclipse.jetty.util.Loader; +import org.eclipse.jetty.util.StringUtil; +import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.component.Container; import org.eclipse.jetty.util.component.ContainerLifeCycle; @@ -45,15 +54,197 @@ import org.eclipse.jetty.util.log.Logger; @ManagedObject("The component that registers beans as MBeans") public class MBeanContainer implements Container.InheritedListener, Dumpable, Destroyable { - private final static Logger LOG = Log.getLogger(MBeanContainer.class.getName()); - private final static ConcurrentMap __unique = new ConcurrentHashMap<>(); + private static final Logger LOG = Log.getLogger(MBeanContainer.class.getName()); + private static final ConcurrentMap __unique = new ConcurrentHashMap<>(); private static final Container ROOT = new ContainerLifeCycle(); private final MBeanServer _mbeanServer; + private final boolean _useCacheForOtherClassLoaders; + private final ConcurrentMap _metaData = new ConcurrentHashMap<>(); private final ConcurrentMap _beans = new ConcurrentHashMap<>(); private final ConcurrentMap _mbeans = new ConcurrentHashMap<>(); private String _domain = null; + /** + * Constructs MBeanContainer + * + * @param server instance of MBeanServer for use by container + */ + public MBeanContainer(MBeanServer server) + { + this(server, true); + } + + /** + * Constructs MBeanContainer + * + * @param server instance of MBeanServer for use by container + * @param cacheOtherClassLoaders If true, MBeans from other classloaders (eg WebAppClassLoader) will be cached. + * The cache is never flushed, so this should be false if some classloaders do not live forever. + */ + public MBeanContainer(MBeanServer server, boolean cacheOtherClassLoaders) + { + _mbeanServer = server; + _useCacheForOtherClassLoaders = cacheOtherClassLoaders; + } + + /** + * Retrieve instance of MBeanServer used by container + * + * @return instance of MBeanServer + */ + public MBeanServer getMBeanServer() + { + return _mbeanServer; + } + + @ManagedAttribute(value = "Whether to use the cache for MBeans loaded by other ClassLoaders", readonly = true) + public boolean isUseCacheForOtherClassLoaders() + { + return _useCacheForOtherClassLoaders; + } + + /** + * Set domain to be used to add MBeans + * + * @param domain domain name + */ + public void setDomain(String domain) + { + _domain = domain; + } + + /** + * Retrieve domain name used to add MBeans + * + * @return domain name + */ + @ManagedAttribute("The default ObjectName domain") + public String getDomain() + { + return _domain; + } + + /** + *

        Creates an ObjectMBean for the given object.

        + *

        Attempts to create an ObjectMBean for the object by searching the package + * and class name space. For example an object of the type:

        + *
        +     * class com.acme.MyClass extends com.acme.util.BaseClass implements com.acme.Iface
        +     * 
        + *

        then this method would look for the following classes:

        + *
          + *
        • com.acme.jmx.MyClassMBean
        • + *
        • com.acme.util.jmx.BaseClassMBean
        • + *
        • org.eclipse.jetty.jmx.ObjectMBean
        • + *
        + * + * @param o The object + * @return A new instance of an MBean for the object or null. + */ + public Object mbeanFor(Object o) + { + return mbeanFor(this, o); + } + + static Object mbeanFor(MBeanContainer container, Object o) + { + if (o == null) + return null; + Object mbean = findMetaData(container, o.getClass()).newInstance(o); + if (mbean instanceof ObjectMBean) + ((ObjectMBean)mbean).setMBeanContainer(container); + if (LOG.isDebugEnabled()) + { + LOG.debug("MBean for {} is {}", o, mbean); + if (mbean instanceof ObjectMBean) + { + MBeanInfo info = ((ObjectMBean)mbean).getMBeanInfo(); + for (Object a : info.getAttributes()) + { + LOG.debug(" {}", a); + } + for (Object a : info.getOperations()) + { + LOG.debug(" {}", a); + } + } + } + return mbean; + } + + static MetaData findMetaData(MBeanContainer container, Class klass) + { + if (klass == null) + return null; + MetaData metaData = getMetaData(container, klass); + if (metaData != null) + { + if (LOG.isDebugEnabled()) + LOG.debug("Found cached {}", metaData); + return metaData; + } + return newMetaData(container, klass); + } + + private static MetaData getMetaData(MBeanContainer container, Class klass) + { + return container == null ? null : container._metaData.get(klass); + } + + private static MetaData newMetaData(MBeanContainer container, Class klass) + { + if (klass == null) + return null; + if (klass == Object.class) + return new MetaData(klass, null, null, Collections.emptyList()); + + List interfaces = Arrays.stream(klass.getInterfaces()) + .map(intf -> findMetaData(container, intf)) + .collect(Collectors.toList()); + MetaData metaData = new MetaData(klass, findConstructor(klass), findMetaData(container, klass.getSuperclass()), interfaces); + + if (container != null) + { + if (container.isUseCacheForOtherClassLoaders() || klass.getClassLoader() == container.getClass().getClassLoader()) + { + MetaData existing = container._metaData.putIfAbsent(klass, metaData); + if (existing != null) + metaData = existing; + if (LOG.isDebugEnabled()) + LOG.debug("Cached {}", metaData); + } + } + + return metaData; + } + + private static Constructor findConstructor(Class klass) + { + Package pkg = klass.getPackage(); + if (pkg == null) + return null; + String pName = pkg.getName(); + String cName = klass.getName().substring(pName.isEmpty() ? 0 : pName.length() + 1); + String mName = pName + ".jmx." + cName + "MBean"; + try + { + Class mbeanClass = Loader.loadClass(klass, mName); + Constructor constructor = ModelMBean.class.isAssignableFrom(mbeanClass) + ? mbeanClass.getConstructor() + : mbeanClass.getConstructor(Object.class); + if (LOG.isDebugEnabled()) + LOG.debug("Found MBean wrapper: {} for {}", mName, klass.getName()); + return constructor; + } + catch (Throwable x) + { + if (LOG.isDebugEnabled()) + LOG.debug("MBean wrapper not found: {} for {}", mName, klass.getName()); + return null; + } + } + /** * Lookup an object name by instance * @@ -81,47 +272,6 @@ public class MBeanContainer implements Container.InheritedListener, Dumpable, De return null; } - /** - * Constructs MBeanContainer - * - * @param server instance of MBeanServer for use by container - */ - public MBeanContainer(MBeanServer server) - { - _mbeanServer = server; - } - - /** - * Retrieve instance of MBeanServer used by container - * - * @return instance of MBeanServer - */ - public MBeanServer getMBeanServer() - { - return _mbeanServer; - } - - /** - * Set domain to be used to add MBeans - * - * @param domain domain name - */ - public void setDomain(String domain) - { - _domain = domain; - } - - /** - * Retrieve domain name used to add MBeans - * - * @return domain name - */ - public String getDomain() - { - return _domain; - } - - @Override public void beanAdded(Container parent, Object obj) { @@ -154,26 +304,34 @@ public class MBeanContainer implements Container.InheritedListener, Dumpable, De try { // Create an MBean for the object. - Object mbean = ObjectMBean.mbeanFor(obj); + Object mbean = mbeanFor(obj); if (mbean == null) return; ObjectName objectName = null; if (mbean instanceof ObjectMBean) { - ((ObjectMBean)mbean).setMBeanContainer(this); objectName = ((ObjectMBean)mbean).getObjectName(); } // No override of the mbean's ObjectName, so make a generic one. if (objectName == null) { + Class klass = obj.getClass(); + while (klass.isArray()) + { + klass = klass.getComponentType(); + } + // If no explicit domain, create one. String domain = _domain; if (domain == null) - domain = obj.getClass().getPackage().getName(); + { + Package pkg = klass.getPackage(); + domain = pkg == null ? "" : pkg.getName(); + } - String type = obj.getClass().getName().toLowerCase(Locale.ENGLISH); + String type = klass.getName().toLowerCase(Locale.ENGLISH); int dot = type.lastIndexOf('.'); if (dot >= 0) type = type.substring(dot + 1); @@ -242,36 +400,28 @@ public class MBeanContainer implements Container.InheritedListener, Dumpable, De */ public String makeName(String basis) { - if (basis == null) - return null; - return basis - .replace(':', '_') - .replace('*', '_') - .replace('?', '_') - .replace('=', '_') - .replace(',', '_') - .replace(' ', '_'); + return StringUtil.sanitizeFileSystemName(basis); } @Override public void dump(Appendable out, String indent) throws IOException { - ContainerLifeCycle.dumpObject(out,this); - ContainerLifeCycle.dump(out, indent, _mbeans.entrySet()); + Dumpable.dumpObjects(out, indent, this, _mbeans.entrySet()); } @Override public String dump() { - return ContainerLifeCycle.dump(this); + return Dumpable.dump(this); } @Override public void destroy() { + _metaData.clear(); _mbeans.values().stream() - .filter(Objects::nonNull) - .forEach(this::unregister); + .filter(Objects::nonNull) + .forEach(this::unregister); _mbeans.clear(); _beans.clear(); } diff --git a/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/MetaData.java b/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/MetaData.java new file mode 100644 index 00000000000..9519932eeb9 --- /dev/null +++ b/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/MetaData.java @@ -0,0 +1,585 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.jmx; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Array; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.stream.Collectors; +import javax.management.Attribute; +import javax.management.AttributeNotFoundException; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanConstructorInfo; +import javax.management.MBeanException; +import javax.management.MBeanInfo; +import javax.management.MBeanNotificationInfo; +import javax.management.MBeanOperationInfo; +import javax.management.MBeanParameterInfo; +import javax.management.ObjectName; +import javax.management.ReflectionException; +import javax.management.modelmbean.ModelMBean; + +import org.eclipse.jetty.util.annotation.ManagedAttribute; +import org.eclipse.jetty.util.annotation.ManagedObject; +import org.eclipse.jetty.util.annotation.ManagedOperation; +import org.eclipse.jetty.util.annotation.Name; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + +class MetaData +{ + private static final Logger LOG = Log.getLogger(MetaData.class); + private static final MBeanAttributeInfo[] NO_ATTRIBUTES = new MBeanAttributeInfo[0]; + private static final MBeanConstructorInfo[] NO_CONSTRUCTORS = new MBeanConstructorInfo[0]; + private static final MBeanOperationInfo[] NO_OPERATIONS = new MBeanOperationInfo[0]; + private static final MBeanNotificationInfo[] NO_NOTIFICATIONS = new MBeanNotificationInfo[0]; + + private final Map _attributes = new HashMap<>(); + private final Map _operations = new HashMap<>(); + private final Class _klass; + private final MetaData _parent; + private final List _interfaces; + private final Constructor _constructor; + private final MBeanInfo _info; + + MetaData(Class klass, Constructor constructor, MetaData parent, List interfaces) + { + _klass = klass; + _parent = parent; + _interfaces = interfaces; + _constructor = constructor; + if (_constructor != null) + parseMethods(klass, _constructor.getDeclaringClass()); + else + parseMethods(klass); + _info = buildMBeanInfo(klass); + } + + Object newInstance(Object bean) + { + Object mbean; + if (_constructor != null) + mbean = newInstance(_constructor, bean); + else if (_parent != null) + mbean = _parent.newInstance(bean); + else + mbean = new ObjectMBean(bean); + return mbean; + } + + MBeanInfo getMBeanInfo() + { + return _info; + } + + Object getAttribute(String name, ObjectMBean mbean) throws AttributeNotFoundException, ReflectionException, MBeanException + { + AttributeInfo info = findAttribute(name); + if (info == null) + throw new AttributeNotFoundException(name); + return info.getAttribute(mbean); + } + + void setAttribute(Attribute attribute, ObjectMBean mbean) throws AttributeNotFoundException, ReflectionException, MBeanException + { + if (attribute == null) + return; + String name = attribute.getName(); + AttributeInfo info = findAttribute(name); + if (info == null) + throw new AttributeNotFoundException(name); + info.setAttribute(attribute.getValue(), mbean); + } + + private AttributeInfo findAttribute(String name) + { + if (name == null) + return null; + + AttributeInfo result = null; + for (MetaData intf : _interfaces) + { + AttributeInfo r = intf.findAttribute(name); + if (r != null) + result = r; + } + + if (_parent != null) + { + AttributeInfo r = _parent.findAttribute(name); + if (r != null) + result = r; + } + + AttributeInfo r = _attributes.get(name); + if (r != null) + result = r; + + return result; + } + + Object invoke(String name, String[] params, Object[] args, ObjectMBean mbean) throws ReflectionException, MBeanException + { + String signature = signature(name, params); + OperationInfo info = findOperation(signature); + if (info == null) + throw new ReflectionException(new NoSuchMethodException(signature)); + return info.invoke(args, mbean); + } + + private OperationInfo findOperation(String signature) + { + OperationInfo result = null; + for (MetaData intf : _interfaces) + { + OperationInfo r = intf.findOperation(signature); + if (r != null) + result = r; + } + + if (_parent != null) + { + OperationInfo r = _parent.findOperation(signature); + if (r != null) + result = r; + } + + OperationInfo r = _operations.get(signature); + if (r != null) + result = r; + + return result; + } + + private static Object newInstance(Constructor constructor, Object bean) + { + try + { + Object mbean = constructor.getParameterCount() == 0 ? constructor.newInstance() : constructor.newInstance(bean); + if (mbean instanceof ModelMBean) + ((ModelMBean)mbean).setManagedResource(bean, "objectReference"); + return mbean; + } + catch (Throwable x) + { + return null; + } + } + + private void parseMethods(Class... classes) + { + for (Class klass : classes) + { + // Only work on the public method of the class, not of the hierarchy. + for (Method method : klass.getDeclaredMethods()) + { + if (!Modifier.isPublic(method.getModifiers())) + continue; + ManagedAttribute attribute = method.getAnnotation(ManagedAttribute.class); + if (attribute != null) + { + AttributeInfo info = new AttributeInfo(attribute, method); + if (LOG.isDebugEnabled()) + LOG.debug("Found attribute {} for {}: {}", info._name, klass.getName(), info); + _attributes.put(info._name, info); + } + ManagedOperation operation = method.getAnnotation(ManagedOperation.class); + if (operation != null) + { + OperationInfo info = new OperationInfo(operation, method); + if (LOG.isDebugEnabled()) + LOG.debug("Found operation {} for {}: {}", info._name, klass.getName(), info); + _operations.put(info._name, info); + } + } + } + } + + static String toAttributeName(String methodName) + { + String attributeName = methodName; + if (methodName.startsWith("get") || methodName.startsWith("set")) + attributeName = attributeName.substring(3); + else if (methodName.startsWith("is")) + attributeName = attributeName.substring(2); + return attributeName.substring(0, 1).toLowerCase(Locale.ENGLISH) + attributeName.substring(1); + } + + private static boolean isManagedObject(Class klass) + { + if (klass.isArray()) + klass = klass.getComponentType(); + if (klass.isPrimitive()) + return false; + while (klass != null) + { + if (klass.isAnnotationPresent(ManagedObject.class)) + return true; + klass = klass.getSuperclass(); + } + return false; + } + + private static String signature(String name, String[] params) + { + return String.format("%s(%s)", name, String.join(",", params)); + } + + private static String signature(Method method) + { + String signature = Arrays.stream(method.getParameterTypes()) + .map(Class::getName) + .collect(Collectors.joining(",")); + return String.format("%s(%s)", method.getName(), signature); + } + + private MBeanInfo buildMBeanInfo(Class klass) + { + ManagedObject managedObject = klass.getAnnotation(ManagedObject.class); + String description = managedObject == null ? "" : managedObject.value(); + + Map attributeInfos = new HashMap<>(); + collectMBeanAttributeInfos(attributeInfos); + + Map operationInfos = new HashMap<>(); + collectMBeanOperationInfos(operationInfos); + + MBeanInfo mbeanInfo = _parent == null ? null : _parent.getMBeanInfo(); + MBeanAttributeInfo[] attributes = attributeInfos.values().toArray(NO_ATTRIBUTES); + MBeanConstructorInfo[] constructors = mbeanInfo == null ? NO_CONSTRUCTORS : mbeanInfo.getConstructors(); + MBeanOperationInfo[] operations = operationInfos.values().toArray(NO_OPERATIONS); + MBeanNotificationInfo[] notifications = mbeanInfo == null ? NO_NOTIFICATIONS : mbeanInfo.getNotifications(); + return new MBeanInfo(klass.getName(), description, attributes, constructors, operations, notifications); + } + + private void collectMBeanAttributeInfos(Map attributeInfos) + { + // Start with interfaces, overwrite with superClass, then overwrite with local attributes. + for (MetaData intf : _interfaces) + { + intf.collectMBeanAttributeInfos(attributeInfos); + } + if (_parent != null) + { + MBeanAttributeInfo[] parentAttributes = _parent.getMBeanInfo().getAttributes(); + for (MBeanAttributeInfo parentAttribute : parentAttributes) + { + attributeInfos.put(parentAttribute.getName(), parentAttribute); + } + } + for (Map.Entry entry : _attributes.entrySet()) + { + attributeInfos.put(entry.getKey(), entry.getValue()._info); + } + } + + private void collectMBeanOperationInfos(Map operationInfos) + { + // Start with interfaces, overwrite with superClass, then overwrite with local operations. + for (MetaData intf : _interfaces) + { + intf.collectMBeanOperationInfos(operationInfos); + } + if (_parent != null) + { + MBeanOperationInfo[] parentOperations = _parent.getMBeanInfo().getOperations(); + for (MBeanOperationInfo parentOperation : parentOperations) + { + String signature = signature(parentOperation.getName(), Arrays.stream(parentOperation.getSignature()).map(MBeanParameterInfo::getType).toArray(String[]::new)); + operationInfos.put(signature, parentOperation); + } + } + for (Map.Entry entry : _operations.entrySet()) + { + operationInfos.put(entry.getKey(), entry.getValue()._info); + } + } + + private static MBeanException toMBeanException(InvocationTargetException x) + { + Throwable cause = x.getCause(); + if (cause instanceof Exception) + return new MBeanException((Exception)cause); + else + return new MBeanException(x); + } + + @Override + public String toString() + { + return String.format("%s@%x[%s, attrs=%s, opers=%s]", getClass().getSimpleName(), hashCode(), + _klass.getName(), _attributes.keySet(), _operations.keySet()); + } + + private static class AttributeInfo + { + private final String _name; + private final Method _getter; + private final Method _setter; + private final boolean _proxied; + private final boolean _convert; + private final MBeanAttributeInfo _info; + + private AttributeInfo(ManagedAttribute attribute, Method getter) + { + String name = attribute.name(); + if ("".equals(name)) + name = toAttributeName(getter.getName()); + _name = name; + + _getter = getter; + + boolean readOnly = attribute.readonly(); + _setter = readOnly ? null : findSetter(attribute, getter, name); + + _proxied = attribute.proxied(); + + Class returnType = getter.getReturnType(); + _convert = isManagedObject(returnType); + String signature = _convert + ? returnType.isArray() + ? ObjectName[].class.getName() + : ObjectName.class.getName() + : returnType.getName(); + + String description = attribute.value(); + _info = new MBeanAttributeInfo(name, signature, description, true, + _setter != null, getter.getName().startsWith("is")); + } + + Object getAttribute(ObjectMBean mbean) throws ReflectionException, MBeanException + { + try + { + Object target = mbean.getManagedObject(); + if (_proxied || _getter.getDeclaringClass().isInstance(mbean)) + target = mbean; + Object result = _getter.invoke(target); + if (result == null) + return null; + if (!_convert) + return result; + if (!_getter.getReturnType().isArray()) + return mbean.findObjectName(result); + int length = Array.getLength(result); + ObjectName[] names = new ObjectName[length]; + for (int i = 0; i < length; ++i) + { + names[i] = mbean.findObjectName(Array.get(result, i)); + } + return names; + } + catch (InvocationTargetException x) + { + throw toMBeanException(x); + } + catch (Exception x) + { + throw new ReflectionException(x); + } + } + + void setAttribute(Object value, ObjectMBean mbean) throws ReflectionException, MBeanException + { + if (LOG.isDebugEnabled()) + LOG.debug("setAttribute {}.{}={} {}", mbean, _info.getName(), value, _info); + try + { + if (_setter == null) + return; + Object target = mbean.getManagedObject(); + if (_proxied || _setter.getDeclaringClass().isInstance(mbean)) + target = mbean; + if (!_convert || value == null) + { + _setter.invoke(target, value); + return; + } + if (!_getter.getReturnType().isArray()) + { + value = mbean.findBean((ObjectName)value); + _setter.invoke(target, value); + return; + } + ObjectName[] names = (ObjectName[])value; + Object result = new Object[names.length]; + for (int i = 0; i < names.length; ++i) + { + Array.set(result, i, mbean.findBean(names[i])); + } + _setter.invoke(target, result); + } + catch (InvocationTargetException x) + { + throw toMBeanException(x); + } + catch (Exception x) + { + throw new ReflectionException(x); + } + } + + private Method findSetter(ManagedAttribute attribute, Method getter, String name) + { + String setterName = attribute.setter(); + if ("".equals(setterName)) + setterName = "set" + name.substring(0, 1).toUpperCase(Locale.ENGLISH) + name.substring(1); + + Method setter = null; + Class klass = getter.getDeclaringClass(); + for (Method method : klass.getMethods()) + { + if (method.getName().equals(setterName) && method.getParameterCount() == 1) + { + if (setter != null) + { + LOG.info("Multiple setters for mbean attribute {} in {}", name, klass); + continue; + } + if (!getter.getReturnType().equals(method.getParameterTypes()[0])) + { + LOG.info("Getter/setter type mismatch for mbean attribute {} in {}", name, klass); + continue; + } + setter = method; + } + } + + return setter; + } + + @Override + public String toString() + { + return String.format("%s@%x[%s,proxied=%b,convert=%b,info=%s]", getClass().getSimpleName(), hashCode(), + _name, _proxied, _convert, _info); + } + } + + private static class OperationInfo + { + private final String _name; + private final Method _method; + private final boolean _proxied; + private final boolean _convert; + private final MBeanOperationInfo _info; + + private OperationInfo(ManagedOperation operation, Method method) + { + _name = signature(method); + + _method = method; + + _proxied = operation.proxied(); + + Class returnType = method.getReturnType(); + _convert = isManagedObject(returnType); + String returnSignature = _convert + ? returnType.isArray() + ? ObjectName[].class.getName() + : ObjectName.class.getName() + : returnType.getName(); + + String impactName = operation.impact(); + int impact = MBeanOperationInfo.UNKNOWN; + if ("ACTION".equals(impactName)) + impact = MBeanOperationInfo.ACTION; + else if ("INFO".equals(impactName)) + impact = MBeanOperationInfo.INFO; + else if ("ACTION_INFO".equals(impactName)) + impact = MBeanOperationInfo.ACTION_INFO; + + String description = operation.value(); + MBeanParameterInfo[] parameterInfos = parameters(method.getParameterTypes(), method.getParameterAnnotations()); + _info = new MBeanOperationInfo(method.getName(), description, parameterInfos, returnSignature, impact); + } + + public Object invoke(Object[] args, ObjectMBean mbean) throws ReflectionException, MBeanException + { + if (LOG.isDebugEnabled()) + LOG.debug("invoke {}.{}({}) {}", mbean, _info.getName(), Arrays.asList(args), _info); + try + { + Object target = mbean.getManagedObject(); + if (_proxied || _method.getDeclaringClass().isInstance(mbean)) + target = mbean; + Object result = _method.invoke(target, args); + if (result == null) + return null; + if (!_convert) + return result; + if (!_method.getReturnType().isArray()) + return mbean.findObjectName(result); + int length = Array.getLength(result); + ObjectName[] names = new ObjectName[length]; + for (int i = 0; i < length; ++i) + { + names[i] = mbean.findObjectName(Array.get(result, i)); + } + return names; + } + catch (InvocationTargetException x) + { + throw toMBeanException(x); + } + catch (Exception x) + { + throw new ReflectionException(x); + } + } + + private static MBeanParameterInfo[] parameters(Class[] parameterTypes, Annotation[][] parametersAnnotations) + { + MBeanParameterInfo[] result = new MBeanParameterInfo[parameterTypes.length]; + for (int i = 0; i < parametersAnnotations.length; i++) + { + MBeanParameterInfo info = null; + String typeName = parameterTypes[i].getName(); + Annotation[] parameterAnnotations = parametersAnnotations[i]; + for (Annotation parameterAnnotation : parameterAnnotations) + { + if (parameterAnnotation instanceof Name) + { + Name name = (Name)parameterAnnotation; + info = result[i] = new MBeanParameterInfo(name.value(), typeName, name.description()); + break; + } + } + if (info == null) + result[i] = new MBeanParameterInfo("p" + i, typeName, ""); + } + return result; + } + + @Override + public String toString() + { + return String.format("%s@%x[%s,proxied=%b,convert=%b]", getClass().getSimpleName(), hashCode(), + _name, _proxied, _convert); + } + } +} diff --git a/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ObjectMBean.java b/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ObjectMBean.java index e7010719122..aa40e5cf17d 100644 --- a/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ObjectMBean.java +++ b/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ObjectMBean.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,42 +18,15 @@ package org.eclipse.jetty.jmx; -import java.lang.annotation.Annotation; -import java.lang.reflect.Array; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; - import javax.management.Attribute; import javax.management.AttributeList; import javax.management.AttributeNotFoundException; import javax.management.DynamicMBean; -import javax.management.MBeanAttributeInfo; -import javax.management.MBeanConstructorInfo; import javax.management.MBeanException; import javax.management.MBeanInfo; -import javax.management.MBeanNotificationInfo; -import javax.management.MBeanOperationInfo; -import javax.management.MBeanParameterInfo; import javax.management.ObjectName; import javax.management.ReflectionException; -import javax.management.modelmbean.ModelMBean; -import org.eclipse.jetty.util.Loader; -import org.eclipse.jetty.util.TypeUtil; -import org.eclipse.jetty.util.annotation.ManagedAttribute; -import org.eclipse.jetty.util.annotation.ManagedObject; -import org.eclipse.jetty.util.annotation.ManagedOperation; -import org.eclipse.jetty.util.annotation.Name; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -72,119 +45,11 @@ import org.eclipse.jetty.util.log.Logger; public class ObjectMBean implements DynamicMBean { private static final Logger LOG = Log.getLogger(ObjectMBean.class); - private static final Class[] OBJ_ARG = new Class[]{Object.class}; - private static final String OBJECT_NAME_CLASS = ObjectName.class.getName(); - private static final String OBJECT_NAME_ARRAY_CLASS = ObjectName[].class.getName(); - protected Object _managed; - private MBeanInfo _info; - private Map _getters = new HashMap<>(); - private Map _setters = new HashMap<>(); - private Map _methods = new HashMap<>(); - // set of attributes mined from influence hierarchy - private Set _attributes = new HashSet<>(); - // set of attributes that are automatically converted to ObjectName - // as they represent other managed beans which can be linked to - private Set _convert = new HashSet<>(); - private ClassLoader _loader; + protected final Object _managed; + private MetaData _metaData; private MBeanContainer _mbeanContainer; - /** - *

        Creates an ObjectMBean for the given object.

        - *

        Attempts to create an ObjectMBean for the object by searching the package - * and class name space. For example an object of the type:

        - *
        -     * class com.acme.MyClass extends com.acme.util.BaseClass implements com.acme.Iface
        -     * 
        - *

        then this method would look for the following classes:

        - *
          - *
        • com.acme.jmx.MyClassMBean
        • - *
        • com.acme.util.jmx.BaseClassMBean
        • - *
        • org.eclipse.jetty.jmx.ObjectMBean
        • - *
        - * - * @param o The object - * @return A new instance of an MBean for the object or null. - */ - public static Object mbeanFor(Object o) - { - try - { - Class oClass = o.getClass(); - while (oClass != null) - { - String pName = oClass.getPackage().getName(); - String cName = oClass.getName().substring(pName.length() + 1); - String mName = pName + ".jmx." + cName + "MBean"; - - try - { - Class mClass; - try - { - // Look for an MBean class from the same loader that loaded the original class - mClass = (Object.class.equals(oClass)) ? oClass = ObjectMBean.class : Loader.loadClass(oClass, mName); - } - catch (ClassNotFoundException e) - { - // Not found, so if not the same as the thread context loader, try that. - if (Thread.currentThread().getContextClassLoader() == oClass.getClassLoader()) - throw e; - LOG.ignore(e); - mClass = Loader.loadClass(oClass, mName); - } - - if (LOG.isDebugEnabled()) - LOG.debug("ObjectMBean: mbeanFor {} mClass={}", o, mClass); - - Object mbean = null; - try - { - Constructor constructor = mClass.getConstructor(OBJ_ARG); - mbean = constructor.newInstance(o); - } - catch (Exception e) - { - LOG.ignore(e); - if (ModelMBean.class.isAssignableFrom(mClass)) - { - mbean = mClass.getDeclaredConstructor().newInstance(); - ((ModelMBean)mbean).setManagedResource(o, "objectReference"); - } - } - - if (LOG.isDebugEnabled()) - LOG.debug("mbeanFor {} is {}", o, mbean); - - return mbean; - } - catch (ClassNotFoundException e) - { - // The code below was modified to fix bugs 332200 and JETTY-1416 - // The issue was caused by additional information added to the - // message after the class name when running in Apache Felix, - // as well as before the class name when running in JBoss. - if (e.getMessage().contains(mName)) - LOG.ignore(e); - else - LOG.warn(e); - } - catch (Throwable e) - { - LOG.warn(e); - } - - oClass = oClass.getSuperclass(); - } - } - catch (Exception e) - { - LOG.ignore(e); - } - - return null; - } - /** * Creates a new ObjectMBean wrapping the given {@code managedObject}. * @@ -193,7 +58,6 @@ public class ObjectMBean implements DynamicMBean public ObjectMBean(Object managedObject) { _managed = managedObject; - _loader = Thread.currentThread().getContextClassLoader(); } /** @@ -257,177 +121,34 @@ public class ObjectMBean implements DynamicMBean return this._mbeanContainer; } - @Override - public MBeanInfo getMBeanInfo() + /** + * @param o the object to wrap as MBean + * @return a new instance of an MBean for the object or null if the MBean cannot be created + * @deprecated Use {@link MBeanContainer#mbeanFor(Object)} instead + */ + @Deprecated + public static Object mbeanFor(Object o) { - try - { - if (_info == null) - { - String desc = null; - List attributes = new ArrayList<>(); - List operations = new ArrayList<>(); - - // Find list of classes that can influence the mbean - Class o_class = _managed.getClass(); - List> influences = new ArrayList<>(); - influences.add(this.getClass()); // always add MBean itself - influences = findInfluences(influences, _managed.getClass()); - - if (LOG.isDebugEnabled()) - LOG.debug("Influence Count: {}", influences.size()); - - // Process Type Annotations - ManagedObject primary = o_class.getAnnotation(ManagedObject.class); - - if (primary != null) - { - desc = primary.value(); - } - else - { - if (LOG.isDebugEnabled()) - LOG.debug("No @ManagedObject declared on {}", _managed.getClass()); - } - - // For each influence - for (Class oClass : influences) - { - ManagedObject typeAnnotation = oClass.getAnnotation(ManagedObject.class); - - if (LOG.isDebugEnabled()) - LOG.debug("Influenced by: " + oClass.getCanonicalName()); - - if (typeAnnotation == null) - { - if (LOG.isDebugEnabled()) - LOG.debug("Annotations not found for: {}", oClass.getCanonicalName()); - continue; - } - - // Process Method Annotations - - for (Method method : oClass.getDeclaredMethods()) - { - ManagedAttribute methodAttributeAnnotation = method.getAnnotation(ManagedAttribute.class); - - if (methodAttributeAnnotation != null) - { - if (LOG.isDebugEnabled()) - LOG.debug("Attribute Annotation found for: {}", method.getName()); - MBeanAttributeInfo mai = defineAttribute(method, methodAttributeAnnotation); - if (mai != null) - attributes.add(mai); - } - - ManagedOperation methodOperationAnnotation = method.getAnnotation(ManagedOperation.class); - - if (methodOperationAnnotation != null) - { - if (LOG.isDebugEnabled()) - LOG.debug("Method Annotation found for: {}", method.getName()); - MBeanOperationInfo oi = defineOperation(method, methodOperationAnnotation); - if (oi != null) - operations.add(oi); - } - } - } - - _info = new MBeanInfo(o_class.getName(), - desc, - attributes.toArray(new MBeanAttributeInfo[attributes.size()]), - new MBeanConstructorInfo[0], - operations.toArray(new MBeanOperationInfo[operations.size()]), - new MBeanNotificationInfo[0]); - } - } - catch (RuntimeException e) - { - LOG.warn(e); - throw e; - } - return _info; + return MBeanContainer.mbeanFor(null, o); } @Override - public Object getAttribute(String name) throws AttributeNotFoundException, ReflectionException + public MBeanInfo getMBeanInfo() { - Method getter = _getters.get(name); - if (getter == null) - throw new AttributeNotFoundException(name); + return metaData().getMBeanInfo(); + } + @Override + public Object getAttribute(String name) throws AttributeNotFoundException, ReflectionException, MBeanException + { + ClassLoader prevLoader = Thread.currentThread().getContextClassLoader(); try { - Object o = _managed; - if (getter.getDeclaringClass().isInstance(this)) - o = this; // mbean method - - // get the attribute - Object r = getter.invoke(o, (java.lang.Object[])null); - - // convert to ObjectName if the type has the @ManagedObject annotation - if (r != null) - { - if (r.getClass().isArray()) - { - if (r.getClass().getComponentType().isAnnotationPresent(ManagedObject.class)) - { - ObjectName[] on = new ObjectName[Array.getLength(r)]; - for (int i = 0; i < on.length; i++) - on[i] = _mbeanContainer.findMBean(Array.get(r, i)); - r = on; - } - } - else if (r instanceof Collection) - { - @SuppressWarnings("unchecked") - Collection c = (Collection)r; - if (!c.isEmpty() && c.iterator().next().getClass().isAnnotationPresent(ManagedObject.class)) - { - // check the first thing out - ObjectName[] on = new ObjectName[c.size()]; - int i = 0; - for (Object obj : c) - { - on[i++] = _mbeanContainer.findMBean(obj); - } - r = on; - } - } - else - { - Class clazz = r.getClass(); - while (clazz != null) - { - if (clazz.isAnnotationPresent(ManagedObject.class)) - { - ObjectName mbean = _mbeanContainer.findMBean(r); - - if (mbean != null) - { - return mbean; - } - else - { - return null; - } - } - clazz = clazz.getSuperclass(); - } - } - } - - return r; + return metaData().getAttribute(name, this); } - catch (IllegalAccessException e) + finally { - LOG.warn(Log.EXCEPTION, e); - throw new AttributeNotFoundException(e.toString()); - } - catch (InvocationTargetException e) - { - LOG.warn(Log.EXCEPTION, e); - throw new ReflectionException(new Exception(e.getCause())); + Thread.currentThread().setContextClassLoader(prevLoader); } } @@ -441,408 +162,77 @@ public class ObjectMBean implements DynamicMBean { results.add(new Attribute(name, getAttribute(name))); } - catch (Exception e) + catch (Throwable x) { - LOG.warn(Log.EXCEPTION, e); + if (LOG.isDebugEnabled()) + LOG.debug(x); } } return results; } @Override - public void setAttribute(Attribute attr) throws AttributeNotFoundException, ReflectionException + public void setAttribute(Attribute attribute) throws AttributeNotFoundException, ReflectionException, MBeanException { - if (attr == null) - return; - - if (LOG.isDebugEnabled()) - LOG.debug("setAttribute " + _managed + ":" + attr.getName() + "=" + attr.getValue()); - Method setter = _setters.get(attr.getName()); - if (setter == null) - throw new AttributeNotFoundException(attr.getName()); - + ClassLoader prevLoader = Thread.currentThread().getContextClassLoader(); try { - Object o = _managed; - if (setter.getDeclaringClass().isInstance(this)) - o = this; - - // get the value - Object value = attr.getValue(); - - // convert from ObjectName if need be - if (value != null && _convert.contains(attr.getName())) - { - if (value.getClass().isArray()) - { - Class t = setter.getParameterTypes()[0].getComponentType(); - Object na = Array.newInstance(t, Array.getLength(value)); - for (int i = Array.getLength(value); i-- > 0; ) - Array.set(na, i, _mbeanContainer.findBean((ObjectName)Array.get(value, i))); - value = na; - } - else - value = _mbeanContainer.findBean((ObjectName)value); - } - - // do the setting - setter.invoke(o, value); - } - catch (IllegalAccessException e) - { - LOG.warn(Log.EXCEPTION, e); - throw new AttributeNotFoundException(e.toString()); - } - catch (InvocationTargetException e) - { - LOG.warn(Log.EXCEPTION, e); - throw new ReflectionException(new Exception(e.getCause())); - } - } - - @Override - public AttributeList setAttributes(AttributeList attrs) - { - if (LOG.isDebugEnabled()) - LOG.debug("setAttributes"); - - AttributeList results = new AttributeList(attrs.size()); - for (Object element : attrs) - { - try - { - Attribute attr = (Attribute)element; - setAttribute(attr); - results.add(new Attribute(attr.getName(), getAttribute(attr.getName()))); - } - catch (Exception e) - { - LOG.warn(Log.EXCEPTION, e); - } - } - return results; - } - - @Override - public Object invoke(String name, Object[] params, String[] signature) throws MBeanException, ReflectionException - { - if (LOG.isDebugEnabled()) - LOG.debug("ObjectMBean:invoke " + name); - - StringBuilder builder = new StringBuilder(name); - builder.append("("); - if (signature != null) - for (int i = 0; i < signature.length; i++) - builder.append(i > 0 ? "," : "").append(signature[i]); - builder.append(")"); - String methodKey = builder.toString(); - - ClassLoader old_loader = Thread.currentThread().getContextClassLoader(); - try - { - Thread.currentThread().setContextClassLoader(_loader); - Method method = _methods.get(methodKey); - if (method == null) - throw new NoSuchMethodException(methodKey); - - Object o = _managed; - - if (method.getDeclaringClass().isInstance(this)) - o = this; - - return method.invoke(o, params); - } - catch (NoSuchMethodException e) - { - LOG.warn(Log.EXCEPTION, e); - throw new ReflectionException(e); - } - catch (IllegalAccessException e) - { - LOG.warn(Log.EXCEPTION, e); - throw new MBeanException(e); - } - catch (InvocationTargetException e) - { - LOG.warn(Log.EXCEPTION, e); - throw new ReflectionException(new Exception(e.getCause())); + metaData().setAttribute(attribute, this); } finally { - Thread.currentThread().setContextClassLoader(old_loader); + Thread.currentThread().setContextClassLoader(prevLoader); } } - private static List> findInfluences(List> influences, Class aClass) + @Override + public AttributeList setAttributes(AttributeList attributes) { - if (aClass != null) + AttributeList results = new AttributeList(attributes.size()); + for (Attribute attribute : attributes.asList()) { - if (!influences.contains(aClass)) + try { - // This class is a new influence - influences.add(aClass); + setAttribute(attribute); + results.add(new Attribute(attribute.getName(), getAttribute(attribute.getName()))); + } + catch (Throwable x) + { + if (LOG.isDebugEnabled()) + LOG.debug(x); } - - // So are the super classes - influences = findInfluences(influences, aClass.getSuperclass()); - - // So are the interfaces - Class[] ifs = aClass.getInterfaces(); - for (int i = 0; ifs != null && i < ifs.length; i++) - influences = findInfluences(influences, ifs[i]); } - return influences; + return results; } - /** - *

        Defines an attribute for the managed object using the annotation attributes.

        - * - * @param method the method on the managed objec - * @param attributeAnnotation the annotation with the attribute metadata - * @return an MBeanAttributeInfo with the attribute metadata - */ - private MBeanAttributeInfo defineAttribute(Method method, ManagedAttribute attributeAnnotation) + @Override + public Object invoke(String name, Object[] params, String[] signature) throws ReflectionException, MBeanException { - // determine the name of the managed attribute - String name = attributeAnnotation.name(); - - if ("".equals(name)) - name = toVariableName(method.getName()); - - if (_attributes.contains(name)) - return null; // we have an attribute named this already - - String description = attributeAnnotation.value(); - boolean readonly = attributeAnnotation.readonly(); - boolean onMBean = attributeAnnotation.proxied(); - - // determine if we should convert - Class return_type = method.getReturnType(); - - // get the component type - Class component_type = return_type; - while (component_type.isArray()) - component_type = component_type.getComponentType(); - - // Test to see if the returnType or any of its super classes are managed objects - boolean convert = isAnnotationPresent(component_type, ManagedObject.class); - - String uName = name.substring(0, 1).toUpperCase(Locale.ENGLISH) + name.substring(1); - Class oClass = onMBean ? this.getClass() : _managed.getClass(); - - if (LOG.isDebugEnabled()) - LOG.debug("defineAttribute {} {}:{}:{}:{}", name, onMBean, readonly, oClass, description); - - Method setter = null; - - // dig out a setter if one exists - if (!readonly) - { - String declaredSetter = attributeAnnotation.setter(); - - if (LOG.isDebugEnabled()) - LOG.debug("DeclaredSetter: {}", declaredSetter); - - for (Method method1 : oClass.getMethods()) - { - if (!Modifier.isPublic(method1.getModifiers())) - continue; - - if (!"".equals(declaredSetter)) - { - // look for a declared setter - if (method1.getName().equals(declaredSetter) && method1.getParameterCount() == 1) - { - if (setter != null) - { - LOG.warn("Multiple setters for mbean attr {} in {}", name, oClass); - continue; - } - setter = method1; - if (!component_type.equals(method1.getParameterTypes()[0])) - { - LOG.warn("Type conflict for mbean attr {} in {}", name, oClass); - continue; - } - if (LOG.isDebugEnabled()) - LOG.debug("Declared Setter: " + declaredSetter); - } - } - - // look for a setter - if (method1.getName().equals("set" + uName) && method1.getParameterCount() == 1) - { - if (setter != null) - { - LOG.warn("Multiple setters for mbean attr {} in {}", name, oClass); - continue; - } - setter = method1; - if (!return_type.equals(method1.getParameterTypes()[0])) - LOG.warn("Type conflict for mbean attr {} in {}", name, oClass); - } - } - } - - if (convert) - { - if (component_type.isPrimitive() && !component_type.isArray()) - { - LOG.warn("Cannot convert mbean primitive {}", name); - return null; - } - if (LOG.isDebugEnabled()) - LOG.debug("passed convert checks {} for type {}", name, component_type); - } - + ClassLoader prevLoader = Thread.currentThread().getContextClassLoader(); try { - // Remember the methods - _getters.put(name, method); - _setters.put(name, setter); - - MBeanAttributeInfo info; - if (convert) - { - _convert.add(name); - info = new MBeanAttributeInfo(name, - component_type.isArray() ? OBJECT_NAME_ARRAY_CLASS : OBJECT_NAME_CLASS, - description, - true, - setter != null, - method.getName().startsWith("is")); - } - else - { - info = new MBeanAttributeInfo(name, description, method, setter); - } - - _attributes.add(name); - - return info; + return metaData().invoke(name, signature, params, this); } - catch (Exception e) + finally { - LOG.warn(e); - throw new IllegalArgumentException(e.toString()); + Thread.currentThread().setContextClassLoader(prevLoader); } } - /** - *

        Defines an operation for the managed object using the annotation attributes.

        - * - * @param method the method on the managed object - * @param methodAnnotation the annotation with the operation metadata - * @return an MBeanOperationInfo with the operation metadata - */ - private MBeanOperationInfo defineOperation(Method method, ManagedOperation methodAnnotation) + ObjectName findObjectName(Object bean) { - String description = methodAnnotation.value(); - boolean onMBean = methodAnnotation.proxied(); - - // determine if we should convert - Class returnType = method.getReturnType(); - - if (returnType.isArray()) - { - if (LOG.isDebugEnabled()) - LOG.debug("returnType is array, get component type"); - returnType = returnType.getComponentType(); - } - - boolean convert = false; - if (returnType.isAnnotationPresent(ManagedObject.class)) - convert = true; - - String impactName = methodAnnotation.impact(); - - if (LOG.isDebugEnabled()) - LOG.debug("defineOperation {} {}:{}:{}", method.getName(), onMBean, impactName, description); - - try - { - // Resolve the impact - int impact = MBeanOperationInfo.UNKNOWN; - if ("UNKNOWN".equals(impactName)) - impact = MBeanOperationInfo.UNKNOWN; - else if ("ACTION".equals(impactName)) - impact = MBeanOperationInfo.ACTION; - else if ("INFO".equals(impactName)) - impact = MBeanOperationInfo.INFO; - else if ("ACTION_INFO".equals(impactName)) - impact = MBeanOperationInfo.ACTION_INFO; - else - LOG.warn("Unknown impact '" + impactName + "' for " + method); - - Annotation[][] allParameterAnnotations = method.getParameterAnnotations(); - Class[] methodTypes = method.getParameterTypes(); - MBeanParameterInfo[] pInfo = new MBeanParameterInfo[allParameterAnnotations.length]; - - for (int i = 0; i < allParameterAnnotations.length; ++i) - { - Annotation[] parameterAnnotations = allParameterAnnotations[i]; - for (Annotation anno : parameterAnnotations) - { - if (anno instanceof Name) - { - Name nameAnnotation = (Name)anno; - pInfo[i] = new MBeanParameterInfo(nameAnnotation.value(), methodTypes[i].getName(), nameAnnotation.description()); - } - } - } - - StringBuilder builder = new StringBuilder(method.getName()); - builder.append("("); - for (int i = 0; i < methodTypes.length; ++i) - { - builder.append(methodTypes[i].getName()); - if (i != methodTypes.length - 1) - builder.append(","); - } - builder.append(")"); - String signature = builder.toString(); - - Class returnClass = method.getReturnType(); - - if (LOG.isDebugEnabled()) - LOG.debug("Method Cache: " + signature); - - if (_methods.containsKey(signature)) - return null; // we have an operation for this already - - _methods.put(signature, method); - if (convert) - _convert.add(signature); - - return new MBeanOperationInfo(method.getName(), description, pInfo, returnClass.isPrimitive() ? TypeUtil.toName(returnClass) : (returnClass.getName()), impact); - } - catch (Exception e) - { - LOG.warn("Operation '" + method + "'", e); - throw new IllegalArgumentException(e.toString()); - } + return _mbeanContainer.findMBean(bean); } - protected String toVariableName(String methodName) + Object findBean(ObjectName objectName) { - String variableName = methodName; - if (methodName.startsWith("get") || methodName.startsWith("set")) - variableName = variableName.substring(3); - else if (methodName.startsWith("is")) - variableName = variableName.substring(2); - return variableName.substring(0, 1).toLowerCase(Locale.ENGLISH) + variableName.substring(1); + return _mbeanContainer.findBean(objectName); } - protected boolean isAnnotationPresent(Class clazz, Class annotation) + MetaData metaData() { - Class test = clazz; - while (test != null) - { - if (test.isAnnotationPresent(annotation)) - return true; - else - test = test.getSuperclass(); - } - return false; + if (_metaData == null) + _metaData = MBeanContainer.findMetaData(_mbeanContainer, _managed.getClass()); + return _metaData; } } diff --git a/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/package-info.java b/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/package-info.java index e973638b2e3..4a14bafe9b5 100644 --- a/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/package-info.java +++ b/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-jmx/src/main/java/org/eclipse/jetty/util/log/jmx/LogMBean.java b/jetty-jmx/src/main/java/org/eclipse/jetty/util/log/jmx/LogMBean.java index 301c8944d31..d3f447bad6c 100644 --- a/jetty-jmx/src/main/java/org/eclipse/jetty/util/log/jmx/LogMBean.java +++ b/jetty-jmx/src/main/java/org/eclipse/jetty/util/log/jmx/LogMBean.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -28,8 +28,8 @@ import org.eclipse.jetty.util.annotation.ManagedOperation; import org.eclipse.jetty.util.annotation.Name; import org.eclipse.jetty.util.log.Log; -/* ------------------------------------------------------------ */ /** + * */ @ManagedObject("Jetty Logging") public class LogMBean extends ObjectMBean @@ -39,21 +39,21 @@ public class LogMBean extends ObjectMBean super(managedObject); } - @ManagedAttribute(value="list of instantiated loggers") + @ManagedAttribute(value = "list of instantiated loggers") public List getLoggers() { List keySet = new ArrayList(Log.getLoggers().keySet()); return keySet; } - @ManagedOperation(value="true if debug enabled for the given logger") + @ManagedOperation(value = "true if debug enabled for the given logger") public boolean isDebugEnabled(@Name("logger") String logger) { return Log.getLogger(logger).isDebugEnabled(); } - - @ManagedOperation(value="Set debug enabled for given logger") - public void setDebugEnabled(@Name("logger")String logger, @Name("enabled") Boolean enabled) + + @ManagedOperation(value = "Set debug enabled for given logger") + public void setDebugEnabled(@Name("logger") String logger, @Name("enabled") Boolean enabled) { Log.getLogger(logger).setDebugEnabled(enabled); } diff --git a/jetty-jmx/src/main/java/org/eclipse/jetty/util/log/jmx/package-info.java b/jetty-jmx/src/main/java/org/eclipse/jetty/util/log/jmx/package-info.java index c7c7b1bca37..119069fab0a 100644 --- a/jetty-jmx/src/main/java/org/eclipse/jetty/util/log/jmx/package-info.java +++ b/jetty-jmx/src/main/java/org/eclipse/jetty/util/log/jmx/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-jmx/src/test/java/com/acme/Base.java b/jetty-jmx/src/test/java/com/acme/Base.java index dd079580c73..5d6820e9169 100644 --- a/jetty-jmx/src/test/java/com/acme/Base.java +++ b/jetty-jmx/src/test/java/com/acme/Base.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -26,7 +26,6 @@ public class Base extends AbstractLifeCycle int value; String[] messages; - /* ------------------------------------------------------------ */ /** * @return Returns the messages. */ @@ -35,17 +34,14 @@ public class Base extends AbstractLifeCycle return messages; } - /* ------------------------------------------------------------ */ /** - * @param messages - * The messages to set. + * @param messages The messages to set. */ public void setMessages(String[] messages) { this.messages = messages; } - /* ------------------------------------------------------------ */ /** * @return Returns the name. */ @@ -54,17 +50,14 @@ public class Base extends AbstractLifeCycle return name; } - /* ------------------------------------------------------------ */ /** - * @param name - * The name to set. + * @param name The name to set. */ public void setName(String name) { this.name = name; } - /* ------------------------------------------------------------ */ /** * @return Returns the value. */ @@ -73,26 +66,21 @@ public class Base extends AbstractLifeCycle return value; } - /* ------------------------------------------------------------ */ /** - * @param value - * The value to set. + * @param value The value to set. */ public void setValue(int value) { this.value = value; } - /* ------------------------------------------------------------ */ public void doSomething(int arg) { System.err.println("doSomething " + arg); } - /* ------------------------------------------------------------ */ public String findSomething(int arg) { return ("found " + arg); } - } diff --git a/jetty-jmx/src/test/java/com/acme/Derived.java b/jetty-jmx/src/test/java/com/acme/Derived.java index eba0baac1f6..7016baf4e37 100644 --- a/jetty-jmx/src/test/java/com/acme/Derived.java +++ b/jetty-jmx/src/test/java/com/acme/Derived.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -78,5 +78,4 @@ public class Derived extends Base implements Signature { return superManagedInstance; } - } diff --git a/jetty-jmx/src/test/java/com/acme/DerivedExtended.java b/jetty-jmx/src/test/java/com/acme/DerivedExtended.java index b25280e2154..d072d357529 100644 --- a/jetty-jmx/src/test/java/com/acme/DerivedExtended.java +++ b/jetty-jmx/src/test/java/com/acme/DerivedExtended.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -25,7 +25,6 @@ import org.eclipse.jetty.util.annotation.ManagedOperation; @ManagedObject(value = "Test the mbean extended stuff") public class DerivedExtended extends Derived { - private String doodle4 = "doodle4"; @ManagedAttribute(value = "The doodle4 name of something", name = "doodle4", setter = "setDoodle4") diff --git a/jetty-jmx/src/test/java/com/acme/DerivedManaged.java b/jetty-jmx/src/test/java/com/acme/DerivedManaged.java index 0ce4c30920b..b539528b0cd 100644 --- a/jetty-jmx/src/test/java/com/acme/DerivedManaged.java +++ b/jetty-jmx/src/test/java/com/acme/DerivedManaged.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-jmx/src/test/java/com/acme/Managed.java b/jetty-jmx/src/test/java/com/acme/Managed.java index bd7831fa8d4..0da7a21b31f 100644 --- a/jetty-jmx/src/test/java/com/acme/Managed.java +++ b/jetty-jmx/src/test/java/com/acme/Managed.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -41,5 +41,4 @@ public class Managed { return "bad"; } - } diff --git a/jetty-jmx/src/test/java/com/acme/Signature.java b/jetty-jmx/src/test/java/com/acme/Signature.java index 12031386d73..759df6a1811 100644 --- a/jetty-jmx/src/test/java/com/acme/Signature.java +++ b/jetty-jmx/src/test/java/com/acme/Signature.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-jmx/src/test/java/com/acme/SuperManaged.java b/jetty-jmx/src/test/java/com/acme/SuperManaged.java index a9646945f1f..b417abf02ac 100644 --- a/jetty-jmx/src/test/java/com/acme/SuperManaged.java +++ b/jetty-jmx/src/test/java/com/acme/SuperManaged.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -25,5 +25,4 @@ public class SuperManaged extends Managed { return "super"; } - } diff --git a/jetty-jmx/src/test/java/com/acme/jmx/DerivedMBean.java b/jetty-jmx/src/test/java/com/acme/jmx/DerivedMBean.java index 6b7b14449af..5b91b4c37d1 100644 --- a/jetty-jmx/src/test/java/com/acme/jmx/DerivedMBean.java +++ b/jetty-jmx/src/test/java/com/acme/jmx/DerivedMBean.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,6 +18,7 @@ package com.acme.jmx; +import com.acme.Derived; import org.eclipse.jetty.jmx.ObjectMBean; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; @@ -25,8 +26,6 @@ import org.eclipse.jetty.util.annotation.ManagedOperation; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import com.acme.Derived; - @ManagedObject("Derived MBean Wrapper") public class DerivedMBean extends ObjectMBean { @@ -48,5 +47,4 @@ public class DerivedMBean extends ObjectMBean { return "goop"; } - } diff --git a/jetty-jmx/src/test/java/com/acme/jmx/ManagedMBean.java b/jetty-jmx/src/test/java/com/acme/jmx/ManagedMBean.java index ae4fce0de43..3325f6c1094 100644 --- a/jetty-jmx/src/test/java/com/acme/jmx/ManagedMBean.java +++ b/jetty-jmx/src/test/java/com/acme/jmx/ManagedMBean.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,13 +18,12 @@ package com.acme.jmx; +import com.acme.Managed; import org.eclipse.jetty.jmx.ObjectMBean; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.annotation.ManagedOperation; -import com.acme.Managed; - @ManagedObject("Managed MBean Wrapper") public class ManagedMBean extends ObjectMBean { diff --git a/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/ConnectorServerTest.java b/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/ConnectorServerTest.java index c007488b3de..701027a12bd 100644 --- a/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/ConnectorServerTest.java +++ b/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/ConnectorServerTest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,17 +18,12 @@ package org.eclipse.jetty.jmx; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.net.ConnectException; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.util.HashMap; import java.util.Map; - import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXServiceURL; @@ -40,6 +35,10 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + /** * Running the tests of this class in the same JVM results often in *
        @@ -83,7 +82,8 @@ public class ConnectorServerTest
         
                 // Verify that I can connect to the RMI registry using a non-loopback address.
                 new Socket(InetAddress.getLocalHost(), 1099).close();
        -        assertThrows(ConnectException.class, ()->{
        +        assertThrows(ConnectException.class, () ->
        +        {
                     // Verify that I cannot connect to the RMI registry using the loopback address.
                     new Socket(InetAddress.getLoopbackAddress(), 1099).close();
                 });
        @@ -100,7 +100,8 @@ public class ConnectorServerTest
         
                 // Verify that I can connect to the RMI registry using a non-loopback address.
                 new Socket(InetAddress.getLocalHost(), registryPort).close();
        -        assertThrows(ConnectException.class, ()->{
        +        assertThrows(ConnectException.class, () ->
        +        {
                     // Verify that I cannot connect to the RMI registry using the loopback address.
                     new Socket(InetAddress.getLoopbackAddress(), registryPort).close();
                 });
        @@ -130,7 +131,8 @@ public class ConnectorServerTest
                 InetAddress localHost = InetAddress.getLocalHost();
                 if (!localHost.isLoopbackAddress())
                 {
        -            assertThrows(ConnectException.class, ()->{
        +            assertThrows(ConnectException.class, () ->
        +            {
                         // Verify that I cannot connect to the RMIRegistry using a non-loopback address.
                         new Socket(localHost, 1099);
                     });
        @@ -148,7 +150,8 @@ public class ConnectorServerTest
         
                 // Verify that I can connect to the RMI server using a non-loopback address.
                 new Socket(InetAddress.getLocalHost(), connectorServer.getAddress().getPort()).close();
        -        assertThrows(ConnectException.class, ()->{
        +        assertThrows(ConnectException.class, () ->
        +        {
                     // Verify that I cannot connect to the RMI server using the loopback address.
                     new Socket(InetAddress.getLoopbackAddress(), connectorServer.getAddress().getPort()).close();
                 });
        @@ -176,7 +179,8 @@ public class ConnectorServerTest
                 InetAddress localHost = InetAddress.getLocalHost();
                 if (!localHost.isLoopbackAddress())
                 {
        -            assertThrows(ConnectException.class, ()->{
        +            assertThrows(ConnectException.class, () ->
        +            {
                         // Verify that I cannot connect to the RMIRegistry using a non-loopback address.
                         new Socket(localHost, address.getPort());
                     });
        @@ -227,7 +231,7 @@ public class ConnectorServerTest
             @Test
             public void testJMXOverTLS() throws Exception
             {
        -        SslContextFactory sslContextFactory = new SslContextFactory();
        +        SslContextFactory sslContextFactory = new SslContextFactory.Server();
                 String keyStorePath = MavenTestingUtils.getTestResourcePath("keystore.jks").toString();
                 String keyStorePassword = "storepwd";
                 sslContextFactory.setKeyStorePath(keyStorePath);
        diff --git a/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/MBeanContainerLifeCycleTest.java b/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/MBeanContainerLifeCycleTest.java
        index 889abadd909..94dd6fb6d38 100644
        --- a/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/MBeanContainerLifeCycleTest.java
        +++ b/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/MBeanContainerLifeCycleTest.java
        @@ -1,6 +1,6 @@
         //
         //  ========================================================================
        -//  Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
        +//  Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
         //  ------------------------------------------------------------------------
         //  All rights reserved. This program and the accompanying materials
         //  are made available under the terms of the Eclipse Public License v1.0
        @@ -18,21 +18,19 @@
         
         package org.eclipse.jetty.jmx;
         
        -import static org.junit.jupiter.api.Assertions.assertEquals;
        -
         import java.lang.management.ManagementFactory;
         import java.util.Set;
        -
         import javax.management.MBeanServer;
         import javax.management.ObjectName;
         
         import org.eclipse.jetty.util.component.ContainerLifeCycle;
         import org.eclipse.jetty.util.thread.QueuedThreadPool;
        -
         import org.junit.jupiter.api.AfterEach;
         import org.junit.jupiter.api.BeforeEach;
         import org.junit.jupiter.api.Test;
         
        +import static org.junit.jupiter.api.Assertions.assertEquals;
        +
         public class MBeanContainerLifeCycleTest
         {
             private ContainerLifeCycle container;
        diff --git a/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/MBeanContainerTest.java b/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/MBeanContainerTest.java
        index ded64808426..2b87fa53cfb 100644
        --- a/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/MBeanContainerTest.java
        +++ b/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/MBeanContainerTest.java
        @@ -1,6 +1,6 @@
         //
         //  ========================================================================
        -//  Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
        +//  Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
         //  ------------------------------------------------------------------------
         //  All rights reserved. This program and the accompanying materials
         //  are made available under the terms of the Eclipse Public License v1.0
        @@ -18,24 +18,22 @@
         
         package org.eclipse.jetty.jmx;
         
        +import java.lang.management.ManagementFactory;
        +import javax.management.MBeanServer;
        +import javax.management.ObjectName;
        +
        +import com.acme.Managed;
        +import org.eclipse.jetty.util.component.Container;
        +import org.eclipse.jetty.util.component.ContainerLifeCycle;
        +import org.junit.jupiter.api.BeforeEach;
        +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.assertNotNull;
         import static org.junit.jupiter.api.Assertions.assertNull;
         import static org.junit.jupiter.api.Assertions.assertTrue;
         
        -import com.acme.Managed;
        -
        -import java.lang.management.ManagementFactory;
        -
        -import javax.management.MBeanServer;
        -import javax.management.ObjectName;
        -
        -import org.eclipse.jetty.util.component.Container;
        -import org.eclipse.jetty.util.component.ContainerLifeCycle;
        -import org.junit.jupiter.api.BeforeEach;
        -import org.junit.jupiter.api.Test;
        -
         public class MBeanContainerTest
         {
             private MBeanContainer mbeanContainer;
        @@ -54,27 +52,21 @@ public class MBeanContainerTest
             @Test
             public void testMakeName()
             {
        -        // given
                 beanName = "mngd:bean";
         
        -        // when
                 beanName = mbeanContainer.makeName(beanName);
         
        -        // then
                 assertEquals("mngd_bean", beanName, "Bean name should be mngd_bean");
             }
         
             @Test
             public void testFindBean()
             {
        -        // given
                 managed = getManaged();
         
        -        // when
                 objectName = mbeanContainer.findMBean(managed);
                 assertNotNull(objectName);
         
        -        // then
                 assertEquals(managed, mbeanContainer.findBean(objectName), "Bean must be added");
                 assertNull(mbeanContainer.findBean(null), "It must return null as there is no bean with the name null");
             }
        @@ -104,40 +96,31 @@ public class MBeanContainerTest
             @Test
             public void testDomain()
             {
        -        // given
                 String domain = "Test";
         
        -        // when
                 mbeanContainer.setDomain(domain);
         
        -        // then
                 assertEquals(domain, mbeanContainer.getDomain(), "Domain name must be Test");
             }
         
             @Test
        -    public void testBeanAdded() throws Exception
        +    public void testBeanAdded()
             {
        -        // given
                 setBeanAdded();
         
        -        // when
                 objectName = mbeanContainer.findMBean(managed);
         
        -        // then
                 assertTrue(mbeanServer.isRegistered(objectName), "Bean must have been registered");
             }
         
             @Test
        -    public void testBeanAddedNullCheck() throws Exception
        +    public void testBeanAddedNullCheck()
             {
        -        // given
                 setBeanAdded();
                 Integer mbeanCount = mbeanServer.getMBeanCount();
         
        -        // when
                 mbeanContainer.beanAdded(null, null);
         
        -        // then
                 assertEquals(mbeanCount, mbeanServer.getMBeanCount(), "MBean count must not change after beanAdded(null, null) call");
             }
         
        @@ -150,15 +133,12 @@ public class MBeanContainerTest
             }
         
             @Test
        -    public void testBeanRemoved() throws Exception
        +    public void testBeanRemoved()
             {
        -        // given
                 setUpBeanRemoved();
         
        -        // when
                 mbeanContainer.beanRemoved(null, managed);
         
        -        // then
                 assertNull(mbeanContainer.findMBean(managed), "Bean shouldn't be registered with container as we removed the bean");
             }
         
        @@ -200,30 +180,24 @@ public class MBeanContainerTest
             }
         
             @Test
        -    public void testDestroy() throws Exception
        +    public void testDestroy()
             {
        -        // given
                 setUpDestroy();
         
        -        // when
                 objectName = mbeanContainer.findMBean(managed);
                 mbeanContainer.destroy();
         
        -        // then
                 assertFalse(mbeanContainer.getMBeanServer().isRegistered(objectName), "Unregistered bean - managed");
             }
         
             @Test
             public void testDestroyInstanceNotFoundException() throws Exception
             {
        -        // given
                 setUpDestroy();
         
        -        // when
                 objectName = mbeanContainer.findMBean(managed);
                 mbeanContainer.getMBeanServer().unregisterMBean(objectName);
         
        -        // then
                 assertFalse(mbeanContainer.getMBeanServer().isRegistered(objectName), "Unregistered bean - managed");
                 // this flow covers InstanceNotFoundException. Actual code just eating
                 // the exception. i.e Actual code just printing the stacktrace, whenever
        diff --git a/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/ObjectMBeanTest.java b/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/ObjectMBeanTest.java
        index 0c0b9f95223..51f6cce9c7a 100644
        --- a/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/ObjectMBeanTest.java
        +++ b/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/ObjectMBeanTest.java
        @@ -1,6 +1,6 @@
         //
         //  ========================================================================
        -//  Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
        +//  Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
         //  ------------------------------------------------------------------------
         //  All rights reserved. This program and the accompanying materials
         //  are made available under the terms of the Eclipse Public License v1.0
        @@ -18,211 +18,175 @@
         
         package org.eclipse.jetty.jmx;
         
        -import static org.junit.jupiter.api.Assertions.assertEquals;
        -import static org.junit.jupiter.api.Assertions.assertNotNull;
        -import static org.junit.jupiter.api.Assertions.assertTrue;
        -
        -import com.acme.Derived;
        -
         import java.lang.management.ManagementFactory;
        -
         import javax.management.Attribute;
         import javax.management.MBeanInfo;
         import javax.management.MBeanOperationInfo;
         import javax.management.MBeanParameterInfo;
        +import javax.management.ObjectName;
         
        -import org.eclipse.jetty.util.log.Log;
        -import org.eclipse.jetty.util.log.Logger;
        -import org.eclipse.jetty.util.thread.QueuedThreadPool;
        +import com.acme.Derived;
        +import com.acme.Managed;
         import org.junit.jupiter.api.AfterEach;
         import org.junit.jupiter.api.BeforeEach;
        -import org.junit.jupiter.api.Disabled;
         import org.junit.jupiter.api.Test;
         
        +import static org.junit.jupiter.api.Assertions.assertEquals;
        +import static org.junit.jupiter.api.Assertions.assertNotNull;
        +import static org.junit.jupiter.api.Assertions.assertNotSame;
        +import static org.junit.jupiter.api.Assertions.assertNull;
        +import static org.junit.jupiter.api.Assertions.assertSame;
        +import static org.junit.jupiter.api.Assertions.assertTrue;
        +
         public class ObjectMBeanTest
         {
        -    private static final Logger LOG = Log.getLogger(ObjectMBeanTest.class);
        -
        -    private static MBeanContainer container;
        +    private MBeanContainer container;
         
             @BeforeEach
        -    public void before() throws Exception
        +    public void before()
             {
                 container = new MBeanContainer(ManagementFactory.getPlatformMBeanServer());
             }
         
             @AfterEach
        -    public void after() throws Exception
        +    public void after()
             {
                 container.destroy();
                 container = null;
             }
         
        -    /*
        -     * this test uses the com.acme.Derived test classes
        -     */
        +    @Test
        +    public void testMBeanForNull()
        +    {
        +        Object mBean = container.mbeanFor(null);
        +        assertNull(mBean);
        +    }
        +
        +    @Test
        +    public void testMBeanForString()
        +    {
        +        String obj = "foo";
        +        Object mbean = container.mbeanFor(obj);
        +        assertNotNull(mbean);
        +        container.beanAdded(null, obj);
        +        ObjectName objectName = container.findMBean(obj);
        +        assertNotNull(objectName);
        +    }
        +
        +    @Test
        +    public void testMBeanForStringArray()
        +    {
        +        String[] obj = {"a", "b"};
        +        Object mbean = container.mbeanFor(obj);
        +        assertNotNull(mbean);
        +        container.beanAdded(null, obj);
        +        ObjectName objectName = container.findMBean(obj);
        +        assertNotNull(objectName);
        +    }
        +
        +    @Test
        +    public void testMBeanForIntArray()
        +    {
        +        int[] obj = {0, 1, 2};
        +        Object mbean = container.mbeanFor(obj);
        +        assertNotNull(mbean);
        +        container.beanAdded(null, obj);
        +        ObjectName objectName = container.findMBean(obj);
        +        assertNotNull(objectName);
        +    }
        +
        +    @Test
        +    public void testMetaDataCaching()
        +    {
        +        Derived derived = new Derived();
        +        ObjectMBean derivedMBean = (ObjectMBean)container.mbeanFor(derived);
        +        ObjectMBean derivedMBean2 = (ObjectMBean)container.mbeanFor(derived);
        +        assertNotSame(derivedMBean, derivedMBean2);
        +        assertSame(derivedMBean.metaData(), derivedMBean2.metaData());
        +    }
        +
             @Test
             public void testDerivedAttributes() throws Exception
             {
                 Derived derived = new Derived();
        -        ObjectMBean mbean = (ObjectMBean)ObjectMBean.mbeanFor(derived);
        +        Managed managed = derived.getManagedInstance();
        +        ObjectMBean derivedMBean = (ObjectMBean)container.mbeanFor(derived);
        +        ObjectMBean managedMBean = (ObjectMBean)container.mbeanFor(managed);
         
        -        ObjectMBean managed = (ObjectMBean)ObjectMBean.mbeanFor(derived.getManagedInstance());
        -        mbean.setMBeanContainer(container);
        -        managed.setMBeanContainer(container);
        +        container.beanAdded(null, derived);
        +        container.beanAdded(null, managed);
         
        -        container.beanAdded(null,derived);
        -        container.beanAdded(null,derived.getManagedInstance());
        +        MBeanInfo derivedInfo = derivedMBean.getMBeanInfo();
        +        assertNotNull(derivedInfo);
        +        MBeanInfo managedInfo = managedMBean.getMBeanInfo();
        +        assertNotNull(managedInfo);
         
        -        MBeanInfo toss = managed.getMBeanInfo();
        +        assertEquals("com.acme.Derived", derivedInfo.getClassName(), "name does not match");
        +        assertEquals("Test the mbean stuff", derivedInfo.getDescription(), "description does not match");
        +        assertEquals(6, derivedInfo.getAttributes().length, "attribute count does not match");
        +        assertEquals("Full Name", derivedMBean.getAttribute("fname"), "attribute values does not match");
         
        -        assertNotNull(mbean.getMBeanInfo());
        -
        -        MBeanInfo info = mbean.getMBeanInfo();
        -
        -        assertEquals("com.acme.Derived", info.getClassName(), "name does not match");
        -        assertEquals("Test the mbean stuff", info.getDescription(), "description does not match");
        -
        -        // for ( MBeanAttributeInfo i : info.getAttributes())
        -        // {
        -        // LOG.debug(i.toString());
        -        // }
        -
        -        /*
        -         * 2 attributes from lifecycle and 2 from Derived and 1 from MBean
        -         */
        -        assertEquals(6, info.getAttributes().length, "attribute count does not match");
        -
        -        assertEquals("Full Name", mbean.getAttribute("fname"), "attribute values does not match");
        -
        -        mbean.setAttribute(new Attribute("fname","Fuller Name"));
        -
        -        assertEquals("Fuller Name", mbean.getAttribute("fname"), "set attribute value does not match");
        -
        -        assertEquals("goop", mbean.getAttribute("goop"), "proxy attribute values do not match");
        -
        -        // Thread.sleep(100000);
        +        derivedMBean.setAttribute(new Attribute("fname", "Fuller Name"));
        +        assertEquals("Fuller Name", derivedMBean.getAttribute("fname"), "set attribute value does not match");
        +        assertEquals("goop", derivedMBean.getAttribute("goop"), "proxy attribute values do not match");
             }
         
             @Test
             public void testDerivedOperations() throws Exception
             {
                 Derived derived = new Derived();
        -        ObjectMBean mbean = (ObjectMBean)ObjectMBean.mbeanFor(derived);
        +        ObjectMBean mbean = (ObjectMBean)container.mbeanFor(derived);
         
        -        mbean.setMBeanContainer(container);
        -
        -        container.beanAdded(null,derived);
        +        container.beanAdded(null, derived);
         
                 MBeanInfo info = mbean.getMBeanInfo();
        -
                 assertEquals(5, info.getOperations().length, "operation count does not match");
         
        -        MBeanOperationInfo[] opinfos = info.getOperations();
        +        MBeanOperationInfo[] operationInfos = info.getOperations();
                 boolean publish = false;
                 boolean doodle = false;
                 boolean good = false;
        -        for (int i = 0; i < opinfos.length; ++i)
        +        for (MBeanOperationInfo operationInfo : operationInfos)
                 {
        -            MBeanOperationInfo opinfo = opinfos[i];
        -
        -            if ("publish".equals(opinfo.getName()))
        +            if ("publish".equals(operationInfo.getName()))
                     {
                         publish = true;
        -                assertEquals("publish something", opinfo.getDescription(), "description doesn't match");
        +                assertEquals("publish something", operationInfo.getDescription(), "description doesn't match");
                     }
         
        -            if ("doodle".equals(opinfo.getName()))
        +            if ("doodle".equals(operationInfo.getName()))
                     {
                         doodle = true;
        -                assertEquals("Doodle something", opinfo.getDescription(), "description doesn't match");
        -
        -                MBeanParameterInfo[] pinfos = opinfo.getSignature();
        -
        -                assertEquals("A description of the argument", pinfos[0].getDescription(), "parameter description doesn't match");
        -                assertEquals("doodle", pinfos[0].getName(), "parameter name doesn't match");
        +                assertEquals("Doodle something", operationInfo.getDescription(), "description doesn't match");
        +                MBeanParameterInfo[] parameterInfos = operationInfo.getSignature();
        +                assertEquals("A description of the argument", parameterInfos[0].getDescription(), "parameter description doesn't match");
        +                assertEquals("doodle", parameterInfos[0].getName(), "parameter name doesn't match");
                     }
         
        -            // This is a proxied operation on the JMX wrapper
        -            if ("good".equals(opinfo.getName()))
        +            // This is a proxied operation on the MBean wrapper.
        +            if ("good".equals(operationInfo.getName()))
                     {
                         good = true;
        -
        -                assertEquals("test of proxy operations", opinfo.getDescription(), "description does not match");
        -                assertEquals("not bad",mbean.invoke("good",new Object[] {}, new String[] {}), "execution contexts wrong");
        +                assertEquals("test of proxy operations", operationInfo.getDescription(), "description does not match");
        +                assertEquals("not bad", mbean.invoke("good", new Object[]{}, new String[]{}), "execution contexts wrong");
                     }
                 }
         
                 assertTrue(publish, "publish operation was not not found");
                 assertTrue(doodle, "doodle operation was not not found");
                 assertTrue(good, "good operation was not not found");
        -
             }
         
             @Test
        -    public void testDerivedObjectAttributes() throws Exception
        +    public void testMethodNameMining()
             {
        -        Derived derived = new Derived();
        -        ObjectMBean mbean = (ObjectMBean)ObjectMBean.mbeanFor(derived);
        -
        -        ObjectMBean managed = (ObjectMBean)ObjectMBean.mbeanFor(derived.getManagedInstance());
        -        mbean.setMBeanContainer(container);
        -        managed.setMBeanContainer(container);
        -
        -        assertNotNull(mbean.getMBeanInfo());
        -
        -        container.beanAdded(null,derived);
        -        container.beanAdded(null,derived.getManagedInstance());
        -        container.beanAdded(null,mbean);
        -        container.beanAdded(null,managed);
        -
        -        // Managed managedInstance = (Managed)mbean.getAttribute("managedInstance");
        -        // assertNotNull(managedInstance);
        -        // assertEquals("foo", managedInstance.getManaged(), "managed instance returning nonsense");
        -
        +        assertEquals("fullName", MetaData.toAttributeName("getFullName"));
        +        assertEquals("fullName", MetaData.toAttributeName("getfullName"));
        +        assertEquals("fullName", MetaData.toAttributeName("isFullName"));
        +        assertEquals("fullName", MetaData.toAttributeName("isfullName"));
        +        assertEquals("fullName", MetaData.toAttributeName("setFullName"));
        +        assertEquals("fullName", MetaData.toAttributeName("setfullName"));
        +        assertEquals("fullName", MetaData.toAttributeName("FullName"));
        +        assertEquals("fullName", MetaData.toAttributeName("fullName"));
             }
        -
        -    @Test
        -    @Disabled("ignore, used in testing jconsole atm")
        -    public void testThreadPool() throws Exception
        -    {
        -
        -        Derived derived = new Derived();
        -        ObjectMBean mbean = (ObjectMBean)ObjectMBean.mbeanFor(derived);
        -
        -        ObjectMBean managed = (ObjectMBean)ObjectMBean.mbeanFor(derived.getManagedInstance());
        -        mbean.setMBeanContainer(container);
        -        managed.setMBeanContainer(container);
        -
        -        QueuedThreadPool qtp = new QueuedThreadPool();
        -
        -        ObjectMBean bqtp = (ObjectMBean)ObjectMBean.mbeanFor(qtp);
        -
        -        bqtp.getMBeanInfo();
        -
        -        container.beanAdded(null,derived);
        -        container.beanAdded(null,derived.getManagedInstance());
        -        container.beanAdded(null,mbean);
        -        container.beanAdded(null,managed);
        -        container.beanAdded(null,qtp);
        -
        -        Thread.sleep(10000000);
        -
        -    }
        -
        -    @Test
        -    public void testMethodNameMining() throws Exception
        -    {
        -        ObjectMBean mbean = new ObjectMBean(new Derived());
        -
        -        assertEquals("fullName",mbean.toVariableName("getFullName"));
        -        assertEquals("fullName",mbean.toVariableName("getfullName"));
        -        assertEquals("fullName",mbean.toVariableName("isFullName"));
        -        assertEquals("fullName",mbean.toVariableName("isfullName"));
        -        assertEquals("fullName",mbean.toVariableName("setFullName"));
        -        assertEquals("fullName",mbean.toVariableName("setfullName"));
        -        assertEquals("fullName",mbean.toVariableName("FullName"));
        -        assertEquals("fullName",mbean.toVariableName("fullName"));
        -    }
        -
         }
        diff --git a/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/ObjectMBeanUtilTest.java b/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/ObjectMBeanUtilTest.java
        index 16c3c313a5d..4ab3a97af53 100644
        --- a/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/ObjectMBeanUtilTest.java
        +++ b/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/ObjectMBeanUtilTest.java
        @@ -1,6 +1,6 @@
         //
         //  ========================================================================
        -//  Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
        +//  Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
         //  ------------------------------------------------------------------------
         //  All rights reserved. This program and the accompanying materials
         //  are made available under the terms of the Eclipse Public License v1.0
        @@ -18,14 +18,9 @@
         
         package org.eclipse.jetty.jmx;
         
        -import com.acme.Derived;
        -import com.acme.DerivedExtended;
        -import com.acme.DerivedManaged;
        -
         import java.lang.management.ManagementFactory;
         import java.util.ArrayList;
         import java.util.Arrays;
        -
         import javax.management.Attribute;
         import javax.management.AttributeList;
         import javax.management.AttributeNotFoundException;
        @@ -33,68 +28,33 @@ import javax.management.MBeanException;
         import javax.management.MBeanInfo;
         import javax.management.ReflectionException;
         
        -import org.eclipse.jetty.util.log.Log;
        -import org.eclipse.jetty.util.log.Logger;
        -import org.eclipse.jetty.util.log.StdErrLog;
        -import org.junit.jupiter.api.AfterAll;
        -import org.junit.jupiter.api.BeforeAll;
        +import com.acme.Derived;
        +import com.acme.DerivedExtended;
        +import com.acme.DerivedManaged;
         import org.junit.jupiter.api.BeforeEach;
         import org.junit.jupiter.api.Test;
         
        -import static org.junit.jupiter.api.Assertions.*;
        +import static org.junit.jupiter.api.Assertions.assertEquals;
        +import static org.junit.jupiter.api.Assertions.assertNotNull;
        +import static org.junit.jupiter.api.Assertions.assertNull;
        +import static org.junit.jupiter.api.Assertions.assertThrows;
         
         public class ObjectMBeanUtilTest
         {
        -
             private ObjectMBean objectMBean;
        -
             private DerivedExtended derivedExtended;
        -
             private MBeanContainer container;
        -
             private MBeanInfo objectMBeanInfo;
        -
        -    private Object mBean;
        -
        -    private String value;
        -
             private Attribute attribute;
        -
        -    private AttributeList attributes;
        -
             private ObjectMBean mBeanDerivedManaged;
        -
        -    private Derived[] derivedes;
        -
        -    private ArrayList aliasNames;
        -
             private DerivedManaged derivedManaged;
         
        -    private static final int EMPTY = 0;
        -
        -    @BeforeAll
        -    public static void beforeClass()
        -    {
        -        Logger ombLog = Log.getLogger(ObjectMBean.class);
        -        if (ombLog instanceof StdErrLog && !ombLog.isDebugEnabled())
        -            ((StdErrLog)ombLog).setHideStacks(true);
        -    }
        -
        -    @AfterAll
        -    public static void afterClass()
        -    {
        -        Logger ombLog = Log.getLogger(ObjectMBean.class);
        -        if (ombLog instanceof StdErrLog)
        -            ((StdErrLog)ombLog).setHideStacks(false);
        -    }
        -
             @BeforeEach
             public void setUp()
             {
        -        derivedExtended = new DerivedExtended();
        -        objectMBean = new ObjectMBean(derivedExtended);
                 container = new MBeanContainer(ManagementFactory.getPlatformMBeanServer());
        -        objectMBean.setMBeanContainer(container);
        +        derivedExtended = new DerivedExtended();
        +        objectMBean = (ObjectMBean)container.mbeanFor(derivedExtended);
                 objectMBeanInfo = objectMBean.getMBeanInfo();
             }
         
        @@ -110,133 +70,88 @@ public class ObjectMBeanUtilTest
             }
         
             @Test
        -    public void testMbeanForNullCheck()
        +    public void testGetAttributeMBeanException() throws Exception
             {
        -        // when
        -        mBean = ObjectMBean.mbeanFor(null);
        +        Attribute attribute = new Attribute("doodle4", "charu");
        +        objectMBean.setAttribute(attribute);
         
        -        // then
        -        assertNull(mBean, "As we are passing null value the output should be null");
        -    }
        +        MBeanException e = assertThrows(MBeanException.class, () -> objectMBean.getAttribute("doodle4"));
         
        -    @Test
        -    public void testGetAttributeReflectionException() throws Exception
        -    {
        -        // given
        -        setUpGetAttribute("doodle4","charu");
        -
        -        // when
        -        ReflectionException e = assertThrows(ReflectionException.class, ()-> {
        -            objectMBean.getAttribute("doodle4");
        -        });
        -
        -        // then
                 assertNotNull(e, "An InvocationTargetException must have occurred by now as doodle4() internally throwing exception");
             }
         
        -    private void setUpGetAttribute(String property, String value) throws Exception
        -    {
        -        Attribute attribute = new Attribute(property,value);
        -        objectMBean.setAttribute(attribute);
        -    }
        -
             @Test
        -    public void testGetAttributeAttributeNotFoundException() throws Exception
        +    public void testGetAttributeAttributeNotFoundException()
             {
        -        // when
        -        AttributeNotFoundException e = assertThrows(AttributeNotFoundException.class, ()->{
        -            objectMBean.getAttribute("ffname");
        -        });
        +        AttributeNotFoundException e = assertThrows(AttributeNotFoundException.class, () -> objectMBean.getAttribute("ffname"));
         
        -        // then
        -        assertNotNull(e, "An AttributeNotFoundException must have occurred by now as there is no " + "attribute with the name ffname in bean");
        +        assertNotNull(e, "An AttributeNotFoundException must have occurred by now as there is no attribute with the name ffname in bean");
             }
         
             @Test
             public void testSetAttributeWithCorrectAttrName() throws Exception
             {
        -        // given
        -        setUpGetAttribute("fname","charu");
        +        Attribute attribute = new Attribute("fname", "charu");
        +        objectMBean.setAttribute(attribute);
         
        -        // when
        -        value = (String)objectMBean.getAttribute("fname");
        +        String value = (String)objectMBean.getAttribute("fname");
         
        -        // then
        -        assertEquals("charu", value, "Attribute(fname) value must be equl to charu");
        +        assertEquals("charu", value, "Attribute(fname) value must be equal to charu");
             }
         
             @Test
             public void testSetAttributeNullCheck() throws Exception
             {
        -        // given
                 objectMBean.setAttribute(null);
         
        -        // when
        -        AttributeNotFoundException e = assertThrows(AttributeNotFoundException.class, ()->{
        -            objectMBean.getAttribute(null);
        -        });
        +        AttributeNotFoundException e = assertThrows(AttributeNotFoundException.class, () -> objectMBean.getAttribute(null));
         
        -        // then
        -        assertNotNull(e,"An AttributeNotFoundException must have occurred by now as there is no attribute with the name null");
        +        assertNotNull(e, "An AttributeNotFoundException must have occurred by now as there is no attribute with the name null");
             }
         
             @Test
        -    public void testSetAttributeAttributeWithWrongAttrName() throws Exception
        +    public void testSetAttributeAttributeWithWrongAttrName()
             {
        -        // given
        -        attribute = new Attribute("fnameee","charu");
        +        attribute = new Attribute("fnameee", "charu");
         
        -        // when
        -        AttributeNotFoundException e = assertThrows(AttributeNotFoundException.class, ()->{
        -            objectMBean.setAttribute(attribute);
        -        });
        +        AttributeNotFoundException e = assertThrows(AttributeNotFoundException.class, () -> objectMBean.setAttribute(attribute));
         
        -        // then
                 assertNotNull(e, "An AttributeNotFoundException must have occurred by now as there is no attribute " + "with the name ffname in bean");
             }
         
             @Test
        -    public void testSetAttributesWithCorrectValues() throws Exception
        +    public void testSetAttributesWithCorrectValues()
             {
        -        // given
        -        attributes = getAttributes("fname","vijay");
        -        attributes = objectMBean.setAttributes(attributes);
        +        AttributeList attributes = getAttributes("fname", "vijay");
        +        objectMBean.setAttributes(attributes);
         
        -        // when
        -        attributes = objectMBean.getAttributes(new String[]
        -        { "fname" });
        +        attributes = objectMBean.getAttributes(new String[]{"fname"});
         
        -        // then
        +        assertEquals(1, attributes.size());
                 assertEquals("vijay", ((Attribute)(attributes.get(0))).getValue(), "Fname value must be equal to vijay");
             }
         
             @Test
        -    public void testSetAttributesForArrayTypeAttribue() throws Exception
        +    public void testSetAttributesForArrayTypeAttribute() throws Exception
             {
        -        // given
        -        derivedes = getArrayTypeAttribute();
        +        Derived[] deriveds = getArrayTypeAttribute();
         
        -        // when
        -        derivedManaged.setAddresses(derivedes);
        +        derivedManaged.setAddresses(deriveds);
                 mBeanDerivedManaged.getMBeanInfo();
         
        -        // then
                 assertNotNull(mBeanDerivedManaged.getAttribute("addresses"), "Address object shouldn't be null");
             }
         
             @Test
        -    public void testSetAttributesForCollectionTypeAttribue() throws Exception
        +    public void testSetAttributesForCollectionTypeAttribute() throws Exception
             {
        -        // given
        -        aliasNames = getCollectionTypeAttribute();
        +        ArrayList aliasNames = new ArrayList<>(Arrays.asList(getArrayTypeAttribute()));
         
        -        // when
                 derivedManaged.setAliasNames(aliasNames);
                 mBeanDerivedManaged.getMBeanInfo();
         
        -        // then
                 assertNotNull(mBeanDerivedManaged.getAttribute("aliasNames"), "Address object shouldn't be null");
        -        assertNull(mBeanDerivedManaged.getAttribute("derived"), "Derived object shouldn't registerd with container so its value will be null");
        +        assertNull(mBeanDerivedManaged.getAttribute("derived"), "Derived object shouldn't registered with container so its value will be null");
             }
         
             private Derived[] getArrayTypeAttribute()
        @@ -246,119 +161,76 @@ public class ObjectMBeanUtilTest
                 MBeanContainer mBeanDerivedManagedContainer = new MBeanContainer(ManagementFactory.getPlatformMBeanServer());
                 mBeanDerivedManaged.setMBeanContainer(mBeanDerivedManagedContainer);
                 Derived derived0 = new Derived();
        -        mBeanDerivedManagedContainer.beanAdded(null,derived0);
        -        Derived[] derivedes = new Derived[3];
        +        mBeanDerivedManagedContainer.beanAdded(null, derived0);
        +        Derived[] deriveds = new Derived[3];
                 for (int i = 0; i < 3; i++)
                 {
        -            derivedes[i] = new Derived();
        +            deriveds[i] = new Derived();
                 }
        -        derivedManaged.setAddresses(derivedes);
        +        derivedManaged.setAddresses(deriveds);
                 mBeanDerivedManaged.getMBeanInfo();
        -        ArrayList aliasNames = new ArrayList(Arrays.asList(derivedes));
        +        ArrayList aliasNames = new ArrayList<>(Arrays.asList(deriveds));
                 derivedManaged.setAliasNames(aliasNames);
        -        return derivedes;
        -    }
        -
        -    private ArrayList getCollectionTypeAttribute()
        -    {
        -        ArrayList aliasNames = new ArrayList(Arrays.asList(getArrayTypeAttribute()));
        -        return aliasNames;
        +        return deriveds;
             }
         
             @Test
             public void testSetAttributesException()
             {
        -        // given
        -        attributes = getAttributes("fnameee","charu");
        +        AttributeList attributes = getAttributes("fnameee", "charu");
         
        -        // when
                 attributes = objectMBean.setAttributes(attributes);
         
        -        // then
                 // Original code eating the exception and returning zero size list
        -        assertEquals(EMPTY,attributes.size(),"As there is no attribute with the name fnameee, this should return empty");
        +        assertEquals(0, attributes.size(), "As there is no attribute with the name fnameee, this should return empty");
             }
         
             private AttributeList getAttributes(String name, String value)
             {
        -        Attribute attribute = new Attribute(name,value);
        +        Attribute attribute = new Attribute(name, value);
                 AttributeList attributes = new AttributeList();
                 attributes.add(attribute);
                 return attributes;
             }
         
             @Test
        -    public void testInvokeMBeanException() throws Exception
        +    public void testInvokeMBeanException()
             {
        -        // given
        -        setMBeanInfoForInvoke();
        +        ReflectionException e = assertThrows(ReflectionException.class, () -> objectMBean.invoke("doodle2", new Object[0], new String[0]));
         
        -        // when
        -        MBeanException e = assertThrows(MBeanException.class, ()->{
        -            objectMBean.invoke("doodle2",new Object[] {},new String[] {});
        -        });
        -
        -        // then
        -        assertNotNull(e, "An MBeanException must have occurred by now as doodle2() in Derived bean throwing exception");
        +        assertNotNull(e, "An ReflectionException must have occurred by now as doodle2() in Derived bean is private");
             }
         
             @Test
        -    public void testInvokeReflectionException() throws Exception
        +    public void testInvokeReflectionException()
             {
        -        // given
        -        setMBeanInfoForInvoke();
        +        MBeanException e = assertThrows(MBeanException.class, () -> objectMBean.invoke("doodle1", new Object[0], new String[0]));
         
        -        // when
        -        ReflectionException e = assertThrows(ReflectionException.class, ()->{
        -            objectMBean.invoke("doodle1",new Object[] {},new String[] {});
        -        });
        -
        -        // then
        -        assertNotNull(e, "ReflectionException is null");
        +        assertNotNull(e, "MBeanException is null");
             }
         
             @Test
             public void testInvoke() throws Exception
             {
        -        // given
        -        setMBeanInfoForInvoke();
        +        String value = (String)objectMBean.invoke("good", new Object[0], new String[0]);
         
        -        // when
        -        value = (String)objectMBean.invoke("good",new Object[] {},new String[] {});
        -
        -        // then
                 assertEquals("not bad", value, "Method(good) invocation on objectMBean must return not bad");
             }
         
             @Test
        -    public void testInvokeNoSuchMethodException() throws Exception
        +    public void testInvokeNoSuchMethodException()
             {
        -        // given
        -        setMBeanInfoForInvoke();
        +        // DerivedMBean contains a managed method with the name good,
        +        // we must call this method without any arguments.
        +        ReflectionException e = assertThrows(ReflectionException.class, () ->
        +            objectMBean.invoke("good", new Object[0], new String[]{"int aone"}));
         
        -        // when
        -        // DerivedMBean contains a managed method with the name good,we must
        -        // call this method without any arguments
        -        ReflectionException e = assertThrows(ReflectionException.class, ()->{
        -            objectMBean.invoke("good",new Object[] {},new String[]
        -                    { "int aone" });
        -        });
        -
        -        // then
        -        assertNotNull(e, "An ReflectionException must have occurred by now as we cannot call a methow with wrong signature");
        -
        -    }
        -
        -    private void setMBeanInfoForInvoke()
        -    {
        -        objectMBean = (ObjectMBean)ObjectMBean.mbeanFor(derivedExtended);
        -        container.beanAdded(null,derivedExtended);
        -        objectMBean.getMBeanInfo();
        +        assertNotNull(e, "A ReflectionException must have occurred by now as we cannot call a method with wrong signature");
             }
         
             @Test
        -    public void testToVariableName()
        +    public void testToAttributeName()
             {
        -        assertEquals("fullName",objectMBean.toVariableName("isfullName"));
        +        assertEquals("fullName", MetaData.toAttributeName("isfullName"));
             }
         }
        diff --git a/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/PojoTest.java b/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/PojoTest.java
        index 3ea782d22ff..4356cdbc5ad 100644
        --- a/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/PojoTest.java
        +++ b/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/PojoTest.java
        @@ -1,6 +1,6 @@
         //
         //  ========================================================================
        -//  Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
        +//  Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
         //  ------------------------------------------------------------------------
         //  All rights reserved. This program and the accompanying materials
         //  are made available under the terms of the Eclipse Public License v1.0
        @@ -20,27 +20,25 @@ package org.eclipse.jetty.jmx;
         
         import java.util.Arrays;
         import java.util.List;
        -import org.eclipse.jetty.util.log.jmx.LogMBean;
        -import org.junit.jupiter.api.Test;
        +
         import com.openpojo.reflection.impl.PojoClassFactory;
         import com.openpojo.validation.Validator;
         import com.openpojo.validation.ValidatorBuilder;
         import com.openpojo.validation.test.impl.GetterTester;
         import com.openpojo.validation.test.impl.SetterTester;
        +import org.eclipse.jetty.util.log.jmx.LogMBean;
        +import org.junit.jupiter.api.Test;
         
         /*
          * This class tests all the getters and setters for a given list of classes.
          */
         public class PojoTest
         {
        -
        -    private Validator validator;
        -
             @Test
             public void testOpenPojo()
             {
        -        validator = ValidatorBuilder.create().with(new SetterTester()).with(new GetterTester()).build();
        -        List classes = Arrays.asList(MBeanContainer.class,ObjectMBean.class,LogMBean.class);
        +        Validator validator = ValidatorBuilder.create().with(new SetterTester()).with(new GetterTester()).build();
        +        List classes = Arrays.asList(MBeanContainer.class, ObjectMBean.class, LogMBean.class);
                 for (Class clazz : classes)
                 {
                     validator.validate(PojoClassFactory.getPojoClass(clazz));
        diff --git a/jetty-jmx/src/test/java/org/eclipse/jetty/util/log/jmx/LogMBeanTest.java b/jetty-jmx/src/test/java/org/eclipse/jetty/util/log/jmx/LogMBeanTest.java
        index 32518893349..d3a5afaac9e 100644
        --- a/jetty-jmx/src/test/java/org/eclipse/jetty/util/log/jmx/LogMBeanTest.java
        +++ b/jetty-jmx/src/test/java/org/eclipse/jetty/util/log/jmx/LogMBeanTest.java
        @@ -1,6 +1,6 @@
         //
         //  ========================================================================
        -//  Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
        +//  Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
         //  ------------------------------------------------------------------------
         //  All rights reserved. This program and the accompanying materials
         //  are made available under the terms of the Eclipse Public License v1.0
        @@ -18,16 +18,16 @@
         
         package org.eclipse.jetty.util.log.jmx;
         
        -import static org.hamcrest.MatcherAssert.assertThat;
        -import static org.hamcrest.Matchers.isIn;
        -import static org.hamcrest.Matchers.not;
        -import static org.junit.jupiter.api.Assertions.assertTrue;
        -
         import com.acme.Managed;
        -
         import org.junit.jupiter.api.BeforeEach;
         import org.junit.jupiter.api.Test;
         
        +import static org.hamcrest.MatcherAssert.assertThat;
        +import static org.hamcrest.Matchers.in;
        +import static org.hamcrest.Matchers.is;
        +import static org.hamcrest.Matchers.not;
        +import static org.junit.jupiter.api.Assertions.assertTrue;
        +
         public class LogMBeanTest
         {
         
        @@ -48,13 +48,13 @@ public class LogMBeanTest
             public void testKeySet()
             {
                 // given
        -        assertThat("Managed is not registered with loggers", MANAGED_CLASS, not(isIn(logMBean.getLoggers())));
        +        assertThat("Managed is not registered with loggers", MANAGED_CLASS, not(is(in(logMBean.getLoggers()))));
         
                 // when
        -        logMBean.setDebugEnabled(MANAGED_CLASS,true);
        +        logMBean.setDebugEnabled(MANAGED_CLASS, true);
         
                 // then
        -        assertThat("Managed must be registered with loggers", MANAGED_CLASS, isIn(logMBean.getLoggers()));
        +        assertThat("Managed must be registered with loggers", MANAGED_CLASS, is(in(logMBean.getLoggers())));
                 assertTrue(logMBean.isDebugEnabled(MANAGED_CLASS), "This must return true as debug is enabled for this class");
             }
         }
        diff --git a/jetty-jmx/src/test/resources/jetty-logging.properties b/jetty-jmx/src/test/resources/jetty-logging.properties
        index f0392ad78c1..ad4b63c91cc 100644
        --- a/jetty-jmx/src/test/resources/jetty-logging.properties
        +++ b/jetty-jmx/src/test/resources/jetty-logging.properties
        @@ -1,2 +1,2 @@
         org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
        -org.eclipse.jetty.jmx.LEVEL=INFO
        +#org.eclipse.jetty.jmx.LEVEL=DEBUG
        diff --git a/jetty-jndi/pom.xml b/jetty-jndi/pom.xml
        index 4e6d764aa8a..a8f2112e6c0 100644
        --- a/jetty-jndi/pom.xml
        +++ b/jetty-jndi/pom.xml
        @@ -2,7 +2,7 @@
           
             org.eclipse.jetty
             jetty-project
        -    9.4.13-SNAPSHOT
        +    9.4.21-SNAPSHOT
           
           4.0.0
           jetty-jndi
        @@ -18,11 +18,11 @@
                 org.apache.felix
                 maven-bundle-plugin
                 true
        -            
        -              
        -               javax.mail.*;resolution:=optional,*
        -              
        -            
        +        
        +          
        +            javax.mail.*;resolution:=optional,*
        +          
        +        
               
               
                 org.apache.maven.plugins
        diff --git a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/BindingEnumeration.java b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/BindingEnumeration.java
        index 6e1c874a453..428500c1b0c 100644
        --- a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/BindingEnumeration.java
        +++ b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/BindingEnumeration.java
        @@ -1,6 +1,6 @@
         //
         //  ========================================================================
        -//  Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
        +//  Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
         //  ------------------------------------------------------------------------
         //  All rights reserved. This program and the accompanying materials
         //  are made available under the terms of the Eclipse Public License v1.0
        @@ -16,23 +16,21 @@
         //  ========================================================================
         //
         
        -
         package org.eclipse.jetty.jndi;
         
         import java.util.Iterator;
        -
         import javax.naming.Binding;
         import javax.naming.NamingEnumeration;
         import javax.naming.NamingException;
         
        -/** 
        +/**
          * BindingEnumeration
          */
         public class BindingEnumeration implements NamingEnumeration
         {
             Iterator _delegate;
         
        -    public BindingEnumeration (Iterator e)
        +    public BindingEnumeration(Iterator e)
             {
                 _delegate = e;
             }
        @@ -44,7 +42,7 @@ public class BindingEnumeration implements NamingEnumeration
             }
         
             @Override
        -    public boolean hasMore ()
        +    public boolean hasMore()
                 throws NamingException
             {
                 return _delegate.hasNext();
        @@ -54,8 +52,8 @@ public class BindingEnumeration implements NamingEnumeration
             public Binding next()
                 throws NamingException
             {
        -        Binding b = (Binding)_delegate.next();
        -        return new Binding (b.getName(), b.getClassName(), b.getObject(), true);
        +        Binding b = _delegate.next();
        +        return new Binding(b.getName(), b.getClassName(), b.getObject(), true);
             }
         
             @Override
        @@ -67,7 +65,7 @@ public class BindingEnumeration implements NamingEnumeration
             @Override
             public Binding nextElement()
             {
        -        Binding b = (Binding)_delegate.next();
        -        return new Binding (b.getName(), b.getClassName(), b.getObject(),true);
        +        Binding b = _delegate.next();
        +        return new Binding(b.getName(), b.getClassName(), b.getObject(), true);
             }
         }
        diff --git a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/ContextFactory.java b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/ContextFactory.java
        index 143efa9e5f9..e2302184605 100644
        --- a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/ContextFactory.java
        +++ b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/ContextFactory.java
        @@ -1,6 +1,6 @@
         //
         //  ========================================================================
        -//  Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
        +//  Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
         //  ------------------------------------------------------------------------
         //  All rights reserved. This program and the accompanying materials
         //  are made available under the terms of the Eclipse Public License v1.0
        @@ -18,12 +18,11 @@
         
         package org.eclipse.jetty.jndi;
         
        -
         import java.io.IOException;
        +import java.util.Collections;
         import java.util.Hashtable;
         import java.util.Map;
         import java.util.WeakHashMap;
        -
         import javax.naming.Context;
         import javax.naming.Name;
         import javax.naming.NameParser;
        @@ -32,10 +31,10 @@ import javax.naming.StringRefAddr;
         import javax.naming.spi.ObjectFactory;
         
         import org.eclipse.jetty.server.handler.ContextHandler;
        +import org.eclipse.jetty.util.component.Dumpable;
        +import org.eclipse.jetty.util.log.Log;
         import org.eclipse.jetty.util.log.Logger;
         
        -
        -
         /**
          * ContextFactory
          * 

        @@ -54,125 +53,138 @@ import org.eclipse.jetty.util.log.Logger; * we try looking at the thread context classloader if it is set, and walk its * hierarchy, creating a context if none is found. If the thread context classloader * is not set, then we use the classloader associated with the current Context. - *

        + *

        * If there is no current context, or no classloader, we return null. */ public class ContextFactory implements ObjectFactory { - private static Logger __log = NamingUtil.__log; + private static final Logger LOG = Log.getLogger(ContextFactory.class); /** * Map of classloaders to contexts. */ - private static final WeakHashMap __contextMap = new WeakHashMap(); + private static final Map __contextMap = Collections.synchronizedMap(new WeakHashMap<>()); /** * Threadlocal for injecting a context to use * instead of looking up the map. */ private static final ThreadLocal __threadContext = new ThreadLocal(); - + /** - * Threadlocal for setting a classloader which must be used + * Threadlocal for setting a classloader which must be used * when finding the comp context. */ private static final ThreadLocal __threadClassLoader = new ThreadLocal(); - - /** * Find or create a context which pertains to a classloader. *

        * If the thread context classloader is set, we try to find an already-created naming context - * for it. If one does not exist, we walk its classloader hierarchy until one is found, or we + * for it. If one does not exist, we walk its classloader hierarchy until one is found, or we * run out of parent classloaders. In the latter case, we will create a new naming context associated * with the original thread context classloader. *

        - * If the thread context classloader is not set, we obtain the classloader from the current - * jetty Context, and look for an already-created naming context. + * If the thread context classloader is not set, we obtain the classloader from the current + * jetty Context, and look for an already-created naming context. *

        - * If there is no current jetty Context, or it has no associated classloader, we + * If there is no current jetty Context, or it has no associated classloader, we * return null. + * * @see javax.naming.spi.ObjectFactory#getObjectInstance(java.lang.Object, javax.naming.Name, javax.naming.Context, java.util.Hashtable) */ @Override - public Object getObjectInstance (Object obj, - Name name, - Context nameCtx, - Hashtable env) + public Object getObjectInstance(Object obj, + Name name, + Context nameCtx, + Hashtable env) throws Exception { //First, see if we have had a context injected into us to use. - Context ctx = (Context)__threadContext.get(); + Context ctx = __threadContext.get(); if (ctx != null) { - if(__log.isDebugEnabled()) __log.debug("Using the Context that is bound on the thread"); + if (LOG.isDebugEnabled()) + LOG.debug("Using the Context that is bound on the thread"); return ctx; } //See if there is a classloader to use for finding the comp context //Don't use its parent hierarchy if set. - ClassLoader loader = (ClassLoader)__threadClassLoader.get(); + ClassLoader loader = __threadClassLoader.get(); if (loader != null) { - if (__log.isDebugEnabled() && loader != null) __log.debug("Using threadlocal classloader"); - ctx = getContextForClassLoader(loader); - if (ctx == null) - { - ctx = newNamingContext(obj, loader, env, name, nameCtx); - __contextMap.put (loader, ctx); - if(__log.isDebugEnabled())__log.debug("Made context "+name.get(0)+" for classloader: "+loader); - } - return ctx; - } - - //If the thread context classloader is set, then try its hierarchy to find a matching context - ClassLoader tccl = Thread.currentThread().getContextClassLoader(); - loader = tccl; - if (loader != null) - { - if (__log.isDebugEnabled() && loader != null) __log.debug("Trying thread context classloader"); - while (ctx == null && loader != null) + if (LOG.isDebugEnabled()) + LOG.debug("Using threadlocal classloader"); + synchronized (__contextMap) { ctx = getContextForClassLoader(loader); - if (ctx == null && loader != null) - loader = loader.getParent(); + if (ctx == null) + { + ctx = newNamingContext(obj, loader, env, name, nameCtx); + __contextMap.put(loader, ctx); + if (LOG.isDebugEnabled()) + LOG.debug("Made context {} for classloader {}", name.get(0), loader); + } + return ctx; } - - if (ctx == null) - { - ctx = newNamingContext(obj, tccl, env, name, nameCtx); - __contextMap.put (tccl, ctx); - if(__log.isDebugEnabled())__log.debug("Made context "+name.get(0)+" for classloader: "+tccl); - } - return ctx; } + //If the thread context classloader is set, then try its hierarchy to find a matching context + ClassLoader tccl = Thread.currentThread().getContextClassLoader(); + loader = tccl; + if (loader != null) + { + if (LOG.isDebugEnabled()) + LOG.debug("Trying thread context classloader"); + synchronized (__contextMap) + { + while (ctx == null && loader != null) + { + ctx = getContextForClassLoader(loader); + if (ctx == null && loader != null) + loader = loader.getParent(); + } + + if (ctx == null) + { + ctx = newNamingContext(obj, tccl, env, name, nameCtx); + __contextMap.put(tccl, ctx); + if (LOG.isDebugEnabled()) + LOG.debug("Made context {} for classloader {}", name.get(0), tccl); + } + return ctx; + } + } //If trying thread context classloader hierarchy failed, try the //classloader associated with the current context if (ContextHandler.getCurrentContext() != null) { - - if (__log.isDebugEnabled() && loader != null) __log.debug("Trying classloader of current org.eclipse.jetty.server.handler.ContextHandler"); - loader = ContextHandler.getCurrentContext().getContextHandler().getClassLoader(); - ctx = (Context)__contextMap.get(loader); - - if (ctx == null && loader != null) + if (LOG.isDebugEnabled() && loader != null) + LOG.debug("Trying classloader of current org.eclipse.jetty.server.handler.ContextHandler"); + synchronized (__contextMap) { - ctx = newNamingContext(obj, loader, env, name, nameCtx); - __contextMap.put (loader, ctx); - if(__log.isDebugEnabled())__log.debug("Made context "+name.get(0)+" for classloader: "+loader); - } + loader = ContextHandler.getCurrentContext().getContextHandler().getClassLoader(); + ctx = __contextMap.get(loader); - return ctx; + if (ctx == null && loader != null) + { + ctx = newNamingContext(obj, loader, env, name, nameCtx); + __contextMap.put(loader, ctx); + if (LOG.isDebugEnabled()) + LOG.debug("Made context {} for classloader {} ", name.get(0), loader); + } + + return ctx; + } } return null; } - /** * Create a new NamingContext. + * * @param obj the object to create * @param loader the classloader for the naming context * @param env the jndi env for the entry @@ -182,24 +194,23 @@ public class ContextFactory implements ObjectFactory * @throws Exception if unable to create a new naming context */ public NamingContext newNamingContext(Object obj, ClassLoader loader, Hashtable env, Name name, Context parentCtx) - throws Exception + throws Exception { Reference ref = (Reference)obj; StringRefAddr parserAddr = (StringRefAddr)ref.get("parser"); - String parserClassName = (parserAddr==null?null:(String)parserAddr.getContent()); + String parserClassName = (parserAddr == null ? null : (String)parserAddr.getContent()); NameParser parser = - (NameParser)(parserClassName==null? - null:loader.loadClass(parserClassName).getDeclaredConstructor().newInstance()); + (NameParser)(parserClassName == null ? null : loader.loadClass(parserClassName).getDeclaredConstructor().newInstance()); - return new NamingContext (env, - name.get(0), - (NamingContext)parentCtx, - parser); + return new NamingContext(env, + name.get(0), + (NamingContext)parentCtx, + parser); } - /** * Find the naming Context for the given classloader + * * @param loader the classloader for the context * @return the context for the classloader */ @@ -207,19 +218,20 @@ public class ContextFactory implements ObjectFactory { if (loader == null) return null; - - return (Context)__contextMap.get(loader); + + return __contextMap.get(loader); } /** * Associate the given Context with the current thread. * disassociate method should be called to reset the context. + * * @param ctx the context to associate to the current thread. * @return the previous context associated on the thread (can be null) */ public static Context associateContext(final Context ctx) { - Context previous = (Context)__threadContext.get(); + Context previous = __threadContext.get(); __threadContext.set(ctx); return previous; } @@ -228,32 +240,24 @@ public class ContextFactory implements ObjectFactory { __threadContext.set(null); } - + public static ClassLoader associateClassLoader(final ClassLoader loader) { - ClassLoader prev = (ClassLoader)__threadClassLoader.get(); + ClassLoader prev = __threadClassLoader.get(); __threadClassLoader.set(loader); return prev; } - - public static void disassociateClassLoader () + + public static void disassociateClassLoader() { __threadClassLoader.set(null); } public static void dump(Appendable out, String indent) throws IOException { - out.append("o.e.j.jndi.ContextFactory@").append(Long.toHexString(__contextMap.hashCode())).append("\n"); - int size=__contextMap.size(); - int i=0; - for (Map.Entry entry : ((Map)__contextMap).entrySet()) + synchronized (__contextMap) { - boolean last=++i==size; - ClassLoader loader=entry.getKey(); - out.append(indent).append(" +- ").append(loader.getClass().getSimpleName()).append("@").append(Long.toHexString(loader.hashCode())).append(": "); - - NamingContext context = entry.getValue(); - context.dump(out,indent+(last?" ":" | ")); + Dumpable.dumpObjects(out, indent, String.format("o.e.j.jndi.ContextFactory@", __contextMap.hashCode()), __contextMap); } } } diff --git a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/DataSourceCloser.java b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/DataSourceCloser.java index 7b60a643757..ccebce8e328 100644 --- a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/DataSourceCloser.java +++ b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/DataSourceCloser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -21,7 +21,6 @@ package org.eclipse.jetty.jndi; import java.lang.reflect.Method; import java.sql.Connection; import java.sql.Statement; - import javax.sql.DataSource; import org.eclipse.jetty.util.component.ContainerLifeCycle; @@ -34,7 +33,6 @@ import org.eclipse.jetty.util.log.Logger; * Some {@link DataSource}'s need to be close (eg. Atomikos). This bean is a {@link Destroyable} and * may be added to any {@link ContainerLifeCycle} so that {@link #destroy()} * will be called. The {@link #destroy()} method calls any no-arg method called "close" on the passed DataSource. - * */ public class DataSourceCloser implements Destroyable { @@ -45,18 +43,18 @@ public class DataSourceCloser implements Destroyable public DataSourceCloser(DataSource datasource) { - if (datasource==null) + if (datasource == null) throw new IllegalArgumentException(); - _datasource=datasource; - _shutdown=null; + _datasource = datasource; + _shutdown = null; } - public DataSourceCloser(DataSource datasource,String shutdownSQL) + public DataSourceCloser(DataSource datasource, String shutdownSQL) { - if (datasource==null) + if (datasource == null) throw new IllegalArgumentException(); - _datasource=datasource; - _shutdown=shutdownSQL; + _datasource = datasource; + _shutdown = shutdownSQL; } @Override @@ -64,11 +62,11 @@ public class DataSourceCloser implements Destroyable { try { - if (_shutdown!=null) + if (_shutdown != null) { - LOG.info("Shutdown datasource {}",_datasource); + LOG.info("Shutdown datasource {}", _datasource); try (Connection connection = _datasource.getConnection(); - Statement stmt = connection.createStatement()) + Statement stmt = connection.createStatement()) { stmt.executeUpdate(_shutdown); } @@ -81,9 +79,9 @@ public class DataSourceCloser implements Destroyable try { - Method close = _datasource.getClass().getMethod("close", new Class[]{}); - LOG.info("Close datasource {}",_datasource); - close.invoke(_datasource, new Object[]{}); + Method close = _datasource.getClass().getMethod("close"); + LOG.info("Close datasource {}", _datasource); + close.invoke(_datasource); } catch (Exception e) { diff --git a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/InitialContextFactory.java b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/InitialContextFactory.java index d9b5a67ea45..50600cbff28 100644 --- a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/InitialContextFactory.java +++ b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/InitialContextFactory.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,10 +18,8 @@ package org.eclipse.jetty.jndi; - import java.util.Hashtable; import java.util.Properties; - import javax.naming.CompoundName; import javax.naming.Context; import javax.naming.Name; @@ -29,59 +27,58 @@ import javax.naming.NameParser; import javax.naming.NamingException; import org.eclipse.jetty.jndi.local.localContextRoot; +import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; - -/*------------------------------------------------*/ /** * InitialContextFactory.java * * Factory for the default InitialContext. * Created: Tue Jul 1 19:08:08 2003 * - * * @version 1.0 */ public class InitialContextFactory implements javax.naming.spi.InitialContextFactory { - private static Logger __log = NamingUtil.__log; + private static final Logger LOG = Log.getLogger(InitialContextFactory.class); public static class DefaultParser implements NameParser { static Properties syntax = new Properties(); + static { syntax.put("jndi.syntax.direction", "left_to_right"); syntax.put("jndi.syntax.separator", "/"); syntax.put("jndi.syntax.ignorecase", "false"); } + @Override - public Name parse (String name) + public Name parse(String name) throws NamingException { - return new CompoundName (name, syntax); + return new CompoundName(name, syntax); } - }; + } - - - /*------------------------------------------------*/ /** * Get Context that has access to default Namespace. * This method won't be called if a name URL beginning * with java: is passed to an InitialContext. * - * @see org.eclipse.jetty.jndi.java.javaURLContextFactory * @param env a Hashtable value * @return a Context value + * @see org.eclipse.jetty.jndi.java.javaURLContextFactory */ @Override public Context getInitialContext(Hashtable env) { - __log.debug("InitialContextFactory.getInitialContext()"); + if (LOG.isDebugEnabled()) + LOG.debug("InitialContextFactory.getInitialContext()"); Context ctx = new localContextRoot(env); - if(__log.isDebugEnabled())__log.debug("Created initial context delegate for local namespace:"+ctx); + if (LOG.isDebugEnabled()) + LOG.debug("Created initial context delegate for local namespace:" + ctx); return ctx; } diff --git a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/NameEnumeration.java b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/NameEnumeration.java index 7ecdc50bca6..ffba9bcd981 100644 --- a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/NameEnumeration.java +++ b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/NameEnumeration.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,20 +19,19 @@ package org.eclipse.jetty.jndi; import java.util.Iterator; - import javax.naming.Binding; import javax.naming.NameClassPair; import javax.naming.NamingEnumeration; import javax.naming.NamingException; -/** +/** * NameEnumeration */ public class NameEnumeration implements NamingEnumeration { Iterator _delegate; - public NameEnumeration (Iterator e) + public NameEnumeration(Iterator e) { _delegate = e; } @@ -44,7 +43,7 @@ public class NameEnumeration implements NamingEnumeration } @Override - public boolean hasMore () + public boolean hasMore() throws NamingException { return _delegate.hasNext(); @@ -55,7 +54,7 @@ public class NameEnumeration implements NamingEnumeration throws NamingException { Binding b = _delegate.next(); - return new NameClassPair(b.getName(),b.getClassName(),true); + return new NameClassPair(b.getName(), b.getClassName(), true); } @Override @@ -68,6 +67,6 @@ public class NameEnumeration implements NamingEnumeration public NameClassPair nextElement() { Binding b = _delegate.next(); - return new NameClassPair(b.getName(),b.getClassName(),true); + return new NameClassPair(b.getName(), b.getClassName(), true); } } diff --git a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/NamingContext.java b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/NamingContext.java index 009e271c00a..94ebf286c9c 100644 --- a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/NamingContext.java +++ b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/NamingContext.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -26,7 +26,8 @@ import java.util.HashMap; import java.util.Hashtable; import java.util.List; import java.util.Map; - +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import javax.naming.Binding; import javax.naming.CompoundName; import javax.naming.Context; @@ -45,9 +46,10 @@ import javax.naming.Referenceable; import javax.naming.spi.NamingManager; import org.eclipse.jetty.util.component.Dumpable; +import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -/** +/** * NamingContext *

        * Implementation of Context interface. @@ -56,24 +58,37 @@ import org.eclipse.jetty.util.log.Logger; * All Names are expected to be Compound, not Composite. */ @SuppressWarnings("unchecked") -public class NamingContext implements Context, Cloneable, Dumpable +public class NamingContext implements Context, Dumpable { - private final static Logger __log=NamingUtil.__log; - private final static List __empty = Collections.emptyList(); + private static final Logger LOG = Log.getLogger(NamingContext.class); + private static final List __empty = Collections.emptyList(); public static final String DEEP_BINDING = "org.eclipse.jetty.jndi.deepBinding"; public static final String LOCK_PROPERTY = "org.eclipse.jetty.jndi.lock"; public static final String UNLOCK_PROPERTY = "org.eclipse.jetty.jndi.unlock"; - protected final Hashtable _env = new Hashtable(); - private boolean _supportDeepBinding = false; - protected Map _bindings = new HashMap(); + /* + * The env is stored as a Hashtable to be compatible with the API. + * There is no need for concurrent protection (see Concurrent Access section + * of the {@link Context} javadoc), so multiple threads acting on the same + * Context env need to self - mutually exclude. + */ + protected final Hashtable _env = new Hashtable<>(); + + /* + * This contexts bindings are stored as a ConcurrentHashMap. + * There is generally no need for concurrent protection (see Concurrent Access section + * of the {@link Context} javadoc), However, the NamingContext is used for root contexts and + * we do not mutually exclude when initializing, so instead we do make the bindings + * thread safe (unlike the env where we expect users to respect the Concurrent Access requirements). + */ + protected final ConcurrentMap _bindings; protected NamingContext _parent = null; protected String _name = null; protected NameParser _parser = null; private Collection _listeners; + private Object _lock; - /*------------------------------------------------*/ /** * Naming Context Listener. */ @@ -82,6 +97,7 @@ public class NamingContext implements Context, Cloneable, Dumpable /** * Called by {@link NamingContext#addBinding(Name, Object)} when adding * a binding. + * * @param ctx The context to add to. * @param binding The binding to add. * @return The binding to bind, or null if the binding should be ignored. @@ -95,78 +111,69 @@ public class NamingContext implements Context, Cloneable, Dumpable void unbind(NamingContext ctx, Binding binding); } - /*------------------------------------------------*/ /** * Constructor * - * @param env environment properties + * @param env environment properties which are copied into this Context's environment * @param name relative name of this context * @param parent immediate ancestor Context (can be null) * @param parser NameParser for this Context */ - public NamingContext(Hashtable env, + public NamingContext(Hashtable env, String name, NamingContext parent, NameParser parser) + { + this(env, name, parent, parser, null); + } + + protected NamingContext(Hashtable env, + String name, + NamingContext parent, + NameParser parser, + ConcurrentMap bindings) { if (env != null) - { _env.putAll(env); - // look for deep binding support in _env - Object support = _env.get(DEEP_BINDING); - if (support == null) - _supportDeepBinding = false; - else - _supportDeepBinding = support != null?Boolean.parseBoolean(support.toString()):false; - } - else - { - // no env? likely this is a root context (java or local) that - // was created without an _env. Look for a system property. - String value = System.getProperty(DEEP_BINDING,"false"); - _supportDeepBinding = Boolean.parseBoolean(value); - // put what we discovered into the _env for later sub-contexts - // to utilize. - _env.put(DEEP_BINDING,_supportDeepBinding); - } _name = name; _parent = parent; _parser = parser; - if(__log.isDebugEnabled()) - __log.debug("supportDeepBinding={}",_supportDeepBinding); + _bindings = bindings == null ? new ConcurrentHashMap<>() : bindings; + if (LOG.isDebugEnabled()) + LOG.debug("new {}", this); } - - /*------------------------------------------------*/ /** - * Clone this NamingContext - * - * @return copy of this NamingContext - * @exception CloneNotSupportedException if an error occurs + * @return A shallow copy of the Context with the same bindings, but with the passed environment */ - @Override - public Object clone () - throws CloneNotSupportedException + public Context shallowCopy(Hashtable env) { - NamingContext ctx = (NamingContext)super.clone(); - ctx._env.putAll(_env); - ctx._bindings.putAll(_bindings); - return ctx; + return new NamingContext(env, _name, _parent, _parser, _bindings); } + public boolean isDeepBindingSupported() + { + // look for deep binding support in _env + Object support = _env.get(DEEP_BINDING); + if (support != null) + return Boolean.parseBoolean(String.valueOf(support)); + + if (_parent != null) + return _parent.isDeepBindingSupported(); + // probably a root context + return Boolean.parseBoolean(System.getProperty(DEEP_BINDING, "false")); + } - /*------------------------------------------------*/ /** * Getter for _name * * @return name of this Context (relative, not absolute) */ - public String getName () + public String getName() { return _name; } - /*------------------------------------------------*/ /** * Getter for _parent * @@ -177,62 +184,100 @@ public class NamingContext implements Context, Cloneable, Dumpable return _parent; } - /*------------------------------------------------*/ - public void setNameParser (NameParser parser) + public void setNameParser(NameParser parser) { _parser = parser; } - - public final void setEnv (Hashtable env) + public final void setEnv(Hashtable env) { - _env.clear(); - if(env == null) - return; - _env.putAll(env); - _supportDeepBinding = _env.containsKey(DEEP_BINDING); + Object lock = _env.get(LOCK_PROPERTY); + try + { + _env.clear(); + if (env == null) + return; + _env.putAll(env); + } + finally + { + if (lock != null) + _env.put(LOCK_PROPERTY, lock); + } } - - public Map getBindings () + private Object dereference(Object ctx, String firstComponent) throws NamingException { - return _bindings; + if (ctx instanceof Reference) + { + //deference the object + try + { + return NamingManager.getObjectInstance(ctx, _parser.parse(firstComponent), this, _env); + } + catch (NamingException e) + { + throw e; + } + catch (Exception e) + { + LOG.warn("", e); + throw new NamingException(e.getMessage()); + } + } + return ctx; } - public void setBindings(Map bindings) + private Context getContext(Name cname) throws NamingException { - _bindings = bindings; + String firstComponent = cname.get(0); + + if (firstComponent.equals("")) + return this; + + Binding binding = getBinding(firstComponent); + if (binding == null) + { + NameNotFoundException nnfe = new NameNotFoundException(firstComponent + " is not bound"); + nnfe.setRemainingName(cname); + throw nnfe; + } + + Object ctx = dereference(binding.getObject(), firstComponent); + + if (!(ctx instanceof Context)) + throw new NotContextException(firstComponent + " not a context in " + this.getNameInNamespace()); + + return (Context)ctx; } - /*------------------------------------------------*/ /** * Bind a name to an object * * @param name Name of the object * @param obj object to bind - * @exception NamingException if an error occurs + * @throws NamingException if an error occurs */ @Override public void bind(Name name, Object obj) throws NamingException { if (isLocked()) - throw new NamingException ("This context is immutable"); + throw new NamingException("This context is immutable"); Name cname = toCanonicalName(name); if (cname == null) - throw new NamingException ("Name is null"); + throw new NamingException("Name is null"); if (cname.size() == 0) - throw new NamingException ("Name is empty"); - + throw new NamingException("Name is empty"); //if no subcontexts, just bind it if (cname.size() == 1) { //get the object to be bound - Object objToBind = NamingManager.getStateToBind(obj, name,this, _env); + Object objToBind = NamingManager.getStateToBind(obj, name, this, _env); // Check for Referenceable if (objToBind instanceof Referenceable) { @@ -240,11 +285,12 @@ public class NamingContext implements Context, Cloneable, Dumpable } //anything else we should be able to bind directly - addBinding (cname, objToBind); + addBinding(cname, objToBind); } else { - if(__log.isDebugEnabled())__log.debug("Checking for existing binding for name="+cname+" for first element of name="+cname.get(0)); + if (LOG.isDebugEnabled()) + LOG.debug("Checking for existing binding for name=" + cname + " for first element of name=" + cname.get(0)); //walk down the subcontext hierarchy //need to ignore trailing empty "" name components @@ -256,14 +302,14 @@ public class NamingContext implements Context, Cloneable, Dumpable ctx = this; else { - - Binding binding = getBinding (firstComponent); - if (binding == null) { - if (_supportDeepBinding) + Binding binding = getBinding(firstComponent); + if (binding == null) + { + if (isDeepBindingSupported()) { Name subname = _parser.parse(firstComponent); - Context subctx = new NamingContext((Hashtable)_env.clone(),firstComponent,this,_parser); - addBinding(subname,subctx); + Context subctx = new NamingContext(_env, firstComponent, this, _parser, null); + addBinding(subname, subctx); binding = getBinding(subname); } else @@ -272,213 +318,132 @@ public class NamingContext implements Context, Cloneable, Dumpable } } - ctx = binding.getObject(); - - if (ctx instanceof Reference) - { - //deference the object - try - { - ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), this, _env); - } - catch (NamingException e) - { - throw e; - } - catch (Exception e) - { - __log.warn("",e); - throw new NamingException (e.getMessage()); - } - } + ctx = dereference(binding.getObject(), firstComponent); } - if (ctx instanceof Context) { - ((Context)ctx).bind (cname.getSuffix(1), obj); + ((Context)ctx).bind(cname.getSuffix(1), obj); } else - throw new NotContextException ("Object bound at "+firstComponent +" is not a Context"); + throw new NotContextException("Object bound at " + firstComponent + " is not a Context"); } } - - - /*------------------------------------------------*/ /** * Bind a name (as a String) to an object * * @param name a String value * @param obj an Object value - * @exception NamingException if an error occurs + * @throws NamingException if an error occurs */ @Override public void bind(String name, Object obj) throws NamingException { - bind (_parser.parse(name), obj); + bind(_parser.parse(name), obj); } - - /*------------------------------------------------*/ /** * Create a context as a child of this one * * @param name a Name value * @return a Context value - * @exception NamingException if an error occurs + * @throws NamingException if an error occurs */ @Override - public Context createSubcontext (Name name) + public Context createSubcontext(Name name) throws NamingException { if (isLocked()) { - NamingException ne = new NamingException ("This context is immutable"); + NamingException ne = new NamingException("This context is immutable"); ne.setRemainingName(name); throw ne; } - Name cname = toCanonicalName (name); + Name cname = toCanonicalName(name); if (cname == null) - throw new NamingException ("Name is null"); + throw new NamingException("Name is null"); if (cname.size() == 0) - throw new NamingException ("Name is empty"); + throw new NamingException("Name is empty"); if (cname.size() == 1) { //not permitted to bind if something already bound at that name - Binding binding = getBinding (cname); + Binding binding = getBinding(cname); if (binding != null) - throw new NameAlreadyBoundException (cname.toString()); + throw new NameAlreadyBoundException(cname.toString()); - Context ctx = new NamingContext ((Hashtable)_env.clone(), cname.get(0), this, _parser); - addBinding (cname, ctx); + Context ctx = new NamingContext(_env, cname.get(0), this, _parser); + addBinding(cname, ctx); return ctx; } - - //If the name has multiple subcontexts, walk the hierarchy by - //fetching the first one. All intermediate subcontexts in the - //name must already exist. - String firstComponent = cname.get(0); - Object ctx = null; - - if (firstComponent.equals("")) - ctx = this; - else - { - Binding binding = getBinding (firstComponent); - if (binding == null) - throw new NameNotFoundException (firstComponent + " is not bound"); - - ctx = binding.getObject(); - - if (ctx instanceof Reference) - { - //deference the object - if(__log.isDebugEnabled())__log.debug("Object bound at "+firstComponent +" is a Reference"); - try - { - ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), this, _env); - } - catch (NamingException e) - { - throw e; - } - catch (Exception e) - { - __log.warn("",e); - throw new NamingException (e.getMessage()); - } - } - } - - if (ctx instanceof Context) - { - return ((Context)ctx).createSubcontext (cname.getSuffix(1)); - } - else - throw new NotContextException (firstComponent +" is not a Context"); + return getContext(cname).createSubcontext(cname.getSuffix(1)); } - - /*------------------------------------------------*/ /** * Create a Context as a child of this one * * @param name a String value * @return a Context value - * @exception NamingException if an error occurs + * @throws NamingException if an error occurs */ @Override - public Context createSubcontext (String name) + public Context createSubcontext(String name) throws NamingException { return createSubcontext(_parser.parse(name)); } - - - /*------------------------------------------------*/ /** - * - * * @param name name of subcontext to remove - * @exception NamingException if an error occurs + * @throws NamingException if an error occurs */ @Override - public void destroySubcontext (String name) + public void destroySubcontext(String name) throws NamingException { removeBinding(_parser.parse(name)); } - - - /*------------------------------------------------*/ /** - * - * * @param name name of subcontext to remove - * @exception NamingException if an error occurs + * @throws NamingException if an error occurs */ @Override - public void destroySubcontext (Name name) + public void destroySubcontext(Name name) throws NamingException { - removeBinding(name); + removeBinding(name); } - /*------------------------------------------------*/ /** * Lookup a binding by name * * @param name name of bound object - * @exception NamingException if an error occurs + * @throws NamingException if an error occurs */ @Override public Object lookup(Name name) throws NamingException { - if(__log.isDebugEnabled())__log.debug("Looking up name=\""+name+"\""); + if (LOG.isDebugEnabled()) + LOG.debug("Looking up name=\"" + name + "\""); Name cname = toCanonicalName(name); if ((cname == null) || (cname.size() == 0)) { - __log.debug("Null or empty name, returning copy of this context"); - NamingContext ctx = new NamingContext (_env, _name, _parent, _parser); - ctx._bindings=_bindings; - return ctx; + if (LOG.isDebugEnabled()) + LOG.debug("Null or empty name, returning shallowCopy of this context"); + return shallowCopy(_env); } - - if (cname.size() == 1) { - Binding binding = getBinding (cname); + Binding binding = getBinding(cname); if (binding == null) { NameNotFoundException nnfe = new NameNotFoundException(); @@ -486,7 +451,6 @@ public class NamingContext implements Context, Cloneable, Dumpable throw nnfe; } - Object o = binding.getObject(); //handle links by looking up the link @@ -495,17 +459,17 @@ public class NamingContext implements Context, Cloneable, Dumpable //if link name starts with ./ it is relative to current context String linkName = ((LinkRef)o).getLinkName(); if (linkName.startsWith("./")) - return this.lookup (linkName.substring(2)); + return this.lookup(linkName.substring(2)); else { //link name is absolute InitialContext ictx = new InitialContext(); - return ictx.lookup (linkName); + return ictx.lookup(linkName); } } else if (o instanceof Reference) { - //deference the object + // TODO use deference ?? try { return NamingManager.getObjectInstance(o, cname, this, _env); @@ -516,271 +480,113 @@ public class NamingContext implements Context, Cloneable, Dumpable } catch (Exception e) { - __log.warn("",e); - throw new NamingException (e.getMessage()); + LOG.warn("", e); + throw new NamingException(e.getMessage()); } } else return o; } - //it is a multipart name, recurse to the first subcontext - - String firstComponent = cname.get(0); - Object ctx = null; - - if (firstComponent.equals("")) - ctx = this; - else - { - - Binding binding = getBinding (firstComponent); - if (binding == null) - { - NameNotFoundException nnfe = new NameNotFoundException(); - nnfe.setRemainingName(cname); - throw nnfe; - } - - //as we have bound a reference to an object factory - //for the component specific contexts - //at "comp" we need to resolve the reference - ctx = binding.getObject(); - - if (ctx instanceof Reference) - { - //deference the object - try - { - ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), this, _env); - } - catch (NamingException e) - { - throw e; - } - catch (Exception e) - { - __log.warn("",e); - throw new NamingException (e.getMessage()); - } - } - } - if (!(ctx instanceof Context)) - throw new NotContextException(); - - return ((Context)ctx).lookup (cname.getSuffix(1)); + return getContext(cname).lookup(cname.getSuffix(1)); } - - /*------------------------------------------------*/ /** * Lookup binding of an object by name * * @param name name of bound object * @return object bound to name - * @exception NamingException if an error occurs + * @throws NamingException if an error occurs */ @Override - public Object lookup (String name) + public Object lookup(String name) throws NamingException { - return lookup (_parser.parse(name)); + return lookup(_parser.parse(name)); } - - - /*------------------------------------------------*/ /** * Lookup link bound to name * * @param name name of link binding * @return LinkRef or plain object bound at name - * @exception NamingException if an error occurs + * @throws NamingException if an error occurs */ @Override - public Object lookupLink (Name name) + public Object lookupLink(Name name) throws NamingException { Name cname = toCanonicalName(name); - if (cname == null) + if (cname == null || name.isEmpty()) { - NamingContext ctx = new NamingContext (_env, _name, _parent, _parser); - ctx._bindings=_bindings; - return ctx; + return shallowCopy(_env); } + if (cname.size() == 0) - throw new NamingException ("Name is empty"); + throw new NamingException("Name is empty"); if (cname.size() == 1) { - Binding binding = getBinding (cname); + Binding binding = getBinding(cname); if (binding == null) throw new NameNotFoundException(); - Object o = binding.getObject(); - - //handle links by looking up the link - if (o instanceof Reference) - { - //deference the object - try - { - return NamingManager.getObjectInstance(o, cname.getPrefix(1), this, _env); - } - catch (NamingException e) - { - throw e; - } - catch (Exception e) - { - __log.warn("",e); - throw new NamingException (e.getMessage()); - } - } - else - { - //object is either a LinkRef which we don't dereference - //or a plain object in which case spec says we return it - return o; - } + return dereference(binding.getObject(), cname.getPrefix(1).toString()); } - - //it is a multipart name, recurse to the first subcontext - String firstComponent = cname.get(0); - Object ctx = null; - - if (firstComponent.equals("")) - ctx = this; - else - { - Binding binding = getBinding (firstComponent); - if (binding == null) - throw new NameNotFoundException (); - - ctx = binding.getObject(); - - if (ctx instanceof Reference) - { - //deference the object - try - { - ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), this, _env); - } - catch (NamingException e) - { - throw e; - } - catch (Exception e) - { - __log.warn("",e); - throw new NamingException (e.getMessage()); - } - } - } - - if (!(ctx instanceof Context)) - throw new NotContextException(); - - return ((Context)ctx).lookup (cname.getSuffix(1)); + return getContext(cname).lookup(cname.getSuffix(1)); } - - /*------------------------------------------------*/ /** * Lookup link bound to name * * @param name name of link binding * @return LinkRef or plain object bound at name - * @exception NamingException if an error occurs + * @throws NamingException if an error occurs */ @Override - public Object lookupLink (String name) + public Object lookupLink(String name) throws NamingException { - return lookupLink (_parser.parse(name)); + return lookupLink(_parser.parse(name)); } - - /*------------------------------------------------*/ /** * List all names bound at Context named by Name * * @param name a Name value * @return a NamingEnumeration value - * @exception NamingException if an error occurs + * @throws NamingException if an error occurs */ @Override public NamingEnumeration list(Name name) throws NamingException { - if(__log.isDebugEnabled())__log.debug("list() on Context="+getName()+" for name="+name); + if (LOG.isDebugEnabled()) + LOG.debug("list() on Context=" + getName() + " for name=" + name); Name cname = toCanonicalName(name); - - if (cname == null) { return new NameEnumeration(__empty.iterator()); } - if (cname.size() == 0) { - return new NameEnumeration (_bindings.values().iterator()); + return new NameEnumeration(_bindings.values().iterator()); } - - //multipart name - String firstComponent = cname.get(0); - Object ctx = null; - - if (firstComponent.equals("")) - ctx = this; - else - { - Binding binding = getBinding (firstComponent); - if (binding == null) - throw new NameNotFoundException (); - - ctx = binding.getObject(); - - if (ctx instanceof Reference) - { - //deference the object - if(__log.isDebugEnabled())__log.debug("Dereferencing Reference for "+name.get(0)); - try - { - ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), this, _env); - } - catch (NamingException e) - { - throw e; - } - catch (Exception e) - { - __log.warn("",e); - throw new NamingException (e.getMessage()); - } - } - } - - if (!(ctx instanceof Context)) - throw new NotContextException(); - - return ((Context)ctx).list (cname.getSuffix(1)); + return getContext(cname).list(cname.getSuffix(1)); } - - /*------------------------------------------------*/ /** * List all names bound at Context named by Name * * @param name a Name value * @return a NamingEnumeration value - * @exception NamingException if an error occurs + * @throws NamingException if an error occurs */ @Override public NamingEnumeration list(String name) @@ -789,21 +595,18 @@ public class NamingContext implements Context, Cloneable, Dumpable return list(_parser.parse(name)); } - - - /*------------------------------------------------*/ /** * List all Bindings present at Context named by Name * * @param name a Name value * @return a NamingEnumeration value - * @exception NamingException if an error occurs + * @throws NamingException if an error occurs */ @Override public NamingEnumeration listBindings(Name name) throws NamingException { - Name cname = toCanonicalName (name); + Name cname = toCanonicalName(name); if (cname == null) { @@ -812,78 +615,32 @@ public class NamingContext implements Context, Cloneable, Dumpable if (cname.size() == 0) { - return new BindingEnumeration (_bindings.values().iterator()); + return new BindingEnumeration(_bindings.values().iterator()); } - - - //multipart name - String firstComponent = cname.get(0); - Object ctx = null; - - //if a name has a leading "/" it is parsed as "" so ignore it by staying - //at this level in the tree - if (firstComponent.equals("")) - ctx = this; - else - { - //it is a non-empty name component - Binding binding = getBinding (firstComponent); - if (binding == null) - throw new NameNotFoundException (); - - ctx = binding.getObject(); - - if (ctx instanceof Reference) - { - //deference the object - try - { - ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), this, _env); - } - catch (NamingException e) - { - throw e; - } - catch (Exception e) - { - __log.warn("",e); - throw new NamingException (e.getMessage()); - } - } - } - - if (!(ctx instanceof Context)) - throw new NotContextException(); - - return ((Context)ctx).listBindings (cname.getSuffix(1)); + return getContext(cname).listBindings(cname.getSuffix(1)); } - - - /*------------------------------------------------*/ /** * List all Bindings at Name * * @param name a String value * @return a NamingEnumeration value - * @exception NamingException if an error occurs + * @throws NamingException if an error occurs */ @Override public NamingEnumeration listBindings(String name) throws NamingException { - return listBindings (_parser.parse(name)); + return listBindings(_parser.parse(name)); } - - /*------------------------------------------------*/ /** * Overwrite or create a binding * * @param name a Name value * @param obj an Object value - * @exception NamingException if an error occurs + * @throws NamingException if an error occurs */ @Override public void rebind(Name name, @@ -891,16 +648,15 @@ public class NamingContext implements Context, Cloneable, Dumpable throws NamingException { if (isLocked()) - throw new NamingException ("This context is immutable"); + throw new NamingException("This context is immutable"); Name cname = toCanonicalName(name); if (cname == null) - throw new NamingException ("Name is null"); + throw new NamingException("Name is null"); if (cname.size() == 0) - throw new NamingException ("Name is empty"); - + throw new NamingException("Name is empty"); //if no subcontexts, just bind it if (cname.size() == 1) @@ -913,173 +669,83 @@ public class NamingContext implements Context, Cloneable, Dumpable objToBind = ((Referenceable)objToBind).getReference(); } removeBinding(cname); - addBinding (cname, objToBind); + addBinding(cname, objToBind); } else { - //walk down the subcontext hierarchy - if(__log.isDebugEnabled())__log.debug("Checking for existing binding for name="+cname+" for first element of name="+cname.get(0)); - - String firstComponent = cname.get(0); - Object ctx = null; - - - if (firstComponent.equals("")) - ctx = this; - else - { - Binding binding = getBinding (name.get(0)); - if (binding == null) - throw new NameNotFoundException (name.get(0)+ " is not bound"); - - ctx = binding.getObject(); - - - if (ctx instanceof Reference) - { - //deference the object - try - { - ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), this, _env); - } - catch (NamingException e) - { - throw e; - } - catch (Exception e) - { - __log.warn("",e); - throw new NamingException (e.getMessage()); - } - } - } - - if (ctx instanceof Context) - { - ((Context)ctx).rebind (cname.getSuffix(1), obj); - } - else - throw new NotContextException ("Object bound at "+firstComponent +" is not a Context"); + getContext(cname).rebind(cname.getSuffix(1), obj); } } - - /*------------------------------------------------*/ /** * Overwrite or create a binding from Name to Object * * @param name a String value * @param obj an Object value - * @exception NamingException if an error occurs + * @throws NamingException if an error occurs */ @Override - public void rebind (String name, - Object obj) + public void rebind(String name, + Object obj) throws NamingException { - rebind (_parser.parse(name), obj); + rebind(_parser.parse(name), obj); } - /*------------------------------------------------*/ /** * Not supported. * * @param name a String value - * @exception NamingException if an error occurs + * @throws NamingException if an error occurs */ @Override - public void unbind (String name) + public void unbind(String name) throws NamingException { unbind(_parser.parse(name)); } - /*------------------------------------------------*/ /** * Not supported. * * @param name a String value - * @exception NamingException if an error occurs + * @throws NamingException if an error occurs */ @Override - public void unbind (Name name) + public void unbind(Name name) throws NamingException { if (name.size() == 0) return; - if (isLocked()) - throw new NamingException ("This context is immutable"); + throw new NamingException("This context is immutable"); Name cname = toCanonicalName(name); if (cname == null) - throw new NamingException ("Name is null"); + throw new NamingException("Name is null"); if (cname.size() == 0) - throw new NamingException ("Name is empty"); - + throw new NamingException("Name is empty"); //if no subcontexts, just unbind it if (cname.size() == 1) { - removeBinding (cname); + removeBinding(cname); } else { - //walk down the subcontext hierarchy - if(__log.isDebugEnabled())__log.debug("Checking for existing binding for name="+cname+" for first element of name="+cname.get(0)); - - String firstComponent = cname.get(0); - Object ctx = null; - - - if (firstComponent.equals("")) - ctx = this; - else - { - Binding binding = getBinding (name.get(0)); - if (binding == null) - throw new NameNotFoundException (name.get(0)+ " is not bound"); - - ctx = binding.getObject(); - - if (ctx instanceof Reference) - { - //deference the object - try - { - ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), this, _env); - } - catch (NamingException e) - { - throw e; - } - catch (Exception e) - { - __log.warn("",e); - throw new NamingException (e.getMessage()); - } - } - } - - if (ctx instanceof Context) - { - ((Context)ctx).unbind (cname.getSuffix(1)); - } - else - throw new NotContextException ("Object bound at "+firstComponent +" is not a Context"); + getContext(cname).unbind(cname.getSuffix(1)); } } - /*------------------------------------------------*/ /** * Not supported * * @param oldName a Name value * @param newName a Name value - * @exception NamingException if an error occurs + * @throws NamingException if an error occurs */ @Override public void rename(Name oldName, @@ -1089,33 +755,29 @@ public class NamingContext implements Context, Cloneable, Dumpable throw new OperationNotSupportedException(); } - - /*------------------------------------------------*/ /** * Not supported * * @param oldName a Name value * @param newName a Name value - * @exception NamingException if an error occurs - */ - @Override - public void rename(String oldName, - String newName) - throws NamingException - { - throw new OperationNotSupportedException(); - } + * @throws NamingException if an error occurs + */ + @Override + public void rename(String oldName, + String newName) + throws NamingException + { + throw new OperationNotSupportedException(); + } - - - /*------------------------------------------------*/ - /** Join two names together. These are treated as + /** + * Join two names together. These are treated as * CompoundNames. * * @param name a Name value * @param prefix a Name value * @return a Name value - * @exception NamingException if an error occurs + * @throws NamingException if an error occurs */ @Override public Name composeName(Name name, @@ -1123,56 +785,50 @@ public class NamingContext implements Context, Cloneable, Dumpable throws NamingException { if (name == null) - throw new NamingException ("Name cannot be null"); + throw new NamingException("Name cannot be null"); if (prefix == null) - throw new NamingException ("Prefix cannot be null"); + throw new NamingException("Prefix cannot be null"); Name compoundName = (CompoundName)prefix.clone(); - compoundName.addAll (name); + compoundName.addAll(name); return compoundName; } - - - /*------------------------------------------------*/ - /** Join two names together. These are treated as + /** + * Join two names together. These are treated as * CompoundNames. * * @param name a Name value * @param prefix a Name value * @return a Name value - * @exception NamingException if an error occurs + * @throws NamingException if an error occurs */ @Override - public String composeName (String name, - String prefix) + public String composeName(String name, + String prefix) throws NamingException { if (name == null) - throw new NamingException ("Name cannot be null"); + throw new NamingException("Name cannot be null"); if (prefix == null) - throw new NamingException ("Prefix cannot be null"); + throw new NamingException("Prefix cannot be null"); Name compoundName = _parser.parse(prefix); - compoundName.add (name); + compoundName.add(name); return compoundName.toString(); } - - /*------------------------------------------------*/ /** * Do nothing * - * @exception NamingException if an error occurs + * @throws NamingException if an error occurs */ @Override - public void close () + public void close() throws NamingException { } - - /*------------------------------------------------*/ /** * Return a NameParser for this Context. * @@ -1180,12 +836,11 @@ public class NamingContext implements Context, Cloneable, Dumpable * @return a NameParser value */ @Override - public NameParser getNameParser (Name name) + public NameParser getNameParser(Name name) { return _parser; } - /*------------------------------------------------*/ /** * Return a NameParser for this Context. * @@ -1193,13 +848,11 @@ public class NamingContext implements Context, Cloneable, Dumpable * @return a NameParser value */ @Override - public NameParser getNameParser (String name) + public NameParser getNameParser(String name) { return _parser; } - - /*------------------------------------------------*/ /** * Get the full name of this Context node * by visiting it's ancestors back to root. @@ -1208,10 +861,10 @@ public class NamingContext implements Context, Cloneable, Dumpable * the URL prefix will be missing * * @return the full name of this Context - * @exception NamingException if an error occurs + * @throws NamingException if an error occurs */ @Override - public String getNameInNamespace () + public String getNameInNamespace() throws NamingException { Name name = _parser.parse(""); @@ -1227,60 +880,66 @@ public class NamingContext implements Context, Cloneable, Dumpable return name.toString(); } - - /*------------------------------------------------*/ /** * Add an environment setting to this Context * * @param propName name of the property to add * @param propVal value of the property to add * @return propVal or previous value of the property - * @exception NamingException if an error occurs + * @throws NamingException if an error occurs */ @Override public Object addToEnvironment(String propName, Object propVal) throws NamingException { - if (isLocked() && !(propName.equals(UNLOCK_PROPERTY))) - throw new NamingException ("This context is immutable"); + switch (propName) + { + case LOCK_PROPERTY: + if (_lock == null) + _lock = propVal; + return null; - return _env.put (propName, propVal); + case UNLOCK_PROPERTY: + if (propVal != null && propVal.equals(_lock)) + _lock = null; + return null; + + default: + if (isLocked()) + throw new NamingException("This context is immutable"); + return _env.put(propName, propVal); + } } - - /*------------------------------------------------*/ /** * Remove a property from this Context's environment. * * @param propName name of property to remove * @return value of property or null if it didn't exist - * @exception NamingException if an error occurs + * @throws NamingException if an error occurs */ @Override public Object removeFromEnvironment(String propName) throws NamingException { if (isLocked()) - throw new NamingException ("This context is immutable"); + throw new NamingException("This context is immutable"); - return _env.remove (propName); + return _env.remove(propName); } - - /*------------------------------------------------*/ /** * Get the environment of this Context. * * @return a copy of the environment of this Context. */ @Override - public Hashtable getEnvironment () + public Hashtable getEnvironment() { - return (Hashtable)_env.clone(); + return _env; } - /*------------------------------------------------*/ /** * Add a name to object binding to this Context. * @@ -1288,27 +947,29 @@ public class NamingContext implements Context, Cloneable, Dumpable * @param obj an Object value * @throws NameAlreadyBoundException if name already bound */ - public void addBinding (Name name, Object obj) throws NameAlreadyBoundException + public void addBinding(Name name, Object obj) throws NameAlreadyBoundException { String key = name.toString(); - Binding binding=new Binding (key, obj); + Binding binding = new Binding(key, obj); Collection list = findListeners(); for (Listener listener : list) { - binding=listener.bind(this,binding); - if (binding==null) + binding = listener.bind(this, binding); + if (binding == null) break; } - if(__log.isDebugEnabled()) - __log.debug("Adding binding with key="+key+" obj="+obj+" for context="+_name+" as "+binding); + if (LOG.isDebugEnabled()) + LOG.debug("Adding binding with key=" + key + " obj=" + obj + " for context=" + _name + " as " + binding); - if (binding!=null) + if (binding != null) { - if (_bindings.containsKey(key)) { - if(_supportDeepBinding) { + if (_bindings.putIfAbsent(key, binding) != null) + { + if (isDeepBindingSupported()) + { // quietly return (no exception) // this is jndi spec breaking, but is added to support broken // jndi users like openejb. @@ -1316,51 +977,47 @@ public class NamingContext implements Context, Cloneable, Dumpable } throw new NameAlreadyBoundException(name.toString()); } - _bindings.put(key,binding); } } - /*------------------------------------------------*/ /** * Get a name to object binding from this Context * * @param name a Name value * @return a Binding value */ - public Binding getBinding (Name name) + public Binding getBinding(Name name) { - return (Binding) _bindings.get(name.toString()); + return _bindings.get(name.toString()); } - - /*------------------------------------------------*/ /** * Get a name to object binding from this Context * * @param name as a String * @return null or the Binding */ - public Binding getBinding (String name) + public Binding getBinding(String name) { - return (Binding) _bindings.get(name); + return _bindings.get(name); } - /*------------------------------------------------*/ - public void removeBinding (Name name) + public void removeBinding(Name name) { String key = name.toString(); - if (__log.isDebugEnabled()) - __log.debug("Removing binding with key="+key); + if (LOG.isDebugEnabled()) + LOG.debug("Removing binding with key=" + key); Binding binding = _bindings.remove(key); - if (binding!=null) + if (binding != null) { Collection list = findListeners(); for (Listener listener : list) - listener.unbind(this,binding); + { + listener.unbind(this, binding); + } } } - /*------------------------------------------------*/ /** * Remove leading or trailing empty components from * name. Eg "/comp/env/" -> "comp/env" @@ -1368,7 +1025,7 @@ public class NamingContext implements Context, Cloneable, Dumpable * @param name the name to normalize * @return normalized name */ - public Name toCanonicalName (Name name) + public Name toCanonicalName(Name name) { Name canonicalName = name; @@ -1379,95 +1036,61 @@ public class NamingContext implements Context, Cloneable, Dumpable if (canonicalName.get(0).equals("")) canonicalName = canonicalName.getSuffix(1); - if (canonicalName.get(canonicalName.size()-1).equals("")) - canonicalName = canonicalName.getPrefix(canonicalName.size()-1); + if (canonicalName.get(canonicalName.size() - 1).equals("")) + canonicalName = canonicalName.getPrefix(canonicalName.size() - 1); } } return canonicalName; } - /* ------------------------------------------------------------ */ public boolean isLocked() { - if ((_env.get(LOCK_PROPERTY) == null) && (_env.get(UNLOCK_PROPERTY) == null)) - return false; - - Object lockKey = _env.get(LOCK_PROPERTY); - Object unlockKey = _env.get(UNLOCK_PROPERTY); - - if ((lockKey != null) && (unlockKey != null) && (lockKey.equals(unlockKey))) - return false; - return true; + //TODO lock whole hierarchy? + return _lock != null; } - - /* ------------------------------------------------------------ */ @Override public String dump() { - StringBuilder buf = new StringBuilder(); - try - { - dump(buf,""); - } - catch(Exception e) - { - __log.warn(e); - } - return buf.toString(); + return Dumpable.dump(this); } - - /* ------------------------------------------------------------ */ @Override - public void dump(Appendable out,String indent) throws IOException + public void dump(Appendable out, String indent) throws IOException { - out.append(this.getClass().getSimpleName()).append("@").append(Long.toHexString(this.hashCode())).append("\n"); - int size=_bindings.size(); - int i=0; - for (Map.Entry entry : ((Map)_bindings).entrySet()) + Map bindings = new HashMap<>(); + for (Map.Entry binding : _bindings.entrySet()) { - boolean last=++i==size; - out.append(indent).append(" +- ").append(entry.getKey()).append(": "); + bindings.put(binding.getKey(), binding.getValue().getObject()); + } - Binding binding = entry.getValue(); - Object value = binding.getObject(); - - if ("comp".equals(entry.getKey()) && value instanceof Reference && "org.eclipse.jetty.jndi.ContextFactory".equals(((Reference)value).getFactoryClassName())) - { - ContextFactory.dump(out,indent+(last?" ":" | ")); - } - else if (value instanceof Dumpable) - { - ((Dumpable)value).dump(out,indent+(last?" ":" | ")); - } - else - { - out.append(value.getClass().getSimpleName()).append("="); - out.append(String.valueOf(value).replace('\n','|').replace('\r','|')); - out.append("\n"); - } + Dumpable.dumpObject(out, this); + Dumpable.dumpMapEntries(out, indent, bindings, _env.isEmpty()); + if (!_env.isEmpty()) + { + out.append(indent).append("+> environment\n"); + Dumpable.dumpMapEntries(out, indent + " ", _env, true); } } private Collection findListeners() { Collection list = new ArrayList(); - NamingContext ctx=this; - while (ctx!=null) + NamingContext ctx = this; + while (ctx != null) { - if (ctx._listeners!=null) + if (ctx._listeners != null) list.addAll(ctx._listeners); - ctx=(NamingContext)ctx.getParent(); + ctx = (NamingContext)ctx.getParent(); } return list; } public void addListener(Listener listener) { - if (_listeners==null) - _listeners=new ArrayList(); + if (_listeners == null) + _listeners = new ArrayList(); _listeners.add(listener); } @@ -1475,7 +1098,7 @@ public class NamingContext implements Context, Cloneable, Dumpable { return _listeners.remove(listener); } - + @Override public String toString() { diff --git a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/NamingUtil.java b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/NamingUtil.java index 22e25db4457..e4e1a003653 100644 --- a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/NamingUtil.java +++ b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/NamingUtil.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,7 +20,6 @@ package org.eclipse.jetty.jndi; import java.util.HashMap; import java.util.Map; - import javax.naming.Binding; import javax.naming.Context; import javax.naming.Name; @@ -29,17 +28,21 @@ import javax.naming.NameParser; import javax.naming.NamingEnumeration; import javax.naming.NamingException; +import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; - /** * Naming Utility Methods */ public class NamingUtil { - public final static Logger __log=org.eclipse.jetty.util.log.Log.getLogger("jndi"); + /** + * @deprecated no replacement, use a logger-per-class idiom instead. + */ + @Deprecated + public static final Logger __log = Log.getLogger("jndi"); + private static final Logger LOG = Log.getLogger(NamingUtil.class); - /* ------------------------------------------------------------ */ /** * Bind an object to a context ensuring all sub-contexts * are created if necessary @@ -48,9 +51,9 @@ public class NamingUtil * @param nameStr the name relative to context to bind * @param obj the object to be bound * @return the bound context - * @exception NamingException if an error occurs + * @throws NamingException if an error occurs */ - public static Context bind (Context ctx, String nameStr, Object obj) + public static Context bind(Context ctx, String nameStr, Object obj) throws NamingException { Name name = ctx.getNameParser("").parse(nameStr); @@ -62,30 +65,30 @@ public class NamingUtil Context subCtx = ctx; //last component of the name will be the name to bind - for (int i=0; i < name.size() - 1; i++) + for (int i = 0; i < name.size() - 1; i++) { try { - subCtx = (Context)subCtx.lookup (name.get(i)); - if(__log.isDebugEnabled()) - __log.debug("Subcontext "+name.get(i)+" already exists"); + subCtx = (Context)subCtx.lookup(name.get(i)); + if (LOG.isDebugEnabled()) + LOG.debug("Subcontext " + name.get(i) + " already exists"); } catch (NameNotFoundException e) { subCtx = subCtx.createSubcontext(name.get(i)); - if(__log.isDebugEnabled()) - __log.debug("Subcontext "+name.get(i)+" created"); + if (LOG.isDebugEnabled()) + LOG.debug("Subcontext " + name.get(i) + " created"); } } - subCtx.rebind (name.get(name.size() - 1), obj); - if(__log.isDebugEnabled()) - __log.debug("Bound object to "+name.get(name.size() - 1)); + subCtx.rebind(name.get(name.size() - 1), obj); + if (LOG.isDebugEnabled()) + LOG.debug("Bound object to " + name.get(name.size() - 1)); return subCtx; } - public static void unbind (Context ctx) - throws NamingException + public static void unbind(Context ctx) + throws NamingException { //unbind everything in the context and all of its subdirectories NamingEnumeration ne = ctx.listBindings(ctx.getNameInNamespace()); @@ -104,18 +107,19 @@ public class NamingUtil /** * Do a deep listing of the bindings for a context. + * * @param ctx the context containing the name for which to list the bindings * @param name the name in the context to list * @return map: key is fully qualified name, value is the bound object * @throws NamingException if unable to flatten bindings */ - public static Map flattenBindings (Context ctx, String name) - throws NamingException + public static Map flattenBindings(Context ctx, String name) + throws NamingException { HashMap map = new HashMap(); //the context representation of name arg - Context c = (Context)ctx.lookup (name); + Context c = (Context)ctx.lookup(name); NameParser parser = c.getNameParser(""); NamingEnumeration enm = ctx.listBindings(name); while (enm.hasMore()) @@ -124,18 +128,16 @@ public class NamingUtil if (b.getObject() instanceof Context) { - map.putAll(flattenBindings (c, b.getName())); + map.putAll(flattenBindings(c, b.getName())); } else { - Name compoundName = parser.parse (c.getNameInNamespace()); + Name compoundName = parser.parse(c.getNameInNamespace()); compoundName.add(b.getName()); - map.put (compoundName.toString(), b.getObject()); + map.put(compoundName.toString(), b.getObject()); } - } return map; } - } diff --git a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/factories/MailSessionReference.java b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/factories/MailSessionReference.java index 3cc355a254e..3b6f5a8aeb5 100644 --- a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/factories/MailSessionReference.java +++ b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/factories/MailSessionReference.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,13 +18,11 @@ package org.eclipse.jetty.jndi.factories; - import java.util.Enumeration; import java.util.Hashtable; import java.util.Iterator; import java.util.Map; import java.util.Properties; - import javax.mail.Authenticator; import javax.mail.PasswordAuthentication; import javax.mail.Session; @@ -47,12 +45,10 @@ import org.eclipse.jetty.util.security.Password; * reference is bound into JNDI and it is only when the reference is looked up that * this object factory will create an instance of javax.mail.Session using the * information captured in the Reference. - * */ public class MailSessionReference extends Reference implements ObjectFactory { - public static class PasswordAuthenticator extends Authenticator { PasswordAuthentication passwordAuthentication; @@ -66,7 +62,7 @@ public class MailSessionReference extends Reference implements ObjectFactory public PasswordAuthenticator(String user, String password) { - passwordAuthentication = new PasswordAuthentication (user, (password.startsWith(Password.__OBFUSCATE)?Password.deobfuscate(password):password)); + passwordAuthentication = new PasswordAuthentication(user, (password.startsWith(Password.__OBFUSCATE) ? Password.deobfuscate(password) : password)); } @Override @@ -75,16 +71,17 @@ public class MailSessionReference extends Reference implements ObjectFactory return passwordAuthentication; } - public void setUser (String user) + public void setUser(String user) { this.user = user; } - public String getUser () + + public String getUser() { return this.user; } - public String getPassword () + public String getPassword() { return this.password; } @@ -93,33 +90,32 @@ public class MailSessionReference extends Reference implements ObjectFactory { this.password = password; } - }; + } public MailSessionReference() { - super ("javax.mail.Session", MailSessionReference.class.getName(), null); + super("javax.mail.Session", MailSessionReference.class.getName(), null); } - /** * Create a javax.mail.Session instance based on the information passed in the Reference - * @see javax.naming.spi.ObjectFactory#getObjectInstance(java.lang.Object, javax.naming.Name, javax.naming.Context, java.util.Hashtable) + * * @param ref the Reference * @param arg1 not used * @param arg2 not used * @param arg3 not used * @return the object found * @throws Exception if unable to get object instance + * @see javax.naming.spi.ObjectFactory#getObjectInstance(java.lang.Object, javax.naming.Name, javax.naming.Context, java.util.Hashtable) */ @Override public Object getObjectInstance(Object ref, Name arg1, Context arg2, Hashtable arg3) throws Exception { if (ref == null) - return null; + return null; Reference reference = (Reference)ref; - Properties props = new Properties(); String user = null; String password = null; @@ -129,7 +125,7 @@ public class MailSessionReference extends Reference implements ObjectFactory { RefAddr refAddr = (RefAddr)refs.nextElement(); String name = refAddr.getType(); - String value = (String)refAddr.getContent(); + String value = (String)refAddr.getContent(); if (name.equalsIgnoreCase("user")) user = value; else if (name.equalsIgnoreCase("pwd")) @@ -144,26 +140,25 @@ public class MailSessionReference extends Reference implements ObjectFactory return Session.getInstance(props, new PasswordAuthenticator(user, password)); } - - public void setUser (String user) + public void setUser(String user) { - StringRefAddr addr = (StringRefAddr)get("user"); - if (addr != null) - { - throw new RuntimeException ("user already set on SessionReference, can't be changed"); - } - add(new StringRefAddr("user", user)); + StringRefAddr addr = (StringRefAddr)get("user"); + if (addr != null) + { + throw new RuntimeException("user already set on SessionReference, can't be changed"); + } + add(new StringRefAddr("user", user)); } - public void setPassword (String password) + public void setPassword(String password) { StringRefAddr addr = (StringRefAddr)get("pwd"); if (addr != null) - throw new RuntimeException ("password already set on SessionReference, can't be changed"); - add(new StringRefAddr ("pwd", password)); + throw new RuntimeException("password already set on SessionReference, can't be changed"); + add(new StringRefAddr("pwd", password)); } - public void setProperties (Properties properties) + public void setProperties(Properties properties) { Iterator entries = properties.entrySet().iterator(); while (entries.hasNext()) @@ -171,11 +166,8 @@ public class MailSessionReference extends Reference implements ObjectFactory Map.Entry e = (Map.Entry)entries.next(); StringRefAddr sref = (StringRefAddr)get((String)e.getKey()); if (sref != null) - throw new RuntimeException ("property "+e.getKey()+" already set on Session reference, can't be changed"); + throw new RuntimeException("property " + e.getKey() + " already set on Session reference, can't be changed"); add(new StringRefAddr((String)e.getKey(), (String)e.getValue())); } } - - - } diff --git a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/factories/package-info.java b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/factories/package-info.java index eb095894426..4549efa2878 100644 --- a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/factories/package-info.java +++ b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/factories/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/java/javaNameParser.java b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/java/javaNameParser.java index 317ca5d086a..2f071e3d1e6 100644 --- a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/java/javaNameParser.java +++ b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/java/javaNameParser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,16 +19,16 @@ package org.eclipse.jetty.jndi.java; import java.util.Properties; - import javax.naming.CompoundName; import javax.naming.Name; import javax.naming.NameParser; import javax.naming.NamingException; +// This is the required name for JNDI +// @checkstyle-disable-check : TypeNameCheck /** * javaNameParser - * */ public class javaNameParser implements NameParser { @@ -37,22 +37,22 @@ public class javaNameParser implements NameParser static { - syntax.put("jndi.syntax.direction", "left_to_right"); - syntax.put("jndi.syntax.separator", "/"); - syntax.put("jndi.syntax.ignorecase", "false"); + syntax.put("jndi.syntax.direction", "left_to_right"); + syntax.put("jndi.syntax.separator", "/"); + syntax.put("jndi.syntax.ignorecase", "false"); } - /** - * Parse a name into its components. - * @param name The non-null string name to parse. - * @return A non-null parsed form of the name using the naming convention - * of this parser. - * @exception NamingException If a naming exception was encountered. - */ - @Override - public Name parse(String name) throws NamingException - { - return new CompoundName(name, syntax); - } - + /** + * Parse a name into its components. + * + * @param name The non-null string name to parse. + * @return A non-null parsed form of the name using the naming convention + * of this parser. + * @throws NamingException If a naming exception was encountered. + */ + @Override + public Name parse(String name) throws NamingException + { + return new CompoundName(name, syntax); + } } diff --git a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/java/javaRootURLContext.java b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/java/javaRootURLContext.java index 58cb52a3957..a9b65d76b39 100644 --- a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/java/javaRootURLContext.java +++ b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/java/javaRootURLContext.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,9 +18,7 @@ package org.eclipse.jetty.jndi.java; - import java.util.Hashtable; - import javax.naming.Context; import javax.naming.Name; import javax.naming.NameParser; @@ -31,13 +29,13 @@ import javax.naming.StringRefAddr; import org.eclipse.jetty.jndi.ContextFactory; import org.eclipse.jetty.jndi.NamingContext; -import org.eclipse.jetty.jndi.NamingUtil; +import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; +// This is the required name for JNDI +// @checkstyle-disable-check : TypeNameCheck - - -/** +/** * javaRootURLContext *

        * This is the root of the java: url namespace @@ -46,7 +44,7 @@ import org.eclipse.jetty.util.log.Logger; */ public class javaRootURLContext implements Context { - private static Logger __log = NamingUtil.__log; + private static final Logger LOG = Log.getLogger(javaRootURLContext.class); public static final String URL_PREFIX = "java:"; @@ -56,33 +54,29 @@ public class javaRootURLContext implements Context protected static NameParser __javaNameParser; - static { try { __javaNameParser = new javaNameParser(); - __nameRoot = new NamingContext(null,null,null,__javaNameParser); + __nameRoot = new NamingContext(null, null, null, __javaNameParser); StringRefAddr parserAddr = new StringRefAddr("parser", __javaNameParser.getClass().getName()); - Reference ref = new Reference ("javax.naming.Context", - parserAddr, - ContextFactory.class.getName(), - (String)null); + Reference ref = new Reference("javax.naming.Context", + parserAddr, + ContextFactory.class.getName(), + null); // bind special object factory at comp - __nameRoot.bind ("comp", ref); + __nameRoot.bind("comp", ref); } catch (Exception e) { - __log.warn(e); + LOG.warn(e); } } - - - /*------------------------------------------------*/ /** * Creates a new javaRootURLContext instance. * @@ -100,7 +94,6 @@ public class javaRootURLContext implements Context return getRoot().lookup(stripProtocol(name)); } - @Override public Object lookup(String name) throws NamingException @@ -123,93 +116,89 @@ public class javaRootURLContext implements Context } @Override - public void unbind (String name) + public void unbind(String name) throws NamingException { getRoot().unbind(stripProtocol(name)); } @Override - public void unbind (Name name) + public void unbind(Name name) throws NamingException { getRoot().unbind(stripProtocol(name)); } @Override - public void rename (String oldStr, String newStr) + public void rename(String oldStr, String newStr) throws NamingException { - getRoot().rename (stripProtocol(oldStr), stripProtocol(newStr)); + getRoot().rename(stripProtocol(oldStr), stripProtocol(newStr)); } @Override - public void rename (Name oldName, Name newName) + public void rename(Name oldName, Name newName) throws NamingException { - getRoot().rename (stripProtocol(oldName), stripProtocol(newName)); + getRoot().rename(stripProtocol(oldName), stripProtocol(newName)); } @Override - public void rebind (Name name, Object obj) + public void rebind(Name name, Object obj) throws NamingException { getRoot().rebind(stripProtocol(name), obj); } @Override - public void rebind (String name, Object obj) + public void rebind(String name, Object obj) throws NamingException { getRoot().rebind(stripProtocol(name), obj); } - @Override - public Object lookupLink (Name name) + public Object lookupLink(Name name) throws NamingException { return getRoot().lookupLink(stripProtocol(name)); } @Override - public Object lookupLink (String name) + public Object lookupLink(String name) throws NamingException { return getRoot().lookupLink(stripProtocol(name)); } - @Override - public Context createSubcontext (Name name) + public Context createSubcontext(Name name) throws NamingException { return getRoot().createSubcontext(stripProtocol(name)); } @Override - public Context createSubcontext (String name) + public Context createSubcontext(String name) throws NamingException { return getRoot().createSubcontext(stripProtocol(name)); } - @Override - public void destroySubcontext (Name name) + public void destroySubcontext(Name name) throws NamingException { getRoot().destroySubcontext(stripProtocol(name)); } @Override - public void destroySubcontext (String name) + public void destroySubcontext(String name) throws NamingException { getRoot().destroySubcontext(stripProtocol(name)); } - @Override public NamingEnumeration list(Name name) throws NamingException @@ -217,7 +206,6 @@ public class javaRootURLContext implements Context return getRoot().list(stripProtocol(name)); } - @Override public NamingEnumeration list(String name) throws NamingException @@ -239,115 +227,110 @@ public class javaRootURLContext implements Context return getRoot().listBindings(stripProtocol(name)); } - @Override - public Name composeName (Name name, - Name prefix) + public Name composeName(Name name, + Name prefix) throws NamingException { return getRoot().composeName(name, prefix); } @Override - public String composeName (String name, - String prefix) + public String composeName(String name, + String prefix) throws NamingException { return getRoot().composeName(name, prefix); } - @Override - public void close () + public void close() throws NamingException { } @Override - public String getNameInNamespace () + public String getNameInNamespace() throws NamingException { return URL_PREFIX; } @Override - public NameParser getNameParser (Name name) + public NameParser getNameParser(Name name) throws NamingException { return __javaNameParser; } @Override - public NameParser getNameParser (String name) + public NameParser getNameParser(String name) throws NamingException { return __javaNameParser; } - @Override public Object addToEnvironment(String propName, Object propVal) throws NamingException { - return _env.put (propName,propVal); + return _env.put(propName, propVal); } @Override public Object removeFromEnvironment(String propName) throws NamingException { - return _env.remove (propName); + return _env.remove(propName); } @Override - public Hashtable getEnvironment () + public Hashtable getEnvironment() { return _env; } - public static NamingContext getRoot () + public static NamingContext getRoot() { return __nameRoot; } - - protected Name stripProtocol (Name name) + protected Name stripProtocol(Name name) throws NamingException { if ((name != null) && (name.size() > 0)) { String head = name.get(0); - if(__log.isDebugEnabled())__log.debug("Head element of name is: "+head); + if (LOG.isDebugEnabled()) + LOG.debug("Head element of name is: " + head); if (head.startsWith(URL_PREFIX)) { - head = head.substring (URL_PREFIX.length()); + head = head.substring(URL_PREFIX.length()); name.remove(0); if (head.length() > 0) name.add(0, head); - if(__log.isDebugEnabled())__log.debug("name modified to "+name.toString()); + if (LOG.isDebugEnabled()) + LOG.debug("name modified to " + name.toString()); } } return name; } - - - protected String stripProtocol (String name) + protected String stripProtocol(String name) { String newName = name; if ((name != null) && (!name.equals(""))) { if (name.startsWith(URL_PREFIX)) - newName = name.substring(URL_PREFIX.length()); + newName = name.substring(URL_PREFIX.length()); } return newName; } - } diff --git a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/java/javaURLContextFactory.java b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/java/javaURLContextFactory.java index d17a2a12507..69687eefc86 100644 --- a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/java/javaURLContextFactory.java +++ b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/java/javaURLContextFactory.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,7 +19,6 @@ package org.eclipse.jetty.jndi.java; import java.util.Hashtable; - import javax.naming.Context; import javax.naming.Name; import javax.naming.NamingException; @@ -28,8 +27,10 @@ import javax.naming.spi.ObjectFactory; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; +// This is the required name for JNDI +// @checkstyle-disable-check : TypeNameCheck -/** +/** * javaURLContextFactory *

        * This is the URL context factory for the java: URL. @@ -46,7 +47,7 @@ public class javaURLContextFactory implements ObjectFactory * @param ctx a Context value * @param env a Hashtable value * @return a new context or the resolved object for the url - * @exception Exception if an error occurs + * @throws Exception if an error occurs */ @Override public Object getObjectInstance(Object url, Name name, Context ctx, Hashtable env) @@ -55,31 +56,34 @@ public class javaURLContextFactory implements ObjectFactory // null object means return a root context for doing resolutions if (url == null) { - if(LOG.isDebugEnabled())LOG.debug(">>> new root context requested "); + if (LOG.isDebugEnabled()) + LOG.debug(">>> new root context requested "); return new javaRootURLContext(env); } // return the resolution of the url if (url instanceof String) { - if(LOG.isDebugEnabled())LOG.debug(">>> resolution of url "+url+" requested"); - Context rootctx = new javaRootURLContext (env); - return rootctx.lookup ((String)url); + if (LOG.isDebugEnabled()) + LOG.debug(">>> resolution of url " + url + " requested"); + Context rootctx = new javaRootURLContext(env); + return rootctx.lookup((String)url); } // return the resolution of at least one of the urls if (url instanceof String[]) { - if(LOG.isDebugEnabled())LOG.debug(">>> resolution of array of urls requested"); + if (LOG.isDebugEnabled()) + LOG.debug(">>> resolution of array of urls requested"); String[] urls = (String[])url; - Context rootctx = new javaRootURLContext (env); + Context rootctx = new javaRootURLContext(env); Object object = null; NamingException e = null; - for (int i=0;(i< urls.length) && (object == null); i++) + for (int i = 0; (i < urls.length) && (object == null); i++) { try { - object = rootctx.lookup (urls[i]); + object = rootctx.lookup(urls[i]); } catch (NamingException x) { @@ -93,7 +97,8 @@ public class javaURLContextFactory implements ObjectFactory return object; } - if(LOG.isDebugEnabled())LOG.debug(">>> No idea what to do, so return a new root context anyway"); - return new javaRootURLContext (env); + if (LOG.isDebugEnabled()) + LOG.debug(">>> No idea what to do, so return a new root context anyway"); + return new javaRootURLContext(env); } -}; +} diff --git a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/java/package-info.java b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/java/package-info.java index 5706fb6fda2..189f9393067 100644 --- a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/java/package-info.java +++ b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/java/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/local/localContextRoot.java b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/local/localContextRoot.java index 4881a9cbea7..f560d4c1f57 100644 --- a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/local/localContextRoot.java +++ b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/local/localContextRoot.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,11 +18,8 @@ package org.eclipse.jetty.jndi.local; -import java.util.Collections; import java.util.Hashtable; -import java.util.List; import java.util.Properties; - import javax.naming.Binding; import javax.naming.CompoundName; import javax.naming.Context; @@ -40,39 +37,32 @@ import javax.naming.Reference; import javax.naming.Referenceable; import javax.naming.spi.NamingManager; -import org.eclipse.jetty.jndi.BindingEnumeration; -import org.eclipse.jetty.jndi.NameEnumeration; import org.eclipse.jetty.jndi.NamingContext; -import org.eclipse.jetty.jndi.NamingUtil; +import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; +// This is the required name for JNDI +// @checkstyle-disable-check : TypeNameCheck + /** - * * localContext * * Implementation of the delegate for InitialContext for the local namespace. - * - * - * @version $Revision: 4780 $ $Date: 2009-03-17 16:36:08 +0100 (Tue, 17 Mar 2009) $ - * */ public class localContextRoot implements Context { - private final static Logger __log=NamingUtil.__log; - protected final static NamingContext __root = new NamingRoot(); - private final Hashtable _env; - + private static final Logger LOG = Log.getLogger(localContextRoot.class); + protected static final NamingContext __root = new NamingRoot(); + private final Hashtable _env; static class NamingRoot extends NamingContext { public NamingRoot() { - super (null,null,null,new LocalNameParser()); + super(null, null, null, new LocalNameParser()); } } - - static class LocalNameParser implements NameParser { Properties syntax = new Properties(); @@ -91,7 +81,6 @@ public class localContextRoot implements Context } } - /* * Root has to use the localContextRoot's env for all operations. * So, if createSubcontext in the root, use the env of the localContextRoot. @@ -99,11 +88,6 @@ public class localContextRoot implements Context * */ - - - - - public static NamingContext getRoot() { return __root; @@ -115,19 +99,14 @@ public class localContextRoot implements Context } /** - * - * * @see javax.naming.Context#close() */ @Override public void close() throws NamingException { - } /** - * - * * @see javax.naming.Context#getNameInNamespace() */ @Override @@ -136,41 +115,25 @@ public class localContextRoot implements Context return ""; } - /** - * - * * @see javax.naming.Context#destroySubcontext(javax.naming.Name) */ @Override public void destroySubcontext(Name name) throws NamingException { - synchronized (__root) - { - __root.destroySubcontext(getSuffix(name)); - } + __root.destroySubcontext(getSuffix(name)); } - /** - * - * * @see javax.naming.Context#destroySubcontext(java.lang.String) */ @Override public void destroySubcontext(String name) throws NamingException { - synchronized (__root) - { - - destroySubcontext(__root.getNameParser("").parse(getSuffix(name))); - } + destroySubcontext(__root.getNameParser("").parse(getSuffix(name))); } - /** - * - * * @see javax.naming.Context#getEnvironment() */ @Override @@ -179,95 +142,84 @@ public class localContextRoot implements Context return _env; } + private Object dereference(Object ctx, String firstComponent) throws NamingException + { + if (ctx instanceof Reference) + { + //deference the object + try + { + return NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), __root, _env); + } + catch (NamingException e) + { + throw e; + } + catch (Exception e) + { + LOG.warn(e); + throw new NamingException(e.getMessage()); + } + } + return ctx; + } + private Context getContext(Name cname) throws NamingException + { + String firstComponent = cname.get(0); + + if (firstComponent.equals("")) + return this; + + Binding binding = __root.getBinding(firstComponent); + if (binding == null) + { + NameNotFoundException nnfe = new NameNotFoundException(firstComponent + " is not bound"); + nnfe.setRemainingName(cname); + throw nnfe; + } + Object ctx = dereference(binding.getObject(), firstComponent); + + if (!(ctx instanceof Context)) + throw new NotContextException(firstComponent + " not a context in " + this.getNameInNamespace()); + + return (Context)ctx; + } /** - * - * * @see javax.naming.Context#unbind(javax.naming.Name) */ @Override public void unbind(Name name) throws NamingException { - synchronized (__root) + //__root.unbind(getSuffix(name)); + + if (name.size() == 0) + return; + + if (__root.isLocked()) + throw new NamingException("This context is immutable"); + + Name cname = __root.toCanonicalName(name); + + if (cname == null) + throw new NamingException("Name is null"); + + if (cname.size() == 0) + throw new NamingException("Name is empty"); + + //if no subcontexts, just unbind it + if (cname.size() == 1) { - //__root.unbind(getSuffix(name)); - - if (name.size() == 0) - return; - - - if (__root.isLocked()) - throw new NamingException ("This context is immutable"); - - Name cname = __root.toCanonicalName(name); - - if (cname == null) - throw new NamingException ("Name is null"); - - if (cname.size() == 0) - throw new NamingException ("Name is empty"); - - - //if no subcontexts, just unbind it - if (cname.size() == 1) - { - __root.removeBinding (cname); - } - else - { - //walk down the subcontext hierarchy - if(__log.isDebugEnabled())__log.debug("Checking for existing binding for name="+cname+" for first element of name="+cname.get(0)); - - String firstComponent = cname.get(0); - Object ctx = null; - - - if (firstComponent.equals("")) - ctx = this; - else - { - Binding binding = __root.getBinding (name.get(0)); - if (binding == null) - throw new NameNotFoundException (name.get(0)+ " is not bound"); - - ctx = binding.getObject(); - - if (ctx instanceof Reference) - { - //deference the object - try - { - ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), __root, _env); - } - catch (NamingException e) - { - throw e; - } - catch (Exception e) - { - __log.warn("",e); - throw new NamingException (e.getMessage()); - } - } - } - - if (ctx instanceof Context) - { - ((Context)ctx).unbind (cname.getSuffix(1)); - } - else - throw new NotContextException ("Object bound at "+firstComponent +" is not a Context"); - } - - - + __root.removeBinding(cname); + } + else + { + getContext(cname).unbind(cname.getSuffix(1)); } } /** - * - * * @see javax.naming.Context#unbind(java.lang.String) */ @Override @@ -276,129 +228,71 @@ public class localContextRoot implements Context unbind(__root.getNameParser("").parse(getSuffix(name))); } - - /** - * - * * @see javax.naming.Context#lookupLink(java.lang.String) */ @Override public Object lookupLink(String name) throws NamingException { - synchronized (__root) - { - return lookupLink(__root.getNameParser("").parse(getSuffix(name))); - } + return lookupLink(__root.getNameParser("").parse(getSuffix(name))); } /** - * - * * @see javax.naming.Context#lookupLink(javax.naming.Name) */ @Override public Object lookupLink(Name name) throws NamingException { - synchronized (__root) + Name cname = __root.toCanonicalName(name); + + if (cname == null || cname.isEmpty()) { - //return __root.lookupLink(getSuffix(name)); + //If no name create copy of this context with same bindings, but with copy of the environment so it can be modified + return __root.shallowCopy(_env); + } + if (cname.size() == 0) + throw new NamingException("Name is empty"); - Name cname = __root.toCanonicalName(name); + if (cname.size() == 1) + { + Binding binding = __root.getBinding(cname); + if (binding == null) + throw new NameNotFoundException(); - if (cname == null) + Object o = binding.getObject(); + + //handle links by looking up the link + if (o instanceof Reference) { - //If no name create copy of this context with same bindings, but with copy of the environment so it can be modified - NamingContext ctx = new NamingContext (_env, null, null, __root.getNameParser("")); - ctx.setBindings(__root.getBindings()); - return ctx; - } - - if (cname.size() == 0) - throw new NamingException ("Name is empty"); - - if (cname.size() == 1) - { - Binding binding = __root.getBinding (cname); - if (binding == null) - throw new NameNotFoundException(); - - Object o = binding.getObject(); - - //handle links by looking up the link - if (o instanceof Reference) + //deference the object + try { - //deference the object - try - { - return NamingManager.getObjectInstance(o, cname.getPrefix(1), __root, _env); - } - catch (NamingException e) - { - throw e; - } - catch (Exception e) - { - __log.warn("",e); - throw new NamingException (e.getMessage()); - } + return NamingManager.getObjectInstance(o, cname.getPrefix(1), __root, _env); } - else + catch (NamingException e) { - //object is either a LinkRef which we don't dereference - //or a plain object in which case spec says we return it - return o; + throw e; + } + catch (Exception e) + { + LOG.warn("", e); + throw new NamingException(e.getMessage()); } } - - - //it is a multipart name, recurse to the first subcontext - String firstComponent = cname.get(0); - Object ctx = null; - - if (firstComponent.equals("")) - ctx = this; else { - Binding binding = __root.getBinding (firstComponent); - if (binding == null) - throw new NameNotFoundException (); - - ctx = binding.getObject(); - - if (ctx instanceof Reference) - { - //deference the object - try - { - ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), __root, _env); - } - catch (NamingException e) - { - throw e; - } - catch (Exception e) - { - __log.warn("",e); - throw new NamingException (e.getMessage()); - } - } + //object is either a LinkRef which we don't dereference + //or a plain object in which case spec says we return it + return o; } - - if (!(ctx instanceof Context)) - throw new NotContextException(); - - return ((Context)ctx).lookup (cname.getSuffix(1)); - - } + + //it is a multipart name, recurse to the first subcontext + return getContext(cname).lookup(cname.getSuffix(1)); } - /** - * - * * @see javax.naming.Context#removeFromEnvironment(java.lang.String) */ @Override @@ -407,501 +301,263 @@ public class localContextRoot implements Context return _env.remove(propName); } - /** - * - * * @see javax.naming.Context#lookup(javax.naming.Name) */ @Override public Object lookup(Name name) throws NamingException { - synchronized (__root) + if (LOG.isDebugEnabled()) + LOG.debug("Looking up name=\"" + name + "\""); + Name cname = __root.toCanonicalName(name); + + if ((cname == null) || cname.isEmpty()) { - //return __root.lookup(getSuffix(name)); - - if(__log.isDebugEnabled())__log.debug("Looking up name=\""+name+"\""); - Name cname = __root.toCanonicalName(name); - - if ((cname == null) || (cname.size() == 0)) - { - __log.debug("Null or empty name, returning copy of this context"); - NamingContext ctx = new NamingContext (_env, null, null, __root.getNameParser("")); - ctx.setBindings(__root.getBindings()); - return ctx; - } - - - - if (cname.size() == 1) - { - Binding binding = __root.getBinding (cname); - if (binding == null) - { - NameNotFoundException nnfe = new NameNotFoundException(); - nnfe.setRemainingName(cname); - throw nnfe; - } - - - Object o = binding.getObject(); - - //handle links by looking up the link - if (o instanceof LinkRef) - { - //if link name starts with ./ it is relative to current context - String linkName = ((LinkRef)o).getLinkName(); - if (linkName.startsWith("./")) - return lookup (linkName.substring(2)); - else - { - //link name is absolute - InitialContext ictx = new InitialContext(); - return ictx.lookup (linkName); - } - } - else if (o instanceof Reference) - { - //deference the object - try - { - return NamingManager.getObjectInstance(o, cname, __root, _env); - } - catch (NamingException e) - { - throw e; - } - catch (final Exception e) - { - throw new NamingException (e.getMessage()) - { - { initCause(e);} - }; - } - } - else - return o; - } - - //it is a multipart name, get the first subcontext - - String firstComponent = cname.get(0); - Object ctx = null; - - if (firstComponent.equals("")) - ctx = this; - else - { - - Binding binding = __root.getBinding (firstComponent); - if (binding == null) - { - NameNotFoundException nnfe = new NameNotFoundException(); - nnfe.setRemainingName(cname); - throw nnfe; - } - - //as we have bound a reference to an object factory - //for the component specific contexts - //at "comp" we need to resolve the reference - ctx = binding.getObject(); - - if (ctx instanceof Reference) - { - //deference the object - try - { - ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), __root, _env); - } - catch (NamingException e) - { - throw e; - } - catch (Exception e) - { - __log.warn("",e); - throw new NamingException (e.getMessage()); - } - } - } - if (!(ctx instanceof Context)) - throw new NotContextException(); - - return ((Context)ctx).lookup (cname.getSuffix(1)); - + return __root.shallowCopy(_env); } + + if (cname.size() == 1) + { + Binding binding = __root.getBinding(cname); + if (binding == null) + { + NameNotFoundException nnfe = new NameNotFoundException(); + nnfe.setRemainingName(cname); + throw nnfe; + } + + Object o = binding.getObject(); + + //handle links by looking up the link + if (o instanceof LinkRef) + { + //if link name starts with ./ it is relative to current context + String linkName = ((LinkRef)o).getLinkName(); + if (linkName.startsWith("./")) + return lookup(linkName.substring(2)); + else + { + //link name is absolute + InitialContext ictx = new InitialContext(); + return ictx.lookup(linkName); + } + } + else if (o instanceof Reference) + { + // TODO use deference + try + { + return NamingManager.getObjectInstance(o, cname, __root, _env); + } + catch (NamingException e) + { + throw e; + } + catch (final Exception e) + { + throw new NamingException(e.getMessage()) + { + { + initCause(e); + } + }; + } + } + else + return o; + } + + return getContext(cname).lookup(cname.getSuffix(1)); } - /** - * - * * @see javax.naming.Context#lookup(java.lang.String) */ @Override public Object lookup(String name) throws NamingException { - synchronized (__root) - { - return lookup(__root.getNameParser("").parse(getSuffix(name))); - } + return lookup(__root.getNameParser("").parse(getSuffix(name))); } - /** - * - * * @see javax.naming.Context#bind(java.lang.String, java.lang.Object) */ @Override public void bind(String name, Object obj) throws NamingException { - synchronized (__root) - { - bind(__root.getNameParser("").parse(getSuffix(name)), obj); - - } + bind(__root.getNameParser("").parse(getSuffix(name)), obj); } - /** - * - * * @see javax.naming.Context#bind(javax.naming.Name, java.lang.Object) */ @Override public void bind(Name name, Object obj) throws NamingException { - synchronized (__root) + if (__root.isLocked()) + throw new NamingException("This context is immutable"); + + Name cname = __root.toCanonicalName(name); + + if (cname == null) + throw new NamingException("Name is null"); + + if (cname.size() == 0) + throw new NamingException("Name is empty"); + + //if no subcontexts, just bind it + if (cname.size() == 1) { - // __root.bind(getSuffix(name), obj); - - - if (__root.isLocked()) - throw new NamingException ("This context is immutable"); - - Name cname = __root.toCanonicalName(name); - - if (cname == null) - throw new NamingException ("Name is null"); - - if (cname.size() == 0) - throw new NamingException ("Name is empty"); - - - //if no subcontexts, just bind it - if (cname.size() == 1) + //get the object to be bound + Object objToBind = NamingManager.getStateToBind(obj, name, this, _env); + // Check for Referenceable + if (objToBind instanceof Referenceable) { - //get the object to be bound - Object objToBind = NamingManager.getStateToBind(obj, name,this, _env); - // Check for Referenceable - if (objToBind instanceof Referenceable) - { - objToBind = ((Referenceable)objToBind).getReference(); - } - - //anything else we should be able to bind directly - __root.addBinding (cname, objToBind); + objToBind = ((Referenceable)objToBind).getReference(); } - else - { - if(__log.isDebugEnabled())__log.debug("Checking for existing binding for name="+cname+" for first element of name="+cname.get(0)); - //walk down the subcontext hierarchy - //need to ignore trailing empty "" name components + //anything else we should be able to bind directly + __root.addBinding(cname, objToBind); + } + else + { + if (LOG.isDebugEnabled()) + LOG.debug("Checking for existing binding for name=" + cname + " for first element of name=" + cname.get(0)); - String firstComponent = cname.get(0); - Object ctx = null; - - if (firstComponent.equals("")) - ctx = this; - else - { - - Binding binding = __root.getBinding (firstComponent); - if (binding == null) - throw new NameNotFoundException (firstComponent+ " is not bound"); - - ctx = binding.getObject(); - - if (ctx instanceof Reference) - { - //deference the object - try - { - ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), this, _env); - } - catch (NamingException e) - { - throw e; - } - catch (Exception e) - { - __log.warn("",e); - throw new NamingException (e.getMessage()); - } - } - } - - - if (ctx instanceof Context) - { - ((Context)ctx).bind (cname.getSuffix(1), obj); - } - else - throw new NotContextException ("Object bound at "+firstComponent +" is not a Context"); - } + getContext(cname).bind(cname.getSuffix(1), obj); } } /** - * - * * @see javax.naming.Context#rebind(javax.naming.Name, java.lang.Object) */ @Override public void rebind(Name name, Object obj) throws NamingException { - synchronized (__root) + if (__root.isLocked()) + throw new NamingException("This context is immutable"); + + Name cname = __root.toCanonicalName(name); + + if (cname == null) + throw new NamingException("Name is null"); + + if (cname.size() == 0) + throw new NamingException("Name is empty"); + + //if no subcontexts, just bind it + if (cname.size() == 1) { - //__root.rebind(getSuffix(name), obj); + //check if it is a Referenceable + Object objToBind = NamingManager.getStateToBind(obj, name, __root, _env); - - if (__root.isLocked()) - throw new NamingException ("This context is immutable"); - - Name cname = __root.toCanonicalName(name); - - if (cname == null) - throw new NamingException ("Name is null"); - - if (cname.size() == 0) - throw new NamingException ("Name is empty"); - - - //if no subcontexts, just bind it - if (cname.size() == 1) + if (objToBind instanceof Referenceable) { - //check if it is a Referenceable - Object objToBind = NamingManager.getStateToBind(obj, name, __root, _env); - - if (objToBind instanceof Referenceable) - { - objToBind = ((Referenceable)objToBind).getReference(); - } - __root.removeBinding(cname); - __root.addBinding (cname, objToBind); + objToBind = ((Referenceable)objToBind).getReference(); } - else - { - //walk down the subcontext hierarchy - if(__log.isDebugEnabled())__log.debug("Checking for existing binding for name="+cname+" for first element of name="+cname.get(0)); + __root.removeBinding(cname); + __root.addBinding(cname, objToBind); + } + else + { + //walk down the subcontext hierarchy + if (LOG.isDebugEnabled()) + LOG.debug("Checking for existing binding for name=" + cname + " for first element of name=" + cname.get(0)); - String firstComponent = cname.get(0); - Object ctx = null; - - - if (firstComponent.equals("")) - ctx = this; - else - { - Binding binding = __root.getBinding (name.get(0)); - if (binding == null) - throw new NameNotFoundException (name.get(0)+ " is not bound"); - - ctx = binding.getObject(); - - - if (ctx instanceof Reference) - { - //deference the object - try - { - ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), __root, _env); - } - catch (NamingException e) - { - throw e; - } - catch (Exception e) - { - __log.warn("",e); - throw new NamingException (e.getMessage()); - } - } - } - - if (ctx instanceof Context) - { - ((Context)ctx).rebind (cname.getSuffix(1), obj); - } - else - throw new NotContextException ("Object bound at "+firstComponent +" is not a Context"); - } + getContext(cname).rebind(cname.getSuffix(1), obj); } } /** - * - * * @see javax.naming.Context#rebind(java.lang.String, java.lang.Object) */ @Override public void rebind(String name, Object obj) throws NamingException { - synchronized (__root) - { - rebind(__root.getNameParser("").parse(getSuffix(name)), obj); - } + rebind(__root.getNameParser("").parse(getSuffix(name)), obj); } + /** - * - * * @see javax.naming.Context#rename(javax.naming.Name, javax.naming.Name) */ @Override public void rename(Name oldName, Name newName) throws NamingException { - synchronized (__root) - { - throw new OperationNotSupportedException(); - } + throw new OperationNotSupportedException(); } /** - * - * * @see javax.naming.Context#rename(java.lang.String, java.lang.String) */ @Override public void rename(String oldName, String newName) throws NamingException { - synchronized (__root) - { - throw new OperationNotSupportedException(); - } + throw new OperationNotSupportedException(); } /** - * - * * @see javax.naming.Context#createSubcontext(java.lang.String) */ @Override public Context createSubcontext(String name) throws NamingException { - synchronized (__root) - { - //if the subcontext comes directly off the root, use the env of the InitialContext - //as the root itself has no environment. Otherwise, it inherits the env of the parent - //Context further down the tree. - //NamingContext ctx = (NamingContext)__root.createSubcontext(name); - //if (ctx.getParent() == __root) - // ctx.setEnv(_env); - //return ctx; + //if the subcontext comes directly off the root, use the env of the InitialContext + //as the root itself has no environment. Otherwise, it inherits the env of the parent + //Context further down the tree. + //NamingContext ctx = (NamingContext)__root.createSubcontext(name); + //if (ctx.getParent() == __root) + // ctx.setEnv(_env); + //return ctx; - return createSubcontext(__root.getNameParser("").parse(name)); - } + return createSubcontext(__root.getNameParser("").parse(name)); } /** - * - * * @see javax.naming.Context#createSubcontext(javax.naming.Name) */ @Override public Context createSubcontext(Name name) throws NamingException { - synchronized (__root) + //if the subcontext comes directly off the root, use the env of the InitialContext + //as the root itself has no environment. Otherwise, it inherits the env of the parent + //Context further down the tree. + //NamingContext ctx = (NamingContext)__root.createSubcontext(getSuffix(name)); + //if (ctx.getParent() == __root) + // ctx.setEnv(_env); + //return ctx; + + if (__root.isLocked()) { - //if the subcontext comes directly off the root, use the env of the InitialContext - //as the root itself has no environment. Otherwise, it inherits the env of the parent - //Context further down the tree. - //NamingContext ctx = (NamingContext)__root.createSubcontext(getSuffix(name)); - //if (ctx.getParent() == __root) - // ctx.setEnv(_env); - //return ctx; - - - - - if (__root.isLocked()) - { - NamingException ne = new NamingException ("This context is immutable"); - ne.setRemainingName(name); - throw ne; - } - - Name cname = __root.toCanonicalName (name); - - if (cname == null) - throw new NamingException ("Name is null"); - if (cname.size() == 0) - throw new NamingException ("Name is empty"); - - if (cname.size() == 1) - { - //not permitted to bind if something already bound at that name - Binding binding = __root.getBinding (cname); - if (binding != null) - throw new NameAlreadyBoundException (cname.toString()); - - //make a new naming context with the root as the parent - Context ctx = new NamingContext ((Hashtable)_env.clone(), cname.get(0), __root, __root.getNameParser("")); - __root.addBinding (cname, ctx); - return ctx; - } - - - //If the name has multiple subcontexts, walk the hierarchy by - //fetching the first one. All intermediate subcontexts in the - //name must already exist. - String firstComponent = cname.get(0); - Object ctx = null; - - if (firstComponent.equals("")) - ctx = this; - else - { - Binding binding = __root.getBinding (firstComponent); - if (binding == null) - throw new NameNotFoundException (firstComponent + " is not bound"); - - ctx = binding.getObject(); - - if (ctx instanceof Reference) - { - //deference the object - if(__log.isDebugEnabled())__log.debug("Object bound at "+firstComponent +" is a Reference"); - try - { - ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), __root, _env); - } - catch (NamingException e) - { - throw e; - } - catch (Exception e) - { - __log.warn("",e); - throw new NamingException (e.getMessage()); - } - } - } - - if (ctx instanceof Context) - { - return ((Context)ctx).createSubcontext (cname.getSuffix(1)); - } - else - throw new NotContextException (firstComponent +" is not a Context"); + NamingException ne = new NamingException("This context is immutable"); + ne.setRemainingName(name); + throw ne; } + + Name cname = __root.toCanonicalName(name); + + if (cname == null) + throw new NamingException("Name is null"); + if (cname.size() == 0) + throw new NamingException("Name is empty"); + + if (cname.size() == 1) + { + //not permitted to bind if something already bound at that name + Binding binding = __root.getBinding(cname); + if (binding != null) + throw new NameAlreadyBoundException(cname.toString()); + + //make a new naming context with the root as the parent + Context ctx = new NamingContext(_env, cname.get(0), __root, __root.getNameParser("")); + __root.addBinding(cname, ctx); + return ctx; + } + + //If the name has multiple subcontexts, + return getContext(cname).createSubcontext(cname.getSuffix(1)); } - /** - * - * * @see javax.naming.Context#getNameParser(java.lang.String) */ @Override @@ -911,8 +567,6 @@ public class localContextRoot implements Context } /** - * - * * @see javax.naming.Context#getNameParser(javax.naming.Name) */ @Override @@ -922,208 +576,65 @@ public class localContextRoot implements Context } /** - * - * * @see javax.naming.Context#list(java.lang.String) */ @Override public NamingEnumeration list(String name) throws NamingException { - synchronized (__root) - { - return list(__root.getNameParser("").parse(getSuffix(name))); - } + return __root.list(name); } - /** - * - * * @see javax.naming.Context#list(javax.naming.Name) */ @Override public NamingEnumeration list(Name name) throws NamingException { - synchronized (__root) - { - //return __root.list(getSuffix(name)); - - - Name cname = __root.toCanonicalName(name); - - if (cname == null) - { - List empty = Collections.emptyList(); - return new NameEnumeration(empty.iterator()); - } - - - if (cname.size() == 0) - { - return new NameEnumeration (__root.getBindings().values().iterator()); - } - - - - //multipart name - String firstComponent = cname.get(0); - Object ctx = null; - - if (firstComponent.equals("")) - ctx = this; - else - { - Binding binding = __root.getBinding (firstComponent); - if (binding == null) - throw new NameNotFoundException (); - - ctx = binding.getObject(); - - if (ctx instanceof Reference) - { - //deference the object - if(__log.isDebugEnabled())__log.debug("Dereferencing Reference for "+name.get(0)); - try - { - ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), __root, _env); - } - catch (NamingException e) - { - throw e; - } - catch (Exception e) - { - __log.warn("",e); - throw new NamingException (e.getMessage()); - } - } - } - - if (!(ctx instanceof Context)) - throw new NotContextException(); - - return ((Context)ctx).list (cname.getSuffix(1)); - - } + return __root.list(name); } /** - * - * * @see javax.naming.Context#listBindings(javax.naming.Name) */ @Override public NamingEnumeration listBindings(Name name) throws NamingException { - synchronized (__root) - { - //return __root.listBindings(getSuffix(name)); - - Name cname = __root.toCanonicalName (name); - - if (cname == null) - { - List empty = Collections.emptyList(); - return new BindingEnumeration(empty.iterator()); - } - - if (cname.size() == 0) - { - return new BindingEnumeration (__root.getBindings().values().iterator()); - } - - - - //multipart name - String firstComponent = cname.get(0); - Object ctx = null; - - //if a name has a leading "/" it is parsed as "" so ignore it by staying - //at this level in the tree - if (firstComponent.equals("")) - ctx = this; - else - { - //it is a non-empty name component - Binding binding = __root.getBinding (firstComponent); - if (binding == null) - throw new NameNotFoundException (); - - ctx = binding.getObject(); - - if (ctx instanceof Reference) - { - //deference the object - try - { - ctx = NamingManager.getObjectInstance(ctx, getNameParser("").parse(firstComponent), __root, _env); - } - catch (NamingException e) - { - throw e; - } - catch (Exception e) - { - __log.warn("",e); - throw new NamingException (e.getMessage()); - } - } - } - - if (!(ctx instanceof Context)) - throw new NotContextException(); - - return ((Context)ctx).listBindings (cname.getSuffix(1)); - - } + return __root.listBindings(name); } - /** - * - * * @see javax.naming.Context#listBindings(java.lang.String) */ @Override public NamingEnumeration listBindings(String name) throws NamingException { - synchronized (__root) - { - return listBindings(__root.getNameParser("").parse(getSuffix(name))); - } + return __root.listBindings(name); } - /** - * - * * @see javax.naming.Context#addToEnvironment(java.lang.String, - * java.lang.Object) + * java.lang.Object) */ @Override public Object addToEnvironment(String propName, Object propVal) - throws NamingException + throws NamingException { return _env.put(propName, propVal); } /** - * - * * @see javax.naming.Context#composeName(java.lang.String, java.lang.String) */ @Override public String composeName(String name, String prefix) - throws NamingException + throws NamingException { return __root.composeName(name, prefix); } /** - * - * * @see javax.naming.Context#composeName(javax.naming.Name, - * javax.naming.Name) + * javax.naming.Name) */ @Override public Name composeName(Name name, Name prefix) throws NamingException @@ -1140,5 +651,4 @@ public class localContextRoot implements Context { return name; } - } diff --git a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/local/package-info.java b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/local/package-info.java index ac507d2707e..7538092e2dd 100644 --- a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/local/package-info.java +++ b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/local/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/package-info.java b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/package-info.java index 7bf3d64e1bc..cc5d88a4940 100644 --- a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/package-info.java +++ b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -17,7 +17,7 @@ // /** - * Jetty Jndi : Java Naming Directory Interface + * Jetty Jndi : Java Naming Directory Interface */ package org.eclipse.jetty.jndi; diff --git a/jetty-jndi/src/test/java/org/eclipse/jetty/jndi/factories/TestMailSessionReference.java b/jetty-jndi/src/test/java/org/eclipse/jetty/jndi/factories/TestMailSessionReference.java index 96cc462e846..ccbc5386bb1 100644 --- a/jetty-jndi/src/test/java/org/eclipse/jetty/jndi/factories/TestMailSessionReference.java +++ b/jetty-jndi/src/test/java/org/eclipse/jetty/jndi/factories/TestMailSessionReference.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,12 +18,7 @@ package org.eclipse.jetty.jndi.factories; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.util.Properties; - import javax.mail.Session; import javax.naming.Context; import javax.naming.InitialContext; @@ -34,19 +29,23 @@ import javax.naming.NameParser; import org.eclipse.jetty.jndi.NamingUtil; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + /** * */ public class TestMailSessionReference { @Test - public void testMailSessionReference () throws Exception + public void testMailSessionReference() throws Exception { InitialContext icontext = new InitialContext(); MailSessionReference sref = new MailSessionReference(); sref.setUser("janb"); sref.setPassword("OBF:1xmk1w261z0f1w1c1xmq"); - Properties props = new Properties (); + Properties props = new Properties(); props.put("mail.smtp.host", "xxx"); props.put("mail.debug", "true"); sref.setProperties(props); @@ -55,9 +54,9 @@ public class TestMailSessionReference assertNotNull(x); assertTrue(x instanceof javax.mail.Session); javax.mail.Session session = (javax.mail.Session)x; - Properties sessionProps = session.getProperties(); + Properties sessionProps = session.getProperties(); assertEquals(props, sessionProps); - assertTrue (session.getDebug()); + assertTrue(session.getDebug()); Context foo = icontext.createSubcontext("foo"); NameParser parser = icontext.getNameParser(""); diff --git a/jetty-jndi/src/test/java/org/eclipse/jetty/jndi/java/TestJNDI.java b/jetty-jndi/src/test/java/org/eclipse/jetty/jndi/java/TestJNDI.java index 791d1a4630e..af44682b588 100644 --- a/jetty-jndi/src/test/java/org/eclipse/jetty/jndi/java/TestJNDI.java +++ b/jetty-jndi/src/test/java/org/eclipse/jetty/jndi/java/TestJNDI.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,16 +18,10 @@ package org.eclipse.jetty.jndi.java; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - import java.net.URL; import java.net.URLClassLoader; import java.util.HashMap; import java.util.Hashtable; - import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.LinkRef; @@ -49,7 +43,16 @@ import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.HandlerList; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; +import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +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.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + /** * */ @@ -71,33 +74,30 @@ public class TestJNDI { return myString; } - } - - + @Test public void testThreadContextClassloaderAndCurrentContext() - throws Exception + throws Exception { - //create a jetty context, and start it so that its classloader it created //and it is the current context ClassLoader currentLoader = Thread.currentThread().getContextClassLoader(); ContextHandler ch = new ContextHandler(); URLClassLoader chLoader = new URLClassLoader(new URL[0], currentLoader); ch.setClassLoader(chLoader); - Server server = new Server(); + Server server = new Server(); HandlerList hl = new HandlerList(); server.setHandler(hl); hl.addHandler(ch); - + //Create another one ContextHandler ch2 = new ContextHandler(); URLClassLoader ch2Loader = new URLClassLoader(new URL[0], currentLoader); ch2.setClassLoader(ch2Loader); hl.addHandler(ch2); - + try { ch.setContextPath("/ch"); @@ -105,7 +105,7 @@ public class TestJNDI { private Context comp; private Object testObj = new Object(); - + @Override public void contextInitialized(ServletContextEvent sce) { @@ -132,7 +132,7 @@ public class TestJNDI try { assertNotNull(comp); - assertEquals(testObj,comp.lookup("env/ch")); + assertEquals(testObj, comp.lookup("env/ch")); comp.destroySubcontext("env"); } catch (Exception e) @@ -144,7 +144,6 @@ public class TestJNDI //Starting the context makes it current and creates a classloader for it ch.start(); - ch2.setContextPath("/ch2"); ch2.addEventListener(new ServletContextListener() { @@ -159,7 +158,7 @@ public class TestJNDI InitialContext initCtx = new InitialContext(); comp = (Context)initCtx.lookup("java:comp"); assertNotNull(comp); - + //another context's bindings should not be visible Context env = ((Context)comp).createSubcontext("env"); try @@ -177,7 +176,7 @@ public class TestJNDI throw new IllegalStateException(e); } } - + @Override public void contextDestroyed(ServletContextEvent sce) { @@ -202,15 +201,14 @@ public class TestJNDI Thread.currentThread().setContextClassLoader(currentLoader); } } - + @Test public void testJavaNameParsing() throws Exception { Thread currentThread = Thread.currentThread(); ClassLoader currentLoader = currentThread.getContextClassLoader(); ClassLoader childLoader1 = new URLClassLoader(new URL[0], currentLoader); - - + //set the current thread's classloader currentThread.setContextClassLoader(childLoader1); @@ -219,55 +217,71 @@ public class TestJNDI InitialContext initCtx = new InitialContext(); Context sub0 = (Context)initCtx.lookup("java:"); - if(LOG.isDebugEnabled())LOG.debug("------ Looked up java: --------------"); + if (LOG.isDebugEnabled()) + LOG.debug("------ Looked up java: --------------"); Name n = sub0.getNameParser("").parse("/red/green/"); - if(LOG.isDebugEnabled())LOG.debug("get(0)="+n.get(0)); - if(LOG.isDebugEnabled())LOG.debug("getPrefix(1)="+n.getPrefix(1)); + if (LOG.isDebugEnabled()) + LOG.debug("get(0)=" + n.get(0)); + if (LOG.isDebugEnabled()) + LOG.debug("getPrefix(1)=" + n.getPrefix(1)); n = n.getSuffix(1); - if(LOG.isDebugEnabled())LOG.debug("getSuffix(1)="+n); - if(LOG.isDebugEnabled())LOG.debug("get(0)="+n.get(0)); - if(LOG.isDebugEnabled())LOG.debug("getPrefix(1)="+n.getPrefix(1)); + if (LOG.isDebugEnabled()) + LOG.debug("getSuffix(1)=" + n); + if (LOG.isDebugEnabled()) + LOG.debug("get(0)=" + n.get(0)); + if (LOG.isDebugEnabled()) + LOG.debug("getPrefix(1)=" + n.getPrefix(1)); n = n.getSuffix(1); - if(LOG.isDebugEnabled())LOG.debug("getSuffix(1)="+n); - if(LOG.isDebugEnabled())LOG.debug("get(0)="+n.get(0)); - if(LOG.isDebugEnabled())LOG.debug("getPrefix(1)="+n.getPrefix(1)); + if (LOG.isDebugEnabled()) + LOG.debug("getSuffix(1)=" + n); + if (LOG.isDebugEnabled()) + LOG.debug("get(0)=" + n.get(0)); + if (LOG.isDebugEnabled()) + LOG.debug("getPrefix(1)=" + n.getPrefix(1)); n = n.getSuffix(1); - if(LOG.isDebugEnabled())LOG.debug("getSuffix(1)="+n); + if (LOG.isDebugEnabled()) + LOG.debug("getSuffix(1)=" + n); n = sub0.getNameParser("").parse("pink/purple/"); - if(LOG.isDebugEnabled())LOG.debug("get(0)="+n.get(0)); - if(LOG.isDebugEnabled())LOG.debug("getPrefix(1)="+n.getPrefix(1)); + if (LOG.isDebugEnabled()) + LOG.debug("get(0)=" + n.get(0)); + if (LOG.isDebugEnabled()) + LOG.debug("getPrefix(1)=" + n.getPrefix(1)); n = n.getSuffix(1); - if(LOG.isDebugEnabled())LOG.debug("getSuffix(1)="+n); - if(LOG.isDebugEnabled())LOG.debug("get(0)="+n.get(0)); - if(LOG.isDebugEnabled())LOG.debug("getPrefix(1)="+n.getPrefix(1)); + if (LOG.isDebugEnabled()) + LOG.debug("getSuffix(1)=" + n); + if (LOG.isDebugEnabled()) + LOG.debug("get(0)=" + n.get(0)); + if (LOG.isDebugEnabled()) + LOG.debug("getPrefix(1)=" + n.getPrefix(1)); NamingContext ncontext = (NamingContext)sub0; Name nn = ncontext.toCanonicalName(ncontext.getNameParser("").parse("/yellow/blue/")); LOG.debug(nn.toString()); - assertEquals (2, nn.size()); + assertEquals(2, nn.size()); nn = ncontext.toCanonicalName(ncontext.getNameParser("").parse("/yellow/blue")); LOG.debug(nn.toString()); - assertEquals (2, nn.size()); + assertEquals(2, nn.size()); nn = ncontext.toCanonicalName(ncontext.getNameParser("").parse("/")); - if(LOG.isDebugEnabled())LOG.debug("/ parses as: "+nn+" with size="+nn.size()); + if (LOG.isDebugEnabled()) + LOG.debug("/ parses as: " + nn + " with size=" + nn.size()); LOG.debug(nn.toString()); - assertEquals (1, nn.size()); + assertEquals(1, nn.size()); nn = ncontext.toCanonicalName(ncontext.getNameParser("").parse("")); LOG.debug(nn.toString()); - assertEquals (0, nn.size()); + assertEquals(0, nn.size()); Context fee = ncontext.createSubcontext("fee"); - fee.bind ("fi", "88"); + fee.bind("fi", "88"); assertEquals("88", initCtx.lookup("java:/fee/fi")); assertEquals("88", initCtx.lookup("java:/fee/fi/")); - assertTrue (initCtx.lookup("java:/fee/") instanceof javax.naming.Context); + assertTrue(initCtx.lookup("java:/fee/") instanceof javax.naming.Context); } finally { @@ -277,8 +291,6 @@ public class TestJNDI currentThread.setContextClassLoader(currentLoader); } } - - @Test public void testIt() throws Exception @@ -288,7 +300,7 @@ public class TestJNDI ClassLoader currentLoader = currentThread.getContextClassLoader(); ClassLoader childLoader1 = new URLClassLoader(new URL[0], currentLoader); ClassLoader childLoader2 = new URLClassLoader(new URL[0], currentLoader); - + InitialContext initCtx = null; try { @@ -322,20 +334,20 @@ public class TestJNDI } }); */ - + //Set up the tccl before doing any jndi operations currentThread.setContextClassLoader(childLoader1); - InitialContext initCtx = new InitialContext(); - + initCtx = new InitialContext(); + //Test we can lookup the root java: naming tree Context sub0 = (Context)initCtx.lookup("java:"); assertNotNull(sub0); - + //Test that we cannot bind java:comp as it should //already be bound try { - Context sub1 = sub0.createSubcontext ("comp"); + Context sub1 = sub0.createSubcontext("comp"); fail("Comp should already be bound"); } catch (NameAlreadyBoundException e) @@ -347,37 +359,37 @@ public class TestJNDI Context sub1 = (Context)initCtx.lookup("java:comp"); assertNotNull(sub1); - Context sub2 = sub1.createSubcontext ("env"); + Context sub2 = sub1.createSubcontext("env"); assertNotNull(sub2); - initCtx.bind ("java:comp/env/rubbish", "abc"); - assertEquals ("abc", initCtx.lookup("java:comp/env/rubbish")); + initCtx.bind("java:comp/env/rubbish", "abc"); + assertEquals("abc", initCtx.lookup("java:comp/env/rubbish")); //check binding LinkRefs - LinkRef link = new LinkRef ("java:comp/env/rubbish"); - initCtx.bind ("java:comp/env/poubelle", link); - assertEquals ("abc", initCtx.lookup("java:comp/env/poubelle")); + LinkRef link = new LinkRef("java:comp/env/rubbish"); + initCtx.bind("java:comp/env/poubelle", link); + assertEquals("abc", initCtx.lookup("java:comp/env/poubelle")); //check binding References StringRefAddr addr = new StringRefAddr("blah", "myReferenceable"); - Reference ref = new Reference (java.lang.String.class.getName(), - addr, - MyObjectFactory.class.getName(), - null); + Reference ref = new Reference(java.lang.String.class.getName(), + addr, + MyObjectFactory.class.getName(), + null); - initCtx.bind ("java:comp/env/quatsch", ref); - assertEquals (MyObjectFactory.myString, initCtx.lookup("java:comp/env/quatsch")); + initCtx.bind("java:comp/env/quatsch", ref); + assertEquals(MyObjectFactory.myString, initCtx.lookup("java:comp/env/quatsch")); //test binding something at java: Context sub3 = initCtx.createSubcontext("java:zero"); - initCtx.bind ("java:zero/one", "ONE"); - assertEquals ("ONE", initCtx.lookup("java:zero/one")); + initCtx.bind("java:zero/one", "ONE"); + assertEquals("ONE", initCtx.lookup("java:zero/one")); //change the current thread's classloader to check distinct naming currentThread.setContextClassLoader(childLoader2); Context otherSub1 = (Context)initCtx.lookup("java:comp"); - assertTrue (!(sub1 == otherSub1)); + assertTrue(!(sub1 == otherSub1)); try { initCtx.lookup("java:comp/env/rubbish"); @@ -393,76 +405,113 @@ public class TestJNDI //test rebind with existing binding initCtx.rebind("java:comp/env/rubbish", "xyz"); - assertEquals ("xyz", initCtx.lookup("java:comp/env/rubbish")); + assertEquals("xyz", initCtx.lookup("java:comp/env/rubbish")); //test rebind with no existing binding - initCtx.rebind ("java:comp/env/mullheim", "hij"); - assertEquals ("hij", initCtx.lookup("java:comp/env/mullheim")); + initCtx.rebind("java:comp/env/mullheim", "hij"); + assertEquals("hij", initCtx.lookup("java:comp/env/mullheim")); //test that the other bindings are already there - assertEquals ("xyz", initCtx.lookup("java:comp/env/poubelle")); + assertEquals("xyz", initCtx.lookup("java:comp/env/poubelle")); //test java:/comp/env/stuff - assertEquals ("xyz", initCtx.lookup("java:/comp/env/poubelle/")); + assertEquals("xyz", initCtx.lookup("java:/comp/env/poubelle/")); //test list Names - NamingEnumeration nenum = initCtx.list ("java:comp/env"); + NamingEnumeration nenum = initCtx.list("java:comp/env"); HashMap results = new HashMap(); while (nenum.hasMore()) { NameClassPair ncp = (NameClassPair)nenum.next(); - results.put (ncp.getName(), ncp.getClassName()); + results.put(ncp.getName(), ncp.getClassName()); } - assertEquals (4, results.size()); + assertEquals(4, results.size()); - assertEquals ("java.lang.String", results.get("rubbish")); - assertEquals ("javax.naming.LinkRef", results.get("poubelle")); - assertEquals ("java.lang.String", results.get("mullheim")); - assertEquals ("javax.naming.Reference", results.get("quatsch")); + assertEquals("java.lang.String", results.get("rubbish")); + assertEquals("javax.naming.LinkRef", results.get("poubelle")); + assertEquals("java.lang.String", results.get("mullheim")); + assertEquals("javax.naming.Reference", results.get("quatsch")); //test list Bindings NamingEnumeration benum = initCtx.list("java:comp/env"); - assertEquals (4, results.size()); + assertEquals(4, results.size()); //test NameInNamespace - assertEquals ("comp/env", sub2.getNameInNamespace()); + assertEquals("comp/env", sub2.getNameInNamespace()); //test close does nothing Context closeCtx = (Context)initCtx.lookup("java:comp/env"); closeCtx.close(); - //test what happens when you close an initial context InitialContext closeInit = new InitialContext(); closeInit.close(); //check locking the context Context ectx = (Context)initCtx.lookup("java:comp"); + //make a deep structure lie ttt/ttt2 for later use + Context ttt = ectx.createSubcontext("ttt"); + ttt.createSubcontext("ttt2"); + //bind a value ectx.bind("crud", "xxx"); - ectx.addToEnvironment("org.eclipse.jndi.immutable", "TRUE"); - assertEquals ("xxx", initCtx.lookup("java:comp/crud")); + //lock + ectx.addToEnvironment("org.eclipse.jetty.jndi.lock", "TRUE"); + //check we can't get the lock + assertFalse(ectx.getEnvironment().containsKey("org.eclipse.jetty.jndi.lock")); + //check once locked we can still do lookups + assertEquals("xxx", initCtx.lookup("java:comp/crud")); + assertNotNull(initCtx.lookup("java:comp/ttt/ttt2")); + + //test trying to bind into java:comp after lock + InitialContext zzz = null; try { - ectx.bind("crud2", "xxx2"); - } - catch (NamingException ne) - { - //expected failure to modify immutable context - } - + zzz = new InitialContext(); - initCtx.close(); + ((Context)zzz.lookup("java:comp")).bind("crud2", "xxx2"); + fail("Should not be able to write to locked context"); + } + catch (NamingException e) + { + assertThat(e.getMessage(), Matchers.containsString("immutable")); + } + finally + { + zzz.close(); + } + + //test trying to bind into a deep structure inside java:comp after lock + try + { + zzz = new InitialContext(); + + //TODO test deep locking + // ((Context)zzz.lookup("java:comp/ttt/ttt2")).bind("zzz2", "zzz2"); + // fail("Should not be able to write to locked context"); + ((Context)zzz.lookup("java:comp")).bind("foo", "bar"); + fail("Should not be able to write to locked context"); + } + catch (NamingException e) + { + assertThat(e.getMessage(), Matchers.containsString("immutable")); + } + finally + { + zzz.close(); + } } finally { //make some effort to clean up + initCtx.close(); InitialContext ic = new InitialContext(); Context java = (Context)ic.lookup("java:"); java.destroySubcontext("zero"); java.destroySubcontext("fee"); currentThread.setContextClassLoader(childLoader1); Context comp = (Context)ic.lookup("java:comp"); + comp.addToEnvironment("org.eclipse.jetty.jndi.unlock", "TRUE"); comp.destroySubcontext("env"); comp.unbind("crud"); comp.unbind("crud2"); diff --git a/jetty-jndi/src/test/java/org/eclipse/jetty/jndi/java/TestLocalJNDI.java b/jetty-jndi/src/test/java/org/eclipse/jetty/jndi/java/TestLocalJNDI.java index 238fffac914..0f49d633ea2 100644 --- a/jetty-jndi/src/test/java/org/eclipse/jetty/jndi/java/TestLocalJNDI.java +++ b/jetty-jndi/src/test/java/org/eclipse/jetty/jndi/java/TestLocalJNDI.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,12 +18,7 @@ package org.eclipse.jetty.jndi.java; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.fail; - import java.util.Hashtable; - import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.Name; @@ -40,6 +35,10 @@ import org.eclipse.jetty.jndi.NamingUtil; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.fail; + /** * */ @@ -56,7 +55,7 @@ public class TestLocalJNDI { if (!env.containsKey("flavour")) - throw new Exception ("No flavour!"); + throw new Exception("No flavour!"); if (obj instanceof Reference) { @@ -71,10 +70,9 @@ public class TestLocalJNDI } } return null; - } + } } - public static class Fruit implements Referenceable { String fruit; @@ -101,13 +99,6 @@ public class TestLocalJNDI } } - - - - - - - @AfterEach public void tearDown() throws Exception { @@ -115,11 +106,10 @@ public class TestLocalJNDI ic.destroySubcontext("a"); } - @Test public void testLocalReferenceable() throws Exception { - Hashtable env1 = new Hashtable(); + Hashtable env1 = new Hashtable(); env1.put("flavour", "orange"); InitialContext ic1 = new InitialContext(env1); @@ -127,7 +117,7 @@ public class TestLocalJNDI Object o = ic1.lookup("valencia"); - Hashtable env2 = new Hashtable(); + Hashtable env2 = new Hashtable(); InitialContext ic2 = new InitialContext(env2); try { @@ -140,11 +130,10 @@ public class TestLocalJNDI } } - @Test public void testLocalEnvironment() throws Exception { - Hashtable env1 = new Hashtable(); + Hashtable env1 = new Hashtable(); env1.put("make", "holden"); env1.put("model", "commodore"); @@ -162,7 +151,7 @@ public class TestLocalJNDI assertEquals("holden", ht.get("make")); assertEquals("commodore", ht.get("model")); - Hashtable env2 = new Hashtable(); + Hashtable env2 = new Hashtable(); env2.put("flavour", "strawberry"); InitialContext ic2 = new InitialContext(env2); assertEquals(car1, ic2.lookup("car1")); @@ -188,14 +177,10 @@ public class TestLocalJNDI c = (Context)ic.lookup("carz/hatchbackz"); assertNotNull(c); assertEquals(hatchbackz, c); - } - - - @Test - public void testLocal () throws Exception + public void testLocal() throws Exception { InitialContext ic = new InitialContext(); NameParser parser = ic.getNameParser(""); diff --git a/jetty-jspc-maven-plugin/pom.xml b/jetty-jspc-maven-plugin/pom.xml index cd2eeb1b88d..746af56521f 100644 --- a/jetty-jspc-maven-plugin/pom.xml +++ b/jetty-jspc-maven-plugin/pom.xml @@ -1,8 +1,9 @@ - + + org.eclipse.jetty jetty-project - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 jetty-jspc-maven-plugin @@ -10,7 +11,6 @@ Jetty :: Jetty JSPC Maven Plugin ${project.groupId}.jspc.plugin - false @@ -56,20 +56,10 @@ - ${it.debug} true - 60 - src/it - ${project.build.directory}/it - - */pom.xml - - ${project.build.directory}/local-repo - src/it/settings.xml ${maven.surefire.version} - ${skipTests} clean @@ -110,7 +100,7 @@ org.eclipse.jetty apache-jsp ${project.version} - + org.eclipse.jetty apache-jstl diff --git a/jetty-jspc-maven-plugin/src/it/package-root/invoker.properties b/jetty-jspc-maven-plugin/src/it/package-root/invoker.properties new file mode 100644 index 00000000000..df6cbf2d0bc --- /dev/null +++ b/jetty-jspc-maven-plugin/src/it/package-root/invoker.properties @@ -0,0 +1,2 @@ +invoker.goals = test -fae +invoker.debug = true diff --git a/jetty-jspc-maven-plugin/src/it/package-root/pom.xml b/jetty-jspc-maven-plugin/src/it/package-root/pom.xml new file mode 100644 index 00000000000..310a1fc0c0c --- /dev/null +++ b/jetty-jspc-maven-plugin/src/it/package-root/pom.xml @@ -0,0 +1,42 @@ + + + 4.0.0 + + org.eclipse.jetty.its.jspc + simple-jsp + 0.0.1-SNAPSHOT + pom + + Jetty :: Simple Jsp + + + UTF-8 + UTF-8 + 1.8 + @project.version@ + + + + + + org.eclipse.jetty + jetty-jspc-maven-plugin + ${jetty.version} + + + + jspc + + compile + + + org.eclipse.jetty.test + + + + + + + + + diff --git a/jetty-jspc-maven-plugin/src/it/package-root/postbuild.groovy b/jetty-jspc-maven-plugin/src/it/package-root/postbuild.groovy new file mode 100644 index 00000000000..2ef6ebf6368 --- /dev/null +++ b/jetty-jspc-maven-plugin/src/it/package-root/postbuild.groovy @@ -0,0 +1,9 @@ + + +System.out.println( "running postbuild.groovy" ) + +File file = new File( basedir, "target/classes/org/eclipse/jetty/test/foo_jsp.class" ) +if ( !file.isFile() ) +{ + throw new FileNotFoundException( "Could not find generated class in the proper package name: " + file ) +} diff --git a/jetty-jspc-maven-plugin/src/it/package-root/src/main/webapp/foo.jsp b/jetty-jspc-maven-plugin/src/it/package-root/src/main/webapp/foo.jsp new file mode 100644 index 00000000000..fb73b0b0002 --- /dev/null +++ b/jetty-jspc-maven-plugin/src/it/package-root/src/main/webapp/foo.jsp @@ -0,0 +1,23 @@ + +<%@ page import="java.util.Enumeration" %> + +

        JSP Dump

        + + + + + + +<% + Enumeration e =request.getParameterNames(); + while(e.hasMoreElements()) + { + String name = (String)e.nextElement(); +%> + + + +<% } %> + +
        Request URI:<%= request.getRequestURI() %>
        ServletPath:<%= request.getServletPath() %>
        PathInfo:<%= request.getPathInfo() %>
        getParameter("<%= name %>")<%= request.getParameter(name) %>
        + diff --git a/jetty-jspc-maven-plugin/src/it/simple-jsp-fail/pom.xml b/jetty-jspc-maven-plugin/src/it/simple-jsp-fail/pom.xml index f6c1416e8e8..5c8fe323d9e 100644 --- a/jetty-jspc-maven-plugin/src/it/simple-jsp-fail/pom.xml +++ b/jetty-jspc-maven-plugin/src/it/simple-jsp-fail/pom.xml @@ -1,6 +1,5 @@ - + 4.0.0 org.eclipse.jetty.its.jspc @@ -18,7 +17,6 @@ @project.version@ - diff --git a/jetty-jspc-maven-plugin/src/it/simple-jsp/pom.xml b/jetty-jspc-maven-plugin/src/it/simple-jsp/pom.xml index 5b1bb09a31b..b4b4052c0d3 100644 --- a/jetty-jspc-maven-plugin/src/it/simple-jsp/pom.xml +++ b/jetty-jspc-maven-plugin/src/it/simple-jsp/pom.xml @@ -1,6 +1,5 @@ - + 4.0.0 org.eclipse.jetty.its.jspc @@ -17,7 +16,6 @@ @project.version@ - diff --git a/jetty-jspc-maven-plugin/src/main/java/org/eclipse/jetty/jspc/plugin/JspcMojo.java b/jetty-jspc-maven-plugin/src/main/java/org/eclipse/jetty/jspc/plugin/JspcMojo.java index 34c75bd66ee..2b93292bbe4 100644 --- a/jetty-jspc-maven-plugin/src/main/java/org/eclipse/jetty/jspc/plugin/JspcMojo.java +++ b/jetty-jspc-maven-plugin/src/main/java/org/eclipse/jetty/jspc/plugin/JspcMojo.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -42,7 +42,6 @@ import org.apache.maven.artifact.Artifact; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; -import org.apache.maven.plugins.annotations.Component; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; @@ -71,90 +70,83 @@ import org.eclipse.jetty.util.resource.Resource; *

        * Runs jspc compiler to produce .java and .class files */ -@Mojo( name = "jspc", defaultPhase = LifecyclePhase.PROCESS_CLASSES, requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME) +@Mojo(name = "jspc", defaultPhase = LifecyclePhase.PROCESS_CLASSES, requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME) public class JspcMojo extends AbstractMojo { public static final String END_OF_WEBAPP = ""; public static final String PRECOMPILED_FLAG = "org.eclipse.jetty.jsp.precompiled"; - /** * JettyJspC * * Add some extra setters to standard JspC class to help configure it * for running in maven. - * + * * TODO move all setters on the plugin onto this jspc class instead. */ public static class JettyJspC extends JspC { - + private boolean scanAll; - - public void setClassLoader (ClassLoader loader) + + public void setClassLoader(ClassLoader loader) { this.loader = loader; } - - public void setScanAllDirectories (boolean scanAll) - { - this.scanAll = scanAll; - } - - public boolean getScanAllDirectories () - { - return this.scanAll; - } - + + public void setScanAllDirectories(boolean scanAll) + { + this.scanAll = scanAll; + } + + public boolean getScanAllDirectories() + { + return this.scanAll; + } @Override protected TldScanner newTldScanner(JspCServletContext context, boolean namespaceAware, boolean validate, boolean blockExternal) - { - if (context != null && context.getAttribute(JarScanner.class.getName()) == null) + { + if (context != null && context.getAttribute(JarScanner.class.getName()) == null) { - StandardJarScanner jarScanner = new StandardJarScanner(); + StandardJarScanner jarScanner = new StandardJarScanner(); jarScanner.setScanAllDirectories(getScanAllDirectories()); context.setAttribute(JarScanner.class.getName(), jarScanner); } - + return super.newTldScanner(context, namespaceAware, validate, blockExternal); - } + } } - - + /** * Whether or not to include dependencies on the plugin's classpath with <scope>provided</scope> * Use WITH CAUTION as you may wind up with duplicate jars/classes. - * + * * @since jetty-7.6.3 */ @Parameter(defaultValue = "false") private boolean useProvidedScope; - + /** * The artifacts for the project. - * + * * @since jetty-7.6.3 */ @Parameter(defaultValue = "${project.artifacts}", readonly = true) - private Set projectArtifacts; - - + private Set projectArtifacts; + /** * The maven project. */ - @Parameter(defaultValue = "${project}", readonly = true , required = true) + @Parameter(defaultValue = "${project}", readonly = true, required = true) private MavenProject project; - - /** * The artifacts for the plugin itself. */ @Parameter(defaultValue = "${plugin.artifacts}", readonly = true) - private List pluginArtifacts; - - + private List pluginArtifacts; + /** * File into which to generate the <servlet> and * <servlet-mapping> tags for the compiled jsps @@ -205,7 +197,6 @@ public class JspcMojo extends AbstractMojo @Parameter(defaultValue = "${basedir}/src/main/webapp/WEB-INF/web.xml") private String webXml; - /** * The comma separated list of patterns for file extensions to be processed. By default * will include all .jsp and .jspx files. @@ -225,35 +216,30 @@ public class JspcMojo extends AbstractMojo @Parameter(defaultValue = "${project.build.outputDirectory}") private File classesDirectory; - /** * Patterns of jars on the system path that contain tlds. Use | to separate each pattern. */ @Parameter(defaultValue = ".*taglibs[^/]*\\.jar|.*jstl[^/]*\\.jar$") private String tldJarNamePatterns; - - + /** * Source version - if not set defaults to jsp default (currently 1.7) */ @Parameter private String sourceVersion; - - + /** * Target version - if not set defaults to jsp default (currently 1.7) */ @Parameter private String targetVersion; - + /** - * * The JspC instance being used to compile the jsps. */ @Parameter private JettyJspC jspc; - /** * Whether dirs on the classpath should be scanned as well as jars. * True by default. This allows for scanning for tlds of dependent projects that @@ -261,7 +247,6 @@ public class JspcMojo extends AbstractMojo */ @Parameter(defaultValue = "true") private boolean scanAllDirectories; - @Override public void execute() throws MojoExecutionException, MojoFailureException @@ -272,14 +257,14 @@ public class JspcMojo extends AbstractMojo getLog().info("webAppSourceDirectory=" + webAppSourceDirectory); getLog().info("generatedClasses=" + generatedClasses); getLog().info("webXmlFragment=" + webXmlFragment); - getLog().info("webXml="+webXml); - getLog().info("insertionMarker="+ (insertionMarker == null || insertionMarker.equals("") ? END_OF_WEBAPP : insertionMarker)); + getLog().info("webXml=" + webXml); + getLog().info("insertionMarker=" + (insertionMarker == null || insertionMarker.equals("") ? END_OF_WEBAPP : insertionMarker)); getLog().info("keepSources=" + keepSources); - getLog().info("mergeFragment=" + mergeFragment); + getLog().info("mergeFragment=" + mergeFragment); if (sourceVersion != null) - getLog().info("sourceVersion="+sourceVersion); + getLog().info("sourceVersion=" + sourceVersion); if (targetVersion != null) - getLog().info("targetVersion="+targetVersion); + getLog().info("targetVersion=" + targetVersion); } try { @@ -300,17 +285,16 @@ public class JspcMojo extends AbstractMojo //set up the classpath of the webapp List webAppUrls = setUpWebAppClassPath(); - + //set up the classpath of the container (ie jetty and jsp jars) Set pluginJars = getPluginJars(); Set providedJars = getProvidedScopeJars(pluginJars); - //Make a classloader so provided jars will be on the classpath List sysUrls = new ArrayList<>(); - sysUrls.addAll(providedJars); + sysUrls.addAll(providedJars); URLClassLoader sysClassLoader = new URLClassLoader(sysUrls.toArray(new URL[0]), currentClassLoader); - + //make a classloader with the webapp classpath URLClassLoader webAppClassLoader = new URLClassLoader(webAppUrls.toArray(new URL[0]), sysClassLoader); StringBuilder webAppClassPath = new StringBuilder(); @@ -318,26 +302,25 @@ public class JspcMojo extends AbstractMojo for (int i = 0; i < webAppUrls.size(); i++) { if (getLog().isDebugEnabled()) - getLog().debug("webappclassloader contains: " + webAppUrls.get(i)); + getLog().debug("webappclassloader contains: " + webAppUrls.get(i)); webAppClassPath.append(new File(webAppUrls.get(i).toURI()).getCanonicalPath()); if (getLog().isDebugEnabled()) getLog().debug("added to classpath: " + (webAppUrls.get(i)).getFile()); - if (i+1 { + delete(generatedClassesDir, pathname -> + { return pathname.isDirectory() || pathname.getName().endsWith(".java"); }); } } } - + static void delete(File dir, FileFilter filter) { File[] files = dir.listFiles(filter); if (files != null) { - for(File f: files) + for (File f : files) { - if(f.isDirectory()) + if (f.isDirectory()) delete(f, filter); else f.delete(); @@ -417,13 +400,13 @@ public class JspcMojo extends AbstractMojo /** * Take the web fragment and put it inside a copy of the web.xml. - * + * * You can specify the insertion point by specifying the string in the * insertionMarker configuration entry. - * + * * If you dont specify the insertionMarker, then the fragment will be * inserted at the end of the file just before the </webapp> - * + * * @throws Exception if unable to merge the web xml */ public void mergeWebXml() throws Exception @@ -432,18 +415,18 @@ public class JspcMojo extends AbstractMojo { // open the src web.xml File webXml = getWebXmlFile(); - + if (!webXml.exists()) { getLog().info(webXml.toString() + " does not exist, cannot merge with generated fragment"); return; } - File fragmentWebXml = new File(webXmlFragment); + File fragmentWebXml = new File(webXmlFragment); File mergedWebXml = new File(fragmentWebXml.getParentFile(), "web.xml"); try (BufferedReader webXmlReader = new BufferedReader(new FileReader(webXml)); - PrintWriter mergedWebXmlWriter = new PrintWriter(new FileWriter(mergedWebXml))) + PrintWriter mergedWebXmlWriter = new PrintWriter(new FileWriter(mergedWebXml))) { if (!fragmentWebXml.exists()) @@ -458,8 +441,7 @@ public class JspcMojo extends AbstractMojo // marker boolean atInsertPoint = false; boolean atEOF = false; - String marker = (insertionMarker == null - || insertionMarker.equals("") ? END_OF_WEBAPP : insertionMarker); + String marker = (insertionMarker == null || insertionMarker.equals("") ? END_OF_WEBAPP : insertionMarker); while (!atInsertPoint && !atEOF) { String line = webXmlReader.readLine(); @@ -476,15 +458,14 @@ public class JspcMojo extends AbstractMojo } if (atEOF && !atInsertPoint) - throw new IllegalStateException("web.xml does not contain insertionMarker "+insertionMarker); + throw new IllegalStateException("web.xml does not contain insertionMarker " + insertionMarker); //put in a context init-param to flag that the contents have been precompiled - mergedWebXmlWriter.println(""+PRECOMPILED_FLAG+"true"); - + mergedWebXmlWriter.println("" + PRECOMPILED_FLAG + "true"); // put in the generated fragment - try (BufferedReader fragmentWebXmlReader = - new BufferedReader(new FileReader(fragmentWebXml))) + try (BufferedReader fragmentWebXmlReader = + new BufferedReader(new FileReader(fragmentWebXml))) { IO.copy(fragmentWebXmlReader, mergedWebXmlWriter); @@ -511,12 +492,11 @@ public class JspcMojo extends AbstractMojo /** * Set up the execution classpath for Jasper. - * + * * Put everything in the classesDirectory and all of the dependencies on the * classpath. - * + * * @returns a list of the urls of the dependencies - * @throws Exception */ private List setUpWebAppClassPath() throws Exception { @@ -530,9 +510,9 @@ public class JspcMojo extends AbstractMojo getLog().debug("Adding to classpath classes dir: " + classesDir); //add the dependencies of the webapp (which will form WEB-INF/lib) - for (Iterator iter = project.getArtifacts().iterator(); iter.hasNext();) + for (Iterator iter = project.getArtifacts().iterator(); iter.hasNext(); ) { - Artifact artifact = (Artifact)iter.next(); + Artifact artifact = iter.next(); // Include runtime and compile time libraries if (!Artifact.SCOPE_TEST.equals(artifact.getScope()) && !Artifact.SCOPE_PROVIDED.equals(artifact.getScope())) @@ -546,14 +526,11 @@ public class JspcMojo extends AbstractMojo } return urls; } - - - + /** - * @return - * @throws MalformedURLException + * */ - private Set getPluginJars () throws MalformedURLException + private Set getPluginJars() throws MalformedURLException { HashSet pluginJars = new HashSet<>(); for (Iterator iter = pluginArtifacts.iterator(); iter.hasNext(); ) @@ -561,30 +538,29 @@ public class JspcMojo extends AbstractMojo Artifact pluginArtifact = iter.next(); if ("jar".equalsIgnoreCase(pluginArtifact.getType())) { - if (getLog().isDebugEnabled()) { getLog().debug("Adding plugin artifact "+pluginArtifact);} + if (getLog().isDebugEnabled()) + { + getLog().debug("Adding plugin artifact " + pluginArtifact); + } pluginJars.add(pluginArtifact.getFile().toURI().toURL()); } } - + return pluginJars; } - - - + /** - * @param pluginJars - * @return - * @throws MalformedURLException + * */ - private Set getProvidedScopeJars (Set pluginJars) throws MalformedURLException + private Set getProvidedScopeJars(Set pluginJars) throws MalformedURLException { if (!useProvidedScope) return Collections.emptySet(); - + HashSet providedJars = new HashSet<>(); - - for ( Iterator iter = projectArtifacts.iterator(); iter.hasNext(); ) - { + + for (Iterator iter = projectArtifacts.iterator(); iter.hasNext(); ) + { Artifact artifact = iter.next(); if (Artifact.SCOPE_PROVIDED.equals(artifact.getScope())) { @@ -593,39 +569,43 @@ public class JspcMojo extends AbstractMojo if (!pluginJars.contains(jar)) { providedJars.add(jar); - if (getLog().isDebugEnabled()) { getLog().debug("Adding provided artifact: "+artifact);} - } + if (getLog().isDebugEnabled()) + { + getLog().debug("Adding provided artifact: " + artifact); + } + } else { - if (getLog().isDebugEnabled()) { getLog().debug("Skipping provided artifact: "+artifact);} + if (getLog().isDebugEnabled()) + { + getLog().debug("Skipping provided artifact: " + artifact); + } } } } return providedJars; } - - - private File getWebXmlFile () - throws IOException + private File getWebXmlFile() + throws IOException { File file = null; File baseDir = project.getBasedir().getCanonicalFile(); - File defaultWebAppSrcDir = new File (baseDir, "src/main/webapp").getCanonicalFile(); - File webAppSrcDir = new File (webAppSourceDirectory).getCanonicalFile(); - File defaultWebXml = new File (defaultWebAppSrcDir, "web.xml").getCanonicalFile(); - + File defaultWebAppSrcDir = new File(baseDir, "src/main/webapp").getCanonicalFile(); + File webAppSrcDir = new File(webAppSourceDirectory).getCanonicalFile(); + File defaultWebXml = new File(defaultWebAppSrcDir, "web.xml").getCanonicalFile(); + //If the web.xml has been changed from the default, try that - File webXmlFile = new File (webXml).getCanonicalFile(); + File webXmlFile = new File(webXml).getCanonicalFile(); if (webXmlFile.compareTo(defaultWebXml) != 0) { - file = new File (webXml); + file = new File(webXml); return file; } - + //If the web app src directory has not been changed from the default, use whatever //is set for the web.xml location - file = new File (webAppSrcDir, "web.xml"); + file = new File(webAppSrcDir, "web.xml"); return file; } } diff --git a/jetty-jspc-maven-plugin/src/main/java/org/eclipse/jetty/jspc/plugin/package-info.java b/jetty-jspc-maven-plugin/src/main/java/org/eclipse/jetty/jspc/plugin/package-info.java index b3f891e2d67..dc7883db9dc 100644 --- a/jetty-jspc-maven-plugin/src/main/java/org/eclipse/jetty/jspc/plugin/package-info.java +++ b/jetty-jspc-maven-plugin/src/main/java/org/eclipse/jetty/jspc/plugin/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-maven-plugin/README_INTEGRATION_TEST.md b/jetty-maven-plugin/README_INTEGRATION_TEST.md index 206b7191097..93ff4c3bd58 100644 --- a/jetty-maven-plugin/README_INTEGRATION_TEST.md +++ b/jetty-maven-plugin/README_INTEGRATION_TEST.md @@ -14,9 +14,11 @@ As they can be long to run, the tests do not run per default. So to run them you Running single test -------------------- -You can run single or set of test as well using the command line argument: ```-Dinvoker.test=jetty-run-mojo-it,jetty-run-war*-it,!jetty-run-distro*``` +You can run single or set of test as well using the command line argument: ```-Dinvoker.test=it-parent-pom,jetty-run-mojo-it,jetty-run-war*-it,!jetty-run-distro*``` The parameter supports pattern and exclusion with ! +Due to [files filtering](http://maven.apache.org/plugins/maven-invoker-plugin/examples/filtering.html), ```it-parent-pom``` must be included - otherwise tests will fail during execution. + Running Logs -------------------- The output of each Maven build will be located in /target/it/${project-name}/build.log diff --git a/jetty-maven-plugin/pom.xml b/jetty-maven-plugin/pom.xml index c4d02c88a29..ecb746a6233 100644 --- a/jetty-maven-plugin/pom.xml +++ b/jetty-maven-plugin/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 jetty-maven-plugin @@ -11,7 +11,6 @@ Jetty maven plugins ${project.groupId}.maven.plugin - false FREEBEER @@ -62,29 +61,15 @@ - ${java.home} - - ${java.home} - - ${it.debug} true - src/it - 600 - ${project.build.directory}/it - - */pom.xml - it-parent-pom/pom.xml - ${project.build.directory}/local-repo - src/it/settings.xml ${jetty.stopKey} ${jetty.stopPort} ${maven.surefire.version} - ${skipTests} clean @@ -126,7 +111,7 @@ org.apache.maven maven-artifact - + org.apache.maven maven-core @@ -185,6 +170,26 @@ jetty-server ${project.version} + + org.eclipse.jetty + jetty-servlet + ${project.version} + + + org.eclipse.jetty + jetty-client + ${project.version} + + + org.eclipse.jetty + jetty-http + ${project.version} + + + org.eclipse.jetty + jetty-io + ${project.version} + org.eclipse.jetty jetty-jmx @@ -215,11 +220,11 @@ apache-jstl ${project.version} - - javax.transaction - javax.transaction-api - compile - + + javax.transaction + javax.transaction-api + compile + org.eclipse.jetty jetty-home diff --git a/jetty-maven-plugin/src/it/it-parent-pom/pom.xml b/jetty-maven-plugin/src/it/it-parent-pom/pom.xml index ffffdf384e7..06bf3d62cdd 100644 --- a/jetty-maven-plugin/src/it/it-parent-pom/pom.xml +++ b/jetty-maven-plugin/src/it/it-parent-pom/pom.xml @@ -1,6 +1,5 @@ - + 4.0.0 org.eclipse.jetty.its @@ -10,6 +9,7 @@ @project.version@ + UTF-8 @@ -19,17 +19,17 @@ commons-io 2.6 + + org.apache.commons + commons-lang3 + 3.8.1 + javax.servlet javax.servlet-api @javax.servlet.api.version@ provided - - org.jboss.weld.servlet - weld-servlet - @weld.version@ - org.eclipse.jetty.toolchain jetty-perf-helper @@ -38,7 +38,7 @@ com.fasterxml.jackson.core jackson-databind - 2.8.1 + 2.9.8 org.slf4j @@ -139,8 +139,18 @@ maven-war-plugin @maven.war.plugin.version@
        + + org.apache.maven.plugins + maven-install-plugin + @maven.install.plugin.version@ + + + org.apache.maven.plugins + maven-deploy-plugin + @maven.deploy.plugin.version@ +
        -
        \ No newline at end of file +
        diff --git a/jetty-maven-plugin/src/it/javax-annotation-api/invoker.properties b/jetty-maven-plugin/src/it/javax-annotation-api/invoker.properties new file mode 100644 index 00000000000..e0222d4d54e --- /dev/null +++ b/jetty-maven-plugin/src/it/javax-annotation-api/invoker.properties @@ -0,0 +1 @@ +invoker.goals = test \ No newline at end of file diff --git a/jetty-maven-plugin/src/it/javax-annotation-api/pom.xml b/jetty-maven-plugin/src/it/javax-annotation-api/pom.xml new file mode 100644 index 00000000000..651b2c07836 --- /dev/null +++ b/jetty-maven-plugin/src/it/javax-annotation-api/pom.xml @@ -0,0 +1,102 @@ + + + + 4.0.0 + + + + + org.eclipse.jetty.its + it-parent-pom + 0.0.1-SNAPSHOT + + + javax-annotation-api-test + 1.0.0-SNAPSHOT + war + + + UTF-8 + 8 + 8 + + ${project.build.directory}/jetty-run-mojo-annotation.txt + @javax.annotation-api@ + + + + + javax.servlet + javax.servlet-api + @javax.servlet.api.version@ + provided + + + javax.annotation + javax.annotation-api + ${annotation-api.version} + + + org.springframework.boot + spring-boot-autoconfigure + @spring-boot.version@ + + + org.springframework.boot + spring-boot-starter-web + @spring-boot.version@ + + + org.springframework.boot + spring-boot-starter-tomcat + + + + + + + + + + org.eclipse.jetty + jetty-maven-plugin + + + start-jetty + test-compile + + start + + + + + jetty.port.file + ${jetty.port.file} + + + true + ${basedir}/src/config/jetty.xml + + + + + + + + + javax.annotation + javax.annotation-api + ${annotation-api.version} + + + javax.annotation + jsr250-api + @jsr250-api.version@ + + + + diff --git a/jetty-maven-plugin/src/it/javax-annotation-api/postbuild.groovy b/jetty-maven-plugin/src/it/javax-annotation-api/postbuild.groovy new file mode 100644 index 00000000000..9533c9ecc2c --- /dev/null +++ b/jetty-maven-plugin/src/it/javax-annotation-api/postbuild.groovy @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +File buildLog = new File( basedir, 'build.log' ) +assert buildLog.text.contains( 'Started Jetty Server' ) +assert buildLog.text.contains( 'all good guys get a good Beer') diff --git a/jetty-maven-plugin/src/it/javax-annotation-api/src/config/jetty.xml b/jetty-maven-plugin/src/it/javax-annotation-api/src/config/jetty.xml new file mode 100644 index 00000000000..10a800b245d --- /dev/null +++ b/jetty-maven-plugin/src/it/javax-annotation-api/src/config/jetty.xml @@ -0,0 +1,39 @@ + + + + + https + + 32768 + 8192 + 8192 + 4096 + + + + + + + + + + + + + + + + + + + + + + + + 0 + 30000 + + + + diff --git a/jetty-maven-plugin/src/it/javax-annotation-api/src/main/java/test/App.java b/jetty-maven-plugin/src/it/javax-annotation-api/src/main/java/test/App.java new file mode 100644 index 00000000000..ab3b8dc2c77 --- /dev/null +++ b/jetty-maven-plugin/src/it/javax-annotation-api/src/main/java/test/App.java @@ -0,0 +1,65 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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 test; + +import java.io.InputStream; +import java.util.Properties; +import javax.annotation.PostConstruct; +import javax.annotation.Resource; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; +import org.springframework.context.annotation.Bean; + +/** + * Hello world! + */ +public class App extends SpringBootServletInitializer +{ + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @Resource(name = "my.properties") + private Properties somePropertyFile; + + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) + { + return builder.sources(App.class); + } + + @PostConstruct + public void done() + { + logger.info("all good guys get a good {}", somePropertyFile.get("drink")); + } + + @Bean(name = "my.properties") + public Properties getSomeProperties() throws Exception + { + Properties properties = new Properties(); + try (InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("my.properties")) + { + properties.load(inputStream); + } + return properties; + } +} diff --git a/jetty-maven-plugin/src/it/javax-annotation-api/src/main/resources/my.properties b/jetty-maven-plugin/src/it/javax-annotation-api/src/main/resources/my.properties new file mode 100644 index 00000000000..5c07b0ed01e --- /dev/null +++ b/jetty-maven-plugin/src/it/javax-annotation-api/src/main/resources/my.properties @@ -0,0 +1 @@ +drink=Beer diff --git a/jetty-maven-plugin/src/it/jetty-cdi-run-forked/pom.xml b/jetty-maven-plugin/src/it/jetty-cdi-run-forked/pom.xml index 9208f7ecd10..77a6976ca96 100644 --- a/jetty-maven-plugin/src/it/jetty-cdi-run-forked/pom.xml +++ b/jetty-maven-plugin/src/it/jetty-cdi-run-forked/pom.xml @@ -1,7 +1,5 @@ - + 4.0.0 @@ -20,10 +18,6 @@ - - org.jboss.weld.servlet - weld-servlet - javax.servlet javax.servlet-api @@ -57,6 +51,7 @@ ${jetty.port.file} true + ${project.groupId}:${project.artifactId} org.eclipse.jetty:jetty-maven-plugin diff --git a/jetty-maven-plugin/src/it/jetty-cdi-run-forked/src/main/java/test/Greeter.java b/jetty-maven-plugin/src/it/jetty-cdi-run-forked/src/main/java/test/Greeter.java index c9e9a9ab797..4534448fc90 100644 --- a/jetty-maven-plugin/src/it/jetty-cdi-run-forked/src/main/java/test/Greeter.java +++ b/jetty-maven-plugin/src/it/jetty-cdi-run-forked/src/main/java/test/Greeter.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,24 +18,24 @@ package test; +import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -@WebServlet( "/*" ) +@WebServlet("/*") public class Greeter extends HttpServlet { @Override - protected void doGet( final HttpServletRequest req, final HttpServletResponse resp ) + protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException { - String who = req.getParameter( "name" ); + String who = req.getParameter("name"); - resp.getWriter().write( "Hello " + (who == null ? "unknown" : who) ); + resp.getWriter().write("Hello " + (who == null ? "unknown" : who)); } } diff --git a/jetty-maven-plugin/src/it/jetty-cdi-run-forked/src/main/jetty/jetty-context.xml b/jetty-maven-plugin/src/it/jetty-cdi-run-forked/src/main/jetty/jetty-context.xml index e8d11555975..035ac67844e 100644 --- a/jetty-maven-plugin/src/it/jetty-cdi-run-forked/src/main/jetty/jetty-context.xml +++ b/jetty-maven-plugin/src/it/jetty-cdi-run-forked/src/main/jetty/jetty-context.xml @@ -1,23 +1,23 @@ - - + - - - -org.eclipse.jetty.util.Decorator - - - -org.eclipse.jetty.util.DecoratedObjectFactory - - - -org.eclipse.jetty.server.handler.ContextHandler. - - - -org.eclipse.jetty.server.handler.ContextHandler - - - -org.eclipse.jetty.servlet.ServletContextHandler - + + + -org.eclipse.jetty.util.Decorator + + + -org.eclipse.jetty.util.DecoratedObjectFactory + + + -org.eclipse.jetty.server.handler.ContextHandler. + + + -org.eclipse.jetty.server.handler.ContextHandler + + + -org.eclipse.jetty.servlet.ServletContextHandler + + diff --git a/jetty-maven-plugin/src/it/jetty-cdi-run-forked/src/main/jetty/jetty.xml b/jetty-maven-plugin/src/it/jetty-cdi-run-forked/src/main/jetty/jetty.xml index 4fb92bbea50..10a800b245d 100644 --- a/jetty-maven-plugin/src/it/jetty-cdi-run-forked/src/main/jetty/jetty.xml +++ b/jetty-maven-plugin/src/it/jetty-cdi-run-forked/src/main/jetty/jetty.xml @@ -1,5 +1,4 @@ - - + diff --git a/jetty-maven-plugin/src/it/jetty-deploy-war-mojo-it/pom.xml b/jetty-maven-plugin/src/it/jetty-deploy-war-mojo-it/pom.xml index 528b0890f38..d29454fdaf9 100644 --- a/jetty-maven-plugin/src/it/jetty-deploy-war-mojo-it/pom.xml +++ b/jetty-maven-plugin/src/it/jetty-deploy-war-mojo-it/pom.xml @@ -1,6 +1,5 @@ - + 4.0.0 @@ -43,6 +42,7 @@ ${jetty.port.file} + ${project.groupId}:${project.artifactId} Bean Validation Webapp example @@ -95,7 +95,6 @@
        - org.apache.maven.plugins maven-dependency-plugin diff --git a/jetty-maven-plugin/src/it/jetty-deploy-war-mojo-it/src/config/jetty.xml b/jetty-maven-plugin/src/it/jetty-deploy-war-mojo-it/src/config/jetty.xml index 4fb92bbea50..10a800b245d 100644 --- a/jetty-maven-plugin/src/it/jetty-deploy-war-mojo-it/src/config/jetty.xml +++ b/jetty-maven-plugin/src/it/jetty-deploy-war-mojo-it/src/config/jetty.xml @@ -1,5 +1,4 @@ - - + diff --git a/jetty-maven-plugin/src/it/jetty-maven-plugin-provided-module-dep/api/pom.xml b/jetty-maven-plugin/src/it/jetty-maven-plugin-provided-module-dep/api/pom.xml new file mode 100755 index 00000000000..da37bc1e3d6 --- /dev/null +++ b/jetty-maven-plugin/src/it/jetty-maven-plugin-provided-module-dep/api/pom.xml @@ -0,0 +1,11 @@ + + 4.0.0 + + + test.jetty-maven-plugin-provided-module-dep + parent + 1.0-SNAPSHOT + + api + + diff --git a/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/TimeFormatter.java b/jetty-maven-plugin/src/it/jetty-maven-plugin-provided-module-dep/api/src/main/java/test/Api.java old mode 100644 new mode 100755 similarity index 79% rename from jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/TimeFormatter.java rename to jetty-maven-plugin/src/it/jetty-maven-plugin-provided-module-dep/api/src/main/java/test/Api.java index bd19ce309ea..cf09b59a299 --- a/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/TimeFormatter.java +++ b/jetty-maven-plugin/src/it/jetty-maven-plugin-provided-module-dep/api/src/main/java/test/Api.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,11 +16,12 @@ // ======================================================================== // -package org.eclipse.jetty.cdi.servlet; +package test; -import java.util.Calendar; - -public interface TimeFormatter +public class Api { - public String format(Calendar cal); + + public void noOp() + { + } } diff --git a/jetty-maven-plugin/src/it/jetty-maven-plugin-provided-module-dep/invoker.properties b/jetty-maven-plugin/src/it/jetty-maven-plugin-provided-module-dep/invoker.properties new file mode 100644 index 00000000000..816c3f38def --- /dev/null +++ b/jetty-maven-plugin/src/it/jetty-maven-plugin-provided-module-dep/invoker.properties @@ -0,0 +1,2 @@ +invoker.goals = verify -V -e +#test-compile failsafe:integration-test \ No newline at end of file diff --git a/jetty-maven-plugin/src/it/jetty-maven-plugin-provided-module-dep/pom.xml b/jetty-maven-plugin/src/it/jetty-maven-plugin-provided-module-dep/pom.xml new file mode 100755 index 00000000000..d7e74fcaa00 --- /dev/null +++ b/jetty-maven-plugin/src/it/jetty-maven-plugin-provided-module-dep/pom.xml @@ -0,0 +1,20 @@ + + 4.0.0 + + + org.eclipse.jetty.its + it-parent-pom + 0.0.1-SNAPSHOT + + + test.jetty-maven-plugin-provided-module-dep + parent + 1.0-SNAPSHOT + pom + + + api + web + + + diff --git a/jetty-maven-plugin/src/it/jetty-maven-plugin-provided-module-dep/postbuild.groovy b/jetty-maven-plugin/src/it/jetty-maven-plugin-provided-module-dep/postbuild.groovy new file mode 100644 index 00000000000..4c12de49d83 --- /dev/null +++ b/jetty-maven-plugin/src/it/jetty-maven-plugin-provided-module-dep/postbuild.groovy @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +File buildLog = new File( basedir, 'build.log' ) +assert buildLog.text.contains( 'Started Jetty Server' ) +assert buildLog.text.contains( 'ClassNotFoundException') \ No newline at end of file diff --git a/jetty-maven-plugin/src/it/jetty-maven-plugin-provided-module-dep/web/pom.xml b/jetty-maven-plugin/src/it/jetty-maven-plugin-provided-module-dep/web/pom.xml new file mode 100755 index 00000000000..d09cb5dfeb7 --- /dev/null +++ b/jetty-maven-plugin/src/it/jetty-maven-plugin-provided-module-dep/web/pom.xml @@ -0,0 +1,57 @@ + + 4.0.0 + + + test.jetty-maven-plugin-provided-module-dep + parent + 1.0-SNAPSHOT + + web + war + + + + ${project.groupId} + api + ${project.version} + provided + + + javax.servlet + javax.servlet-api + provided + + + + + + + org.apache.maven.plugins + maven-war-plugin + + false + + + + + + + org.eclipse.jetty + jetty-maven-plugin + + + start-jetty + test-compile + + start + + + true + ${basedir}/src/config/jetty.xml + + + + + + + diff --git a/jetty-maven-plugin/src/it/jetty-maven-plugin-provided-module-dep/web/src/config/jetty.xml b/jetty-maven-plugin/src/it/jetty-maven-plugin-provided-module-dep/web/src/config/jetty.xml new file mode 100644 index 00000000000..f04eb038c0c --- /dev/null +++ b/jetty-maven-plugin/src/it/jetty-maven-plugin-provided-module-dep/web/src/config/jetty.xml @@ -0,0 +1,46 @@ + + + + + https + + + + 32768 + 8192 + 8192 + 4096 + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + 30000 + + + + diff --git a/jetty-maven-plugin/src/it/jetty-maven-plugin-provided-module-dep/web/src/main/java/test/ClassLoadingTestingServletContextListener.java b/jetty-maven-plugin/src/it/jetty-maven-plugin-provided-module-dep/web/src/main/java/test/ClassLoadingTestingServletContextListener.java new file mode 100755 index 00000000000..e5c41993eb0 --- /dev/null +++ b/jetty-maven-plugin/src/it/jetty-maven-plugin-provided-module-dep/web/src/main/java/test/ClassLoadingTestingServletContextListener.java @@ -0,0 +1,48 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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 test; + +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import javax.servlet.annotation.WebListener; + +@WebListener +public class ClassLoadingTestingServletContextListener + implements ServletContextListener +{ + + @Override + public void contextInitialized(ServletContextEvent sce) + { + try + { + Api api = new Api(); + } + catch (java.lang.Exception exception) + { + exception.printStackTrace(); + } + //System.out.println("Class " + api.getClass().getName() + " is available and loaded by classloader " + api.getClass().getClassLoader().toString() + ". Expected ClassNotFoundException."); + } + + @Override + public void contextDestroyed(ServletContextEvent sce) + { + } +} diff --git a/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-base/pom.xml b/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-base/pom.xml index fdcc1c71400..1432226dbe5 100644 --- a/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-base/pom.xml +++ b/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-base/pom.xml @@ -1,6 +1,5 @@ - + 4.0.0 diff --git a/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_distro_mojo_it/HelloServlet.java b/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_distro_mojo_it/HelloServlet.java index 12a508a7e96..72553f5395f 100644 --- a/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_distro_mojo_it/HelloServlet.java +++ b/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_distro_mojo_it/HelloServlet.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,15 +16,14 @@ // ======================================================================== // - package org.eclipse.jetty.its.jetty_run_distro_mojo_it; +import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.io.IOException; /** * @@ -35,11 +34,11 @@ public class HelloServlet { @Override - protected void doGet( HttpServletRequest req, HttpServletResponse resp ) + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException - { - String who = req.getParameter( "name" ); + { + String who = req.getParameter("name"); - resp.getWriter().write( "Hello " + (who == null ? "unknown" : who) ); + resp.getWriter().write("Hello " + (who == null ? "unknown" : who)); } } diff --git a/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_distro_mojo_it/PingServlet.java b/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_distro_mojo_it/PingServlet.java index 434fdae2d12..4dd7c6f7eb8 100644 --- a/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_distro_mojo_it/PingServlet.java +++ b/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_distro_mojo_it/PingServlet.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,26 +16,24 @@ // ======================================================================== // - package org.eclipse.jetty.its.jetty_run_distro_mojo_it; +import java.io.IOException; import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.io.IOException; public class PingServlet extends HttpServlet { @Override - protected void doGet( HttpServletRequest req, HttpServletResponse resp ) + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - String who = req.getParameter( "name" ); + String who = req.getParameter("name"); - resp.getWriter().write( "pong " + (who == null ? "unknown" : who) ); + resp.getWriter().write("pong " + (who == null ? "unknown" : who)); } } diff --git a/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-webapp/pom.xml b/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-webapp/pom.xml index 168dd7e7b2e..1fd3ec985f2 100644 --- a/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-webapp/pom.xml +++ b/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-webapp/pom.xml @@ -1,6 +1,5 @@ - + 4.0.0 @@ -70,6 +69,7 @@ ${jetty.port.file} true true + ${project.groupId}:${project.artifactId} org.eclipse.jetty:jetty-maven-plugin @@ -92,6 +92,7 @@ ${basedir}/src/base + ${java.home}/bin/java jetty.server.dumpAfterStart=true jetty.port.file=${jetty.port.file} @@ -110,5 +111,4 @@
        -
        diff --git a/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-webapp/src/base/etc/test-jetty.xml b/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-webapp/src/base/etc/test-jetty.xml index 5062d20c4fc..52e0cc6be76 100644 --- a/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-webapp/src/base/etc/test-jetty.xml +++ b/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-webapp/src/base/etc/test-jetty.xml @@ -1,5 +1,4 @@ - - + diff --git a/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-webapp/src/main/webapp/WEB-INF/web.xml b/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-webapp/src/main/webapp/WEB-INF/web.xml index 2a5ac4b71bf..30ebb9bfe89 100644 --- a/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-webapp/src/main/webapp/WEB-INF/web.xml +++ b/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/jetty-simple-webapp/src/main/webapp/WEB-INF/web.xml @@ -1,7 +1,4 @@ - + Jetty Simple Webapp run-mojo-it diff --git a/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/pom.xml b/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/pom.xml index 6ad8242c113..4b7fea358b2 100644 --- a/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/pom.xml +++ b/jetty-maven-plugin/src/it/jetty-run-distro-mojo-it/pom.xml @@ -1,6 +1,5 @@ - + 4.0.0 diff --git a/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/jetty-simple-base/pom.xml b/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/jetty-simple-base/pom.xml index 10adc6ec1c0..ac9aa597956 100644 --- a/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/jetty-simple-base/pom.xml +++ b/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/jetty-simple-base/pom.xml @@ -1,6 +1,5 @@ - + 4.0.0 diff --git a/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_forked_mojo_it/HelloServlet.java b/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_forked_mojo_it/HelloServlet.java index 9d4582a75f6..267d52bafaa 100644 --- a/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_forked_mojo_it/HelloServlet.java +++ b/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_forked_mojo_it/HelloServlet.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,15 +16,14 @@ // ======================================================================== // - package org.eclipse.jetty.its.jetty_run_forked_mojo_it; +import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.io.IOException; /** * @@ -35,11 +34,11 @@ public class HelloServlet { @Override - protected void doGet( HttpServletRequest req, HttpServletResponse resp ) + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - String who = req.getParameter( "name" ); + String who = req.getParameter("name"); - resp.getWriter().write( "Hello " + (who == null ? "unknown" : who) ); + resp.getWriter().write("Hello " + (who == null ? "unknown" : who)); } } diff --git a/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_forked_mojo_it/PingServlet.java b/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_forked_mojo_it/PingServlet.java index 51259941ca4..386bbe55295 100644 --- a/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_forked_mojo_it/PingServlet.java +++ b/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_forked_mojo_it/PingServlet.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,26 +16,24 @@ // ======================================================================== // - package org.eclipse.jetty.its.jetty_run_forked_mojo_it; +import java.io.IOException; import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.io.IOException; public class PingServlet extends HttpServlet { @Override - protected void doGet( HttpServletRequest req, HttpServletResponse resp ) + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - String who = req.getParameter( "name" ); + String who = req.getParameter("name"); - resp.getWriter().write( "pong " + (who == null ? "unknown" : who) ); + resp.getWriter().write("pong " + (who == null ? "unknown" : who)); } } diff --git a/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/jetty-simple-webapp/pom.xml b/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/jetty-simple-webapp/pom.xml index c8af2120bd4..386ae2e2531 100644 --- a/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/jetty-simple-webapp/pom.xml +++ b/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/jetty-simple-webapp/pom.xml @@ -1,6 +1,5 @@ - + 4.0.0 @@ -70,6 +69,7 @@ ${jetty.port.file} true true + ${project.groupId}:${project.artifactId} org.eclipse.jetty:jetty-maven-plugin @@ -96,7 +96,7 @@ ${basedir}/src/config/jetty.xml ${jetty.jvmArgs} - jetty.port.file=${jetty.port.file} + jetty.port.file=${jetty.port.file} @@ -114,5 +114,4 @@ - diff --git a/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/jetty-simple-webapp/src/config/jetty.xml b/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/jetty-simple-webapp/src/config/jetty.xml index 4fb92bbea50..10a800b245d 100644 --- a/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/jetty-simple-webapp/src/config/jetty.xml +++ b/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/jetty-simple-webapp/src/config/jetty.xml @@ -1,5 +1,4 @@ - - + diff --git a/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/jetty-simple-webapp/src/main/webapp/WEB-INF/web.xml b/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/jetty-simple-webapp/src/main/webapp/WEB-INF/web.xml index 2a5ac4b71bf..30ebb9bfe89 100644 --- a/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/jetty-simple-webapp/src/main/webapp/WEB-INF/web.xml +++ b/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/jetty-simple-webapp/src/main/webapp/WEB-INF/web.xml @@ -1,7 +1,4 @@ - + Jetty Simple Webapp run-mojo-it diff --git a/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/pom.xml b/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/pom.xml index 93e5bc38b15..813ecc5bfd0 100644 --- a/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/pom.xml +++ b/jetty-maven-plugin/src/it/jetty-run-forked-mojo-it/pom.xml @@ -1,6 +1,5 @@ - + 4.0.0 diff --git a/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-base/pom.xml b/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-base/pom.xml index 05c9b0335f0..3d8c237caf9 100644 --- a/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-base/pom.xml +++ b/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-base/pom.xml @@ -1,6 +1,5 @@ - + 4.0.0 diff --git a/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_mojo_it/HelloServlet.java b/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_mojo_it/HelloServlet.java index 1c093c1675c..5cf82ccf88e 100644 --- a/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_mojo_it/HelloServlet.java +++ b/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_mojo_it/HelloServlet.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,15 +16,14 @@ // ======================================================================== // - package org.eclipse.jetty.its.jetty_run_mojo_it; +import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.io.IOException; /** * @@ -35,11 +34,11 @@ public class HelloServlet { @Override - protected void doGet( HttpServletRequest req, HttpServletResponse resp ) + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - String who = req.getParameter( "name" ); + String who = req.getParameter("name"); - resp.getWriter().write( "Hello " + (who == null ? "unknown" : who) ); + resp.getWriter().write("Hello " + (who == null ? "unknown" : who)); } } diff --git a/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_mojo_it/PingServlet.java b/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_mojo_it/PingServlet.java index dc1d723151f..48152a7b735 100644 --- a/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_mojo_it/PingServlet.java +++ b/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_mojo_it/PingServlet.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,26 +16,24 @@ // ======================================================================== // - package org.eclipse.jetty.its.jetty_run_mojo_it; +import java.io.IOException; import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.io.IOException; public class PingServlet extends HttpServlet { @Override - protected void doGet( HttpServletRequest req, HttpServletResponse resp ) + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - String who = req.getParameter( "name" ); + String who = req.getParameter("name"); - resp.getWriter().write( "pong " + (who == null ? "unknown" : who) ); + resp.getWriter().write("pong " + (who == null ? "unknown" : who)); } } diff --git a/jetty-cdi/test-cdi-webapp/src/main/java/org/eclipse/jetty/tests/HelloServlet.java b/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-base/src/test/java/org/eclipse/jetty/its/jetty_run_mojo_it_test/HelloTestServlet.java similarity index 73% rename from jetty-cdi/test-cdi-webapp/src/main/java/org/eclipse/jetty/tests/HelloServlet.java rename to jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-base/src/test/java/org/eclipse/jetty/its/jetty_run_mojo_it_test/HelloTestServlet.java index 8809ca1be35..91c72bacf55 100644 --- a/jetty-cdi/test-cdi-webapp/src/main/java/org/eclipse/jetty/tests/HelloServlet.java +++ b/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-base/src/test/java/org/eclipse/jetty/its/jetty_run_mojo_it_test/HelloTestServlet.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,10 +16,9 @@ // ======================================================================== // -package org.eclipse.jetty.tests; +package org.eclipse.jetty.its.jetty_run_mojo_it_test; import java.io.IOException; - import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; @@ -27,16 +26,19 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** - * The most basic servlet here, no CDI use. + * */ -@SuppressWarnings("serial") -@WebServlet("/hello") -public class HelloServlet extends HttpServlet +@WebServlet("/testhello") +public class HelloTestServlet + extends HttpServlet { + @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException + protected void doGet(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { - resp.setContentType("text/plain"); - resp.getWriter().println("Hello World"); + String who = req.getParameter("name"); + + resp.getWriter().write("Hello from test " + (who == null ? "unknown" : who)); } } diff --git a/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-webapp/pom.xml b/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-webapp/pom.xml index d8514ea74e5..d17cc126f78 100644 --- a/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-webapp/pom.xml +++ b/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-webapp/pom.xml @@ -1,6 +1,5 @@ - + 4.0.0 @@ -23,26 +22,44 @@ org.eclipse.jetty.its.jetty-run-mojo-it jetty-simple-base - + + org.eclipse.jetty.its.jetty-run-mojo-it + jetty-simple-base + test + test-jar + org.slf4j slf4j-simple - org.eclipse.jetty jetty-servlet provided - + + org.eclipse.jetty + jetty-client + test + + + org.apache.commons + commons-lang3 + test + org.eclipse.jetty jetty-maven-plugin tests test-jar test + + + * + * + + - org.junit.jupiter junit-jupiter-engine @@ -73,6 +90,8 @@ ${jetty.port.file} true true + true + ${project.groupId}:${project.artifactId} org.eclipse.jetty:jetty-maven-plugin @@ -98,6 +117,7 @@ true ${basedir}/src/config/jetty.xml + true @@ -105,5 +125,4 @@ - diff --git a/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-webapp/src/config/jetty.xml b/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-webapp/src/config/jetty.xml index 4fb92bbea50..10a800b245d 100644 --- a/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-webapp/src/config/jetty.xml +++ b/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-webapp/src/config/jetty.xml @@ -1,5 +1,4 @@ - - + diff --git a/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-webapp/src/main/webapp/WEB-INF/web.xml b/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-webapp/src/main/webapp/WEB-INF/web.xml index 2a5ac4b71bf..30ebb9bfe89 100644 --- a/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-webapp/src/main/webapp/WEB-INF/web.xml +++ b/jetty-maven-plugin/src/it/jetty-run-mojo-it/jetty-simple-webapp/src/main/webapp/WEB-INF/web.xml @@ -1,7 +1,4 @@ - + Jetty Simple Webapp run-mojo-it diff --git a/jetty-maven-plugin/src/it/jetty-run-mojo-it/pom.xml b/jetty-maven-plugin/src/it/jetty-run-mojo-it/pom.xml index 1625960b537..d082c71bbe5 100644 --- a/jetty-maven-plugin/src/it/jetty-run-mojo-it/pom.xml +++ b/jetty-maven-plugin/src/it/jetty-run-mojo-it/pom.xml @@ -1,6 +1,5 @@ - + 4.0.0 @@ -35,6 +34,13 @@ jetty-simple-base ${project.version} + + org.eclipse.jetty.its.jetty-run-mojo-it + jetty-simple-base + ${project.version} + test + test-jar + diff --git a/jetty-maven-plugin/src/it/jetty-run-mojo-jsp/invoker.properties b/jetty-maven-plugin/src/it/jetty-run-mojo-jsp/invoker.properties new file mode 100644 index 00000000000..e0222d4d54e --- /dev/null +++ b/jetty-maven-plugin/src/it/jetty-run-mojo-jsp/invoker.properties @@ -0,0 +1 @@ +invoker.goals = test \ No newline at end of file diff --git a/jetty-maven-plugin/src/it/jetty-run-mojo-jsp/pom.xml b/jetty-maven-plugin/src/it/jetty-run-mojo-jsp/pom.xml new file mode 100644 index 00000000000..2b8d3949624 --- /dev/null +++ b/jetty-maven-plugin/src/it/jetty-run-mojo-jsp/pom.xml @@ -0,0 +1,103 @@ + + + 4.0.0 + + + org.eclipse.jetty.its + it-parent-pom + 0.0.1-SNAPSHOT + + + jetty-run-mojo-jsp + war + + Jetty :: Simple :: Webapp + + + ${project.build.directory}/jetty-run-mojo-jsp.txt + + + + + org.slf4j + slf4j-simple + + + + org.eclipse.jetty + jetty-servlet + provided + + + + org.eclipse.jetty + jetty-maven-plugin + tests + test-jar + test + + + + org.junit.jupiter + junit-jupiter-engine + test + + + + + + + + + + org.apache.maven.plugins + maven-war-plugin + + false + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + ${jetty.port.file} + Counter accessed 1 times. + /jsp/bean1.jsp + ${project.groupId}:${project.artifactId} + + + org.eclipse.jetty:jetty-maven-plugin + + + + + org.eclipse.jetty + jetty-maven-plugin + + + start-jetty + test-compile + + start + + + + + jetty.port.file + ${jetty.port.file} + + + true + ${basedir}/src/config/jetty.xml + + + + + + + + diff --git a/jetty-maven-plugin/src/it/jetty-run-mojo-jsp/postbuild.groovy b/jetty-maven-plugin/src/it/jetty-run-mojo-jsp/postbuild.groovy new file mode 100644 index 00000000000..4c4b42e2f2f --- /dev/null +++ b/jetty-maven-plugin/src/it/jetty-run-mojo-jsp/postbuild.groovy @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +File buildLog = new File( basedir, 'build.log' ) +assert buildLog.text.contains( 'Started Jetty Server' ) +assert buildLog.text.contains( 'Running org.eclipse.jetty.maven.plugin.it.TestGetContent') +assert buildLog.text.contains( 'contentCheck') diff --git a/jetty-maven-plugin/src/it/jetty-run-mojo-jsp/src/config/jetty.xml b/jetty-maven-plugin/src/it/jetty-run-mojo-jsp/src/config/jetty.xml new file mode 100644 index 00000000000..10a800b245d --- /dev/null +++ b/jetty-maven-plugin/src/it/jetty-run-mojo-jsp/src/config/jetty.xml @@ -0,0 +1,39 @@ + + + + + https + + 32768 + 8192 + 8192 + 4096 + + + + + + + + + + + + + + + + + + + + + + + + 0 + 30000 + + + + diff --git a/jetty-maven-plugin/src/it/jetty-run-mojo-jsp/src/main/java/com/acme/Counter.java b/jetty-maven-plugin/src/it/jetty-run-mojo-jsp/src/main/java/com/acme/Counter.java new file mode 100644 index 00000000000..4ff284e5dbe --- /dev/null +++ b/jetty-maven-plugin/src/it/jetty-run-mojo-jsp/src/main/java/com/acme/Counter.java @@ -0,0 +1,43 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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 com.acme; + +@SuppressWarnings("serial") +public class Counter implements java.io.Serializable +{ + int counter = 0; + String last; + + public int getCount() + { + counter++; + return counter; + } + + public void setLast(String uri) + { + last = uri; + } + + public String getLast() + { + return last; + } +} + diff --git a/jetty-maven-plugin/src/it/jetty-run-mojo-jsp/src/main/webapp/WEB-INF/web.xml b/jetty-maven-plugin/src/it/jetty-run-mojo-jsp/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000000..9bc23dafae6 --- /dev/null +++ b/jetty-maven-plugin/src/it/jetty-run-mojo-jsp/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,4 @@ + + + Jetty Simple Webapp run-mojo-jsp + diff --git a/jetty-maven-plugin/src/it/jetty-run-mojo-jsp/src/main/webapp/jsp/bean1.jsp b/jetty-maven-plugin/src/it/jetty-run-mojo-jsp/src/main/webapp/jsp/bean1.jsp new file mode 100644 index 00000000000..02a13d85e56 --- /dev/null +++ b/jetty-maven-plugin/src/it/jetty-run-mojo-jsp/src/main/webapp/jsp/bean1.jsp @@ -0,0 +1,13 @@ + +<%@ page session="true"%> + + + +

        JSP1.2 Beans: 1

        + +Counter accessed times.
        +Counter last accessed by
        + + + + diff --git a/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/common/pom.xml b/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/common/pom.xml new file mode 100644 index 00000000000..06de7ece78d --- /dev/null +++ b/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/common/pom.xml @@ -0,0 +1,11 @@ + + + 4.0.0 + + test.jetty-run-mojo-multi-module-single-war-it + jetty-multi-module-project + 1.0-SNAPSHOT + + common + + diff --git a/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/Dumper.java b/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/common/src/main/java/mca/common/CommonService.java similarity index 75% rename from jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/Dumper.java rename to jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/common/src/main/java/mca/common/CommonService.java index 8faed6976fd..594d387ae36 100644 --- a/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/Dumper.java +++ b/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/common/src/main/java/mca/common/CommonService.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,12 +16,9 @@ // ======================================================================== // -package org.eclipse.jetty.cdi.servlet; +package mca.common; -import java.io.IOException; -import java.io.PrintWriter; - -public interface Dumper +public class CommonService { - public void dump(PrintWriter out) throws IOException; + } diff --git a/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/invoker.properties b/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/invoker.properties new file mode 100644 index 00000000000..fd18ebccf10 --- /dev/null +++ b/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/invoker.properties @@ -0,0 +1 @@ +invoker.goals = test diff --git a/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/module/module-api/pom.xml b/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/module/module-api/pom.xml new file mode 100644 index 00000000000..f3a237dbd74 --- /dev/null +++ b/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/module/module-api/pom.xml @@ -0,0 +1,11 @@ + + + 4.0.0 + + test.jetty-run-mojo-multi-module-single-war-it + module + 1.0-SNAPSHOT + + module-api + + diff --git a/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/module/module-api/src/main/java/mca/module/ModuleApi.java b/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/module/module-api/src/main/java/mca/module/ModuleApi.java new file mode 100644 index 00000000000..c5fc25f27d6 --- /dev/null +++ b/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/module/module-api/src/main/java/mca/module/ModuleApi.java @@ -0,0 +1,24 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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 mca.module; + +public interface ModuleApi +{ + +} diff --git a/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/module/module-impl/pom.xml b/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/module/module-impl/pom.xml new file mode 100644 index 00000000000..0e26990e518 --- /dev/null +++ b/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/module/module-impl/pom.xml @@ -0,0 +1,17 @@ + + + 4.0.0 + + test.jetty-run-mojo-multi-module-single-war-it + module + 1.0-SNAPSHOT + + module-impl + + + + test.jetty-run-mojo-multi-module-single-war-it + module-api + + + diff --git a/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/module/module-impl/src/main/java/mca/module/ModuleImpl.java b/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/module/module-impl/src/main/java/mca/module/ModuleImpl.java new file mode 100644 index 00000000000..4b00df5286a --- /dev/null +++ b/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/module/module-impl/src/main/java/mca/module/ModuleImpl.java @@ -0,0 +1,27 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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 mca.module; + +import mca.common.CommonService; + +public class ModuleImpl implements ModuleApi +{ + + private static final CommonService cs = new CommonService(); +} diff --git a/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/module/pom.xml b/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/module/pom.xml new file mode 100644 index 00000000000..f91edba7216 --- /dev/null +++ b/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/module/pom.xml @@ -0,0 +1,24 @@ + + + 4.0.0 + + test.jetty-run-mojo-multi-module-single-war-it + jetty-multi-module-project + 1.0-SNAPSHOT + + module + pom + + + module-api + module-impl + + + + + test.jetty-run-mojo-multi-module-single-war-it + common + + + + diff --git a/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/pom.xml b/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/pom.xml new file mode 100644 index 00000000000..a098c9a06d1 --- /dev/null +++ b/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/pom.xml @@ -0,0 +1,51 @@ + + + 4.0.0 + + + org.eclipse.jetty.its + it-parent-pom + 0.0.1-SNAPSHOT + + + test.jetty-run-mojo-multi-module-single-war-it + jetty-multi-module-project + 1.0-SNAPSHOT + pom + + Jetty :: multi-module project + + + common + module + webapp-war + + + + UTF-8 + UTF-8 + 1.8 + @project.version@ + + + + + + test.jetty-run-mojo-multi-module-single-war-it + common + ${project.version} + + + test.jetty-run-mojo-multi-module-single-war-it + module-api + ${project.version} + + + test.jetty-run-mojo-multi-module-single-war-it + module-impl + ${project.version} + + + + + diff --git a/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/postbuild.groovy b/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/postbuild.groovy new file mode 100644 index 00000000000..bd9510f83fc --- /dev/null +++ b/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/postbuild.groovy @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +File buildLog = new File( basedir, 'build.log' ) +assert buildLog.text.contains( 'Started Jetty Server' ) + +assert buildLog.text.contains( '(1a) >> javax.servlet.ServletContextListener loaded from jar:' ) +assert buildLog.text.contains( 'javax/servlet/javax.servlet-api/3.1.0/javax.servlet-api-3.1.0.jar!/javax/servlet/ServletContextListener.class << (1b)' ) + +assert buildLog.text.contains( '(2a) >> mca.common.CommonService loaded from file:' ) +assert buildLog.text.contains( 'common/target/classes/mca/common/CommonService.class << (2b)' ) + +assert buildLog.text.contains( '(3a) >> mca.module.ModuleApi loaded from file:' ) +assert buildLog.text.contains( 'module/module-api/target/classes/mca/module/ModuleApi.class << (3b)' ) + +assert buildLog.text.contains( '(4a) >> mca.module.ModuleImpl loaded from file:' ) +assert buildLog.text.contains( 'module/module-impl/target/classes/mca/module/ModuleImpl.class << (4b)' ) + +assert buildLog.text.contains( '(5a) >> mca.webapp.WebAppServletListener loaded from file:' ) +assert buildLog.text.contains( 'webapp-war/target/classes/mca/webapp/WebAppServletListener.class << (5b)' ) diff --git a/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/webapp-war/pom.xml b/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/webapp-war/pom.xml new file mode 100644 index 00000000000..51bd52b5f51 --- /dev/null +++ b/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/webapp-war/pom.xml @@ -0,0 +1,55 @@ + + + 4.0.0 + + test.jetty-run-mojo-multi-module-single-war-it + jetty-multi-module-project + 1.0-SNAPSHOT + + webapp-war + war + + + + javax.servlet + javax.servlet-api + + + test.jetty-run-mojo-multi-module-single-war-it + module-impl + + + + + ${project.build.directory}/jetty-run-mojo.txt + + + + + + org.eclipse.jetty + jetty-maven-plugin + + + start-jetty + test-compile + + start + + + + + jetty.port.file + ${jetty.port.file} + + + true + ${basedir}/src/config/jetty.xml + + + + + + + + diff --git a/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/webapp-war/src/config/jetty.xml b/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/webapp-war/src/config/jetty.xml new file mode 100644 index 00000000000..10a800b245d --- /dev/null +++ b/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/webapp-war/src/config/jetty.xml @@ -0,0 +1,39 @@ + + + + + https + + 32768 + 8192 + 8192 + 4096 + + + + + + + + + + + + + + + + + + + + + + + + 0 + 30000 + + + + diff --git a/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/webapp-war/src/main/java/mca/webapp/WebAppServletListener.java b/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/webapp-war/src/main/java/mca/webapp/WebAppServletListener.java new file mode 100644 index 00000000000..c7ba86c9802 --- /dev/null +++ b/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/webapp-war/src/main/java/mca/webapp/WebAppServletListener.java @@ -0,0 +1,55 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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 mca.webapp; + +import java.net.URL; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; + +import static java.lang.String.format; + +public class WebAppServletListener implements ServletContextListener +{ + + @Override + public void contextInitialized(ServletContextEvent servletContextEvent) + { + print("1", "javax.servlet.ServletContextListener"); + print("2", "mca.common.CommonService"); + print("3", "mca.module.ModuleApi"); + print("4", "mca.module.ModuleImpl"); + print("5", "mca.webapp.WebAppServletListener"); + } + + @Override + public void contextDestroyed(ServletContextEvent servletContextEvent) + { + + } + + private void print(String counter, String className) + { + String res = className.replaceAll("\\.", "/") + ".class"; + URL url = Thread.currentThread().getContextClassLoader().getResource(res); + System.out.println( + format("(%sa) >> %s loaded from %s << (%sb)", + counter, className, url, counter) + ); + } +} diff --git a/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/webapp-war/src/main/webapp/WEB-INF/web.xml b/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/webapp-war/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000000..5d48dd82060 --- /dev/null +++ b/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/webapp-war/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,11 @@ + + + + + + + mca.webapp.WebAppServletListener + + diff --git a/jetty-maven-plugin/src/it/jetty-run-war-exploded-mojo-it/jetty-simple-base/pom.xml b/jetty-maven-plugin/src/it/jetty-run-war-exploded-mojo-it/jetty-simple-base/pom.xml index 1fa6323df0f..9eb42b6801e 100644 --- a/jetty-maven-plugin/src/it/jetty-run-war-exploded-mojo-it/jetty-simple-base/pom.xml +++ b/jetty-maven-plugin/src/it/jetty-run-war-exploded-mojo-it/jetty-simple-base/pom.xml @@ -1,6 +1,5 @@ - + 4.0.0 diff --git a/jetty-maven-plugin/src/it/jetty-run-war-exploded-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_war_exploded_mojo_it/HelloServlet.java b/jetty-maven-plugin/src/it/jetty-run-war-exploded-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_war_exploded_mojo_it/HelloServlet.java index 0ab06680ecf..01cadf64ae9 100644 --- a/jetty-maven-plugin/src/it/jetty-run-war-exploded-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_war_exploded_mojo_it/HelloServlet.java +++ b/jetty-maven-plugin/src/it/jetty-run-war-exploded-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_war_exploded_mojo_it/HelloServlet.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,15 +16,14 @@ // ======================================================================== // - package org.eclipse.jetty.its.jetty_run_war_exploded_mojo_it; +import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.io.IOException; /** * @@ -35,11 +34,11 @@ public class HelloServlet { @Override - protected void doGet( HttpServletRequest req, HttpServletResponse resp ) + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - String who = req.getParameter( "name" ); + String who = req.getParameter("name"); - resp.getWriter().write( "Hello " + (who == null ? "unknown" : who) ); + resp.getWriter().write("Hello " + (who == null ? "unknown" : who)); } } diff --git a/jetty-maven-plugin/src/it/jetty-run-war-exploded-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_war_exploded_mojo_it/PingServlet.java b/jetty-maven-plugin/src/it/jetty-run-war-exploded-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_war_exploded_mojo_it/PingServlet.java index 88155a20738..c4abedfae8e 100644 --- a/jetty-maven-plugin/src/it/jetty-run-war-exploded-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_war_exploded_mojo_it/PingServlet.java +++ b/jetty-maven-plugin/src/it/jetty-run-war-exploded-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_war_exploded_mojo_it/PingServlet.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,26 +16,24 @@ // ======================================================================== // - package org.eclipse.jetty.its.jetty_run_war_exploded_mojo_it; +import java.io.IOException; import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.io.IOException; public class PingServlet extends HttpServlet { @Override - protected void doGet( HttpServletRequest req, HttpServletResponse resp ) + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - String who = req.getParameter( "name" ); + String who = req.getParameter("name"); - resp.getWriter().write( "pong " + (who == null ? "unknown" : who) ); + resp.getWriter().write("pong " + (who == null ? "unknown" : who)); } } diff --git a/jetty-maven-plugin/src/it/jetty-run-war-exploded-mojo-it/jetty-simple-webapp/pom.xml b/jetty-maven-plugin/src/it/jetty-run-war-exploded-mojo-it/jetty-simple-webapp/pom.xml index 0d75cad9095..7c9eae6c588 100644 --- a/jetty-maven-plugin/src/it/jetty-run-war-exploded-mojo-it/jetty-simple-webapp/pom.xml +++ b/jetty-maven-plugin/src/it/jetty-run-war-exploded-mojo-it/jetty-simple-webapp/pom.xml @@ -1,6 +1,5 @@ - + 4.0.0 @@ -71,6 +70,7 @@ ${jetty.port.file} true true + ${project.groupId}:${project.artifactId} org.eclipse.jetty:jetty-maven-plugin @@ -120,5 +120,4 @@ - diff --git a/jetty-maven-plugin/src/it/jetty-run-war-exploded-mojo-it/jetty-simple-webapp/src/config/jetty.xml b/jetty-maven-plugin/src/it/jetty-run-war-exploded-mojo-it/jetty-simple-webapp/src/config/jetty.xml index 4fb92bbea50..10a800b245d 100644 --- a/jetty-maven-plugin/src/it/jetty-run-war-exploded-mojo-it/jetty-simple-webapp/src/config/jetty.xml +++ b/jetty-maven-plugin/src/it/jetty-run-war-exploded-mojo-it/jetty-simple-webapp/src/config/jetty.xml @@ -1,5 +1,4 @@ - - + diff --git a/jetty-maven-plugin/src/it/jetty-run-war-exploded-mojo-it/jetty-simple-webapp/src/main/webapp/WEB-INF/web.xml b/jetty-maven-plugin/src/it/jetty-run-war-exploded-mojo-it/jetty-simple-webapp/src/main/webapp/WEB-INF/web.xml index 2a5ac4b71bf..30ebb9bfe89 100644 --- a/jetty-maven-plugin/src/it/jetty-run-war-exploded-mojo-it/jetty-simple-webapp/src/main/webapp/WEB-INF/web.xml +++ b/jetty-maven-plugin/src/it/jetty-run-war-exploded-mojo-it/jetty-simple-webapp/src/main/webapp/WEB-INF/web.xml @@ -1,7 +1,4 @@ - + Jetty Simple Webapp run-mojo-it diff --git a/jetty-maven-plugin/src/it/jetty-run-war-exploded-mojo-it/pom.xml b/jetty-maven-plugin/src/it/jetty-run-war-exploded-mojo-it/pom.xml index ad5a29cad54..b6ac179988a 100644 --- a/jetty-maven-plugin/src/it/jetty-run-war-exploded-mojo-it/pom.xml +++ b/jetty-maven-plugin/src/it/jetty-run-war-exploded-mojo-it/pom.xml @@ -1,6 +1,5 @@ - + 4.0.0 diff --git a/jetty-maven-plugin/src/it/jetty-run-war-mojo-it/jetty-simple-base/pom.xml b/jetty-maven-plugin/src/it/jetty-run-war-mojo-it/jetty-simple-base/pom.xml index 0269200449e..bb8d9a26bf9 100644 --- a/jetty-maven-plugin/src/it/jetty-run-war-mojo-it/jetty-simple-base/pom.xml +++ b/jetty-maven-plugin/src/it/jetty-run-war-mojo-it/jetty-simple-base/pom.xml @@ -1,6 +1,5 @@ - + 4.0.0 diff --git a/jetty-maven-plugin/src/it/jetty-run-war-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_mojo_it/HelloServlet.java b/jetty-maven-plugin/src/it/jetty-run-war-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_mojo_it/HelloServlet.java index 1c093c1675c..5cf82ccf88e 100644 --- a/jetty-maven-plugin/src/it/jetty-run-war-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_mojo_it/HelloServlet.java +++ b/jetty-maven-plugin/src/it/jetty-run-war-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_mojo_it/HelloServlet.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,15 +16,14 @@ // ======================================================================== // - package org.eclipse.jetty.its.jetty_run_mojo_it; +import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.io.IOException; /** * @@ -35,11 +34,11 @@ public class HelloServlet { @Override - protected void doGet( HttpServletRequest req, HttpServletResponse resp ) + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - String who = req.getParameter( "name" ); + String who = req.getParameter("name"); - resp.getWriter().write( "Hello " + (who == null ? "unknown" : who) ); + resp.getWriter().write("Hello " + (who == null ? "unknown" : who)); } } diff --git a/jetty-maven-plugin/src/it/jetty-run-war-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_mojo_it/PingServlet.java b/jetty-maven-plugin/src/it/jetty-run-war-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_mojo_it/PingServlet.java index dc1d723151f..48152a7b735 100644 --- a/jetty-maven-plugin/src/it/jetty-run-war-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_mojo_it/PingServlet.java +++ b/jetty-maven-plugin/src/it/jetty-run-war-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_mojo_it/PingServlet.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,26 +16,24 @@ // ======================================================================== // - package org.eclipse.jetty.its.jetty_run_mojo_it; +import java.io.IOException; import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.io.IOException; public class PingServlet extends HttpServlet { @Override - protected void doGet( HttpServletRequest req, HttpServletResponse resp ) + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - String who = req.getParameter( "name" ); + String who = req.getParameter("name"); - resp.getWriter().write( "pong " + (who == null ? "unknown" : who) ); + resp.getWriter().write("pong " + (who == null ? "unknown" : who)); } } diff --git a/jetty-maven-plugin/src/it/jetty-run-war-mojo-it/jetty-simple-webapp/pom.xml b/jetty-maven-plugin/src/it/jetty-run-war-mojo-it/jetty-simple-webapp/pom.xml index 6ab552d13e2..67b31e5a081 100644 --- a/jetty-maven-plugin/src/it/jetty-run-war-mojo-it/jetty-simple-webapp/pom.xml +++ b/jetty-maven-plugin/src/it/jetty-run-war-mojo-it/jetty-simple-webapp/pom.xml @@ -1,6 +1,5 @@ - + 4.0.0 @@ -14,7 +13,6 @@ Jetty :: Simple :: Webapp - ${project.build.directory}/jetty-run-war-port.txt @@ -71,6 +69,7 @@ ${jetty.port.file} true true + ${project.groupId}:${project.artifactId} org.eclipse.jetty:jetty-maven-plugin @@ -120,5 +119,4 @@ - diff --git a/jetty-maven-plugin/src/it/jetty-run-war-mojo-it/jetty-simple-webapp/src/config/jetty.xml b/jetty-maven-plugin/src/it/jetty-run-war-mojo-it/jetty-simple-webapp/src/config/jetty.xml index 4fb92bbea50..10a800b245d 100644 --- a/jetty-maven-plugin/src/it/jetty-run-war-mojo-it/jetty-simple-webapp/src/config/jetty.xml +++ b/jetty-maven-plugin/src/it/jetty-run-war-mojo-it/jetty-simple-webapp/src/config/jetty.xml @@ -1,5 +1,4 @@ - - + diff --git a/jetty-maven-plugin/src/it/jetty-run-war-mojo-it/jetty-simple-webapp/src/main/webapp/WEB-INF/web.xml b/jetty-maven-plugin/src/it/jetty-run-war-mojo-it/jetty-simple-webapp/src/main/webapp/WEB-INF/web.xml index 2a5ac4b71bf..30ebb9bfe89 100644 --- a/jetty-maven-plugin/src/it/jetty-run-war-mojo-it/jetty-simple-webapp/src/main/webapp/WEB-INF/web.xml +++ b/jetty-maven-plugin/src/it/jetty-run-war-mojo-it/jetty-simple-webapp/src/main/webapp/WEB-INF/web.xml @@ -1,7 +1,4 @@ - + Jetty Simple Webapp run-mojo-it diff --git a/jetty-maven-plugin/src/it/jetty-run-war-mojo-it/pom.xml b/jetty-maven-plugin/src/it/jetty-run-war-mojo-it/pom.xml index 96f0c6bc8ef..3ae620b58ad 100644 --- a/jetty-maven-plugin/src/it/jetty-run-war-mojo-it/pom.xml +++ b/jetty-maven-plugin/src/it/jetty-run-war-mojo-it/pom.xml @@ -1,6 +1,5 @@ - + 4.0.0 diff --git a/jetty-maven-plugin/src/it/jetty-start-mojo-it/jetty-simple-base/pom.xml b/jetty-maven-plugin/src/it/jetty-start-mojo-it/jetty-simple-base/pom.xml index dbefb81281d..7f860fc93db 100644 --- a/jetty-maven-plugin/src/it/jetty-start-mojo-it/jetty-simple-base/pom.xml +++ b/jetty-maven-plugin/src/it/jetty-start-mojo-it/jetty-simple-base/pom.xml @@ -1,6 +1,5 @@ - + 4.0.0 diff --git a/jetty-maven-plugin/src/it/jetty-start-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_start_mojo_it/HelloServlet.java b/jetty-maven-plugin/src/it/jetty-start-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_start_mojo_it/HelloServlet.java index f2457ceea25..64df66b845e 100644 --- a/jetty-maven-plugin/src/it/jetty-start-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_start_mojo_it/HelloServlet.java +++ b/jetty-maven-plugin/src/it/jetty-start-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_start_mojo_it/HelloServlet.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,15 +16,14 @@ // ======================================================================== // - package org.eclipse.jetty.its.jetty_start_mojo_it; +import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.io.IOException; /** * @@ -35,11 +34,11 @@ public class HelloServlet { @Override - protected void doGet( HttpServletRequest req, HttpServletResponse resp ) + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - String who = req.getParameter( "name" ); + String who = req.getParameter("name"); - resp.getWriter().write( "Hello " + (who == null ? "unknown" : who) ); + resp.getWriter().write("Hello " + (who == null ? "unknown" : who)); } } diff --git a/jetty-maven-plugin/src/it/jetty-start-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_start_mojo_it/PingServlet.java b/jetty-maven-plugin/src/it/jetty-start-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_start_mojo_it/PingServlet.java index 0ee6afe6cf0..d4718cc2662 100644 --- a/jetty-maven-plugin/src/it/jetty-start-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_start_mojo_it/PingServlet.java +++ b/jetty-maven-plugin/src/it/jetty-start-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_start_mojo_it/PingServlet.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,26 +16,24 @@ // ======================================================================== // - package org.eclipse.jetty.its.jetty_start_mojo_it; +import java.io.IOException; import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.io.IOException; public class PingServlet extends HttpServlet { @Override - protected void doGet( HttpServletRequest req, HttpServletResponse resp ) + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - String who = req.getParameter( "name" ); + String who = req.getParameter("name"); - resp.getWriter().write( "pong " + (who == null ? "unknown" : who) ); + resp.getWriter().write("pong " + (who == null ? "unknown" : who)); } } diff --git a/jetty-maven-plugin/src/it/jetty-start-mojo-it/jetty-simple-webapp/pom.xml b/jetty-maven-plugin/src/it/jetty-start-mojo-it/jetty-simple-webapp/pom.xml index feea2dbd628..9c4cf1d1c51 100644 --- a/jetty-maven-plugin/src/it/jetty-start-mojo-it/jetty-simple-webapp/pom.xml +++ b/jetty-maven-plugin/src/it/jetty-start-mojo-it/jetty-simple-webapp/pom.xml @@ -1,6 +1,5 @@ - + 4.0.0 @@ -69,6 +68,7 @@ ${jetty.port.file} true true + ${project.groupId}:${project.artifactId} org.eclipse.jetty:jetty-maven-plugin @@ -86,13 +86,13 @@ start - + jetty.port.file ${jetty.port.file} - - ${basedir}/src/config/jetty.xml + + ${basedir}/src/config/jetty.xml @@ -100,5 +100,4 @@ - diff --git a/jetty-maven-plugin/src/it/jetty-start-mojo-it/jetty-simple-webapp/src/config/jetty.xml b/jetty-maven-plugin/src/it/jetty-start-mojo-it/jetty-simple-webapp/src/config/jetty.xml index 4fb92bbea50..10a800b245d 100644 --- a/jetty-maven-plugin/src/it/jetty-start-mojo-it/jetty-simple-webapp/src/config/jetty.xml +++ b/jetty-maven-plugin/src/it/jetty-start-mojo-it/jetty-simple-webapp/src/config/jetty.xml @@ -1,5 +1,4 @@ - - + diff --git a/jetty-maven-plugin/src/it/jetty-start-mojo-it/jetty-simple-webapp/src/main/webapp/WEB-INF/web.xml b/jetty-maven-plugin/src/it/jetty-start-mojo-it/jetty-simple-webapp/src/main/webapp/WEB-INF/web.xml index 2a5ac4b71bf..30ebb9bfe89 100644 --- a/jetty-maven-plugin/src/it/jetty-start-mojo-it/jetty-simple-webapp/src/main/webapp/WEB-INF/web.xml +++ b/jetty-maven-plugin/src/it/jetty-start-mojo-it/jetty-simple-webapp/src/main/webapp/WEB-INF/web.xml @@ -1,7 +1,4 @@ - + Jetty Simple Webapp run-mojo-it diff --git a/jetty-maven-plugin/src/it/jetty-start-mojo-it/pom.xml b/jetty-maven-plugin/src/it/jetty-start-mojo-it/pom.xml index bd5cb98a9b7..040eeb56b96 100644 --- a/jetty-maven-plugin/src/it/jetty-start-mojo-it/pom.xml +++ b/jetty-maven-plugin/src/it/jetty-start-mojo-it/pom.xml @@ -1,6 +1,5 @@ - + 4.0.0 diff --git a/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-client/src/main/java/org/olamy/App.java b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-client/src/main/java/org/olamy/App.java index 10c1ab186ab..e6e8d9d8993 100644 --- a/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-client/src/main/java/org/olamy/App.java +++ b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-client/src/main/java/org/olamy/App.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -38,25 +38,27 @@ import com.google.gwt.user.client.ui.VerticalPanel; /** * Entry point classes define onModuleLoad(). */ -public class App implements EntryPoint { - /** - * The message displayed to the user when the server cannot be reached or - * returns an error. - */ - private static final String SERVER_ERROR = "An error occurred while " - + "attempting to contact the server. Please check your network " - + "connection and try again."; +public class App implements EntryPoint +{ + /** + * The message displayed to the user when the server cannot be reached or + * returns an error. + */ + private static final String SERVER_ERROR = "An error occurred while " + + "attempting to contact the server. Please check your network " + + "connection and try again."; /** * Create a remote service proxy to talk to the server-side Greeting service. */ private final GreetingServiceAsync greetingService = GWT - .create(GreetingService.class); + .create(GreetingService.class); /** * This is the entry point method. */ - public void onModuleLoad() { + public void onModuleLoad() + { final Button sendButton = new Button("Send"); final TextBox nameField = new TextBox(); nameField.setText("GWT User"); @@ -95,8 +97,10 @@ public class App implements EntryPoint { dialogBox.setWidget(dialogVPanel); // Add a handler to close the DialogBox - closeButton.addClickHandler(new ClickHandler() { - public void onClick(ClickEvent event) { + closeButton.addClickHandler(new ClickHandler() + { + public void onClick(ClickEvent event) + { dialogBox.hide(); sendButton.setEnabled(true); sendButton.setFocus(true); @@ -104,19 +108,23 @@ public class App implements EntryPoint { }); // Create a handler for the sendButton and nameField - class MyHandler implements ClickHandler, KeyUpHandler { + class MyHandler implements ClickHandler, KeyUpHandler + { /** * Fired when the user clicks on the sendButton. */ - public void onClick(ClickEvent event) { + public void onClick(ClickEvent event) + { sendNameToServer(); } /** * Fired when the user types in the nameField. */ - public void onKeyUp(KeyUpEvent event) { - if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) { + public void onKeyUp(KeyUpEvent event) + { + if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) + { sendNameToServer(); } } @@ -124,11 +132,13 @@ public class App implements EntryPoint { /** * Send the name from the nameField to the server and wait for a response. */ - private void sendNameToServer() { + private void sendNameToServer() + { // First, we validate the input. errorLabel.setText(""); String textToServer = nameField.getText(); - if (!FieldVerifier.isValidName(textToServer)) { + if (!FieldVerifier.isValidName(textToServer)) + { errorLabel.setText("Please enter at least four characters"); return; } @@ -138,33 +148,36 @@ public class App implements EntryPoint { textToServerLabel.setText(textToServer); serverResponseLabel.setText(""); greetingService.greetServer(textToServer, - new AsyncCallback() { - public void onFailure(Throwable caught) { - // Show the RPC error message to the user - dialogBox - .setText("Remote Procedure Call - Failure"); - serverResponseLabel - .addStyleName("serverResponseLabelError"); - serverResponseLabel.setHTML(SERVER_ERROR); - dialogBox.center(); - closeButton.setFocus(true); - } + new AsyncCallback() + { + public void onFailure(Throwable caught) + { + // Show the RPC error message to the user + dialogBox + .setText("Remote Procedure Call - Failure"); + serverResponseLabel + .addStyleName("serverResponseLabelError"); + serverResponseLabel.setHTML(SERVER_ERROR); + dialogBox.center(); + closeButton.setFocus(true); + } - public void onSuccess(GreetingResponse result) { - dialogBox.setText("Remote Procedure Call"); - serverResponseLabel - .removeStyleName("serverResponseLabelError"); - serverResponseLabel.setHTML(new SafeHtmlBuilder() - .appendEscaped(result.getGreeting()) - .appendHtmlConstant("

        I am running ") - .appendEscaped(result.getServerInfo()) - .appendHtmlConstant(".

        It looks like you are using:
        ") - .appendEscaped(result.getUserAgent()) - .toSafeHtml()); - dialogBox.center(); - closeButton.setFocus(true); - } - }); + public void onSuccess(GreetingResponse result) + { + dialogBox.setText("Remote Procedure Call"); + serverResponseLabel + .removeStyleName("serverResponseLabelError"); + serverResponseLabel.setHTML(new SafeHtmlBuilder() + .appendEscaped(result.getGreeting()) + .appendHtmlConstant("

        I am running ") + .appendEscaped(result.getServerInfo()) + .appendHtmlConstant(".

        It looks like you are using:
        ") + .appendEscaped(result.getUserAgent()) + .toSafeHtml()); + dialogBox.center(); + closeButton.setFocus(true); + } + }); } } diff --git a/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/pom.xml b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/pom.xml index eb5310f1eaa..9e6afd3bd7a 100644 --- a/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/pom.xml +++ b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/pom.xml @@ -74,6 +74,7 @@ ${jetty.port.file} Please enter your name + ${project.groupId}:${project.artifactId} org.eclipse.jetty:jetty-maven-plugin diff --git a/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/config/jetty.xml b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/config/jetty.xml index 4fb92bbea50..10a800b245d 100644 --- a/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/config/jetty.xml +++ b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/config/jetty.xml @@ -1,5 +1,4 @@ - - + diff --git a/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/main/java/org/olamy/GreetingServiceImpl.java b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/main/java/org/olamy/GreetingServiceImpl.java index 2b5b84fa242..190f491ce06 100644 --- a/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/main/java/org/olamy/GreetingServiceImpl.java +++ b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/main/java/org/olamy/GreetingServiceImpl.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -25,15 +25,18 @@ import com.google.gwt.user.server.rpc.RemoteServiceServlet; */ @SuppressWarnings("serial") public class GreetingServiceImpl extends RemoteServiceServlet implements - GreetingService { + GreetingService +{ - public GreetingResponse greetServer(String input) throws IllegalArgumentException { + public GreetingResponse greetServer(String input) throws IllegalArgumentException + { // Verify that the input is valid. - if (!FieldVerifier.isValidName(input)) { + if (!FieldVerifier.isValidName(input)) + { // If the input is not valid, throw an IllegalArgumentException back to // the client. throw new IllegalArgumentException( - "Name must be at least 4 characters long"); + "Name must be at least 4 characters long"); } GreetingResponse response = new GreetingResponse(); diff --git a/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-shared/src/main/java/org/olamy/FieldVerifier.java b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-shared/src/main/java/org/olamy/FieldVerifier.java index fb6084995b8..108466ff435 100644 --- a/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-shared/src/main/java/org/olamy/FieldVerifier.java +++ b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-shared/src/main/java/org/olamy/FieldVerifier.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -38,21 +38,24 @@ package org.olamy; * JavaScript (such as Widgets) cannot be run on the server. *

        */ -public class FieldVerifier { +public class FieldVerifier +{ /** * Verifies that the specified name is valid for our service. - * + * * In this example, we only require that the name is at least four * characters. In your application, you can use more complex checks to ensure * that usernames, passwords, email addresses, URLs, and other fields have the * proper syntax. - * + * * @param name the name to validate * @return true if valid, false if invalid */ - public static boolean isValidName(String name) { - if (name == null) { + public static boolean isValidName(String name) + { + if (name == null) + { return false; } return name.length() > 3; diff --git a/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-shared/src/main/java/org/olamy/GreetingResponse.java b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-shared/src/main/java/org/olamy/GreetingResponse.java index 1e98d9918fc..aa92eeb22f8 100644 --- a/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-shared/src/main/java/org/olamy/GreetingResponse.java +++ b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-shared/src/main/java/org/olamy/GreetingResponse.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -21,32 +21,39 @@ package org.olamy; import java.io.Serializable; @SuppressWarnings("serial") -public class GreetingResponse implements Serializable { +public class GreetingResponse implements Serializable +{ private String greeting; private String serverInfo; private String userAgent; - public String getGreeting() { + public String getGreeting() + { return greeting; } - public void setGreeting(String greeting) { + public void setGreeting(String greeting) + { this.greeting = greeting; } - public String getServerInfo() { + public String getServerInfo() + { return serverInfo; } - public void setServerInfo(String serverInfo) { + public void setServerInfo(String serverInfo) + { this.serverInfo = serverInfo; } - public String getUserAgent() { + public String getUserAgent() + { return userAgent; } - public void setUserAgent(String userAgent) { + public void setUserAgent(String userAgent) + { this.userAgent = userAgent; } } diff --git a/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-shared/src/main/java/org/olamy/GreetingService.java b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-shared/src/main/java/org/olamy/GreetingService.java index 286e3723468..d4084b162c8 100644 --- a/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-shared/src/main/java/org/olamy/GreetingService.java +++ b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-shared/src/main/java/org/olamy/GreetingService.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -25,6 +25,7 @@ import com.google.gwt.user.client.rpc.RemoteServiceRelativePath; * The client side stub for the RPC service. */ @RemoteServiceRelativePath("greet") -public interface GreetingService extends RemoteService { +public interface GreetingService extends RemoteService +{ GreetingResponse greetServer(String name) throws IllegalArgumentException; } diff --git a/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-shared/src/main/java/org/olamy/GreetingServiceAsync.java b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-shared/src/main/java/org/olamy/GreetingServiceAsync.java index 164c1537937..7cf480ac432 100644 --- a/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-shared/src/main/java/org/olamy/GreetingServiceAsync.java +++ b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-shared/src/main/java/org/olamy/GreetingServiceAsync.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -23,7 +23,8 @@ import com.google.gwt.user.client.rpc.AsyncCallback; /** * The async counterpart of GreetingService. */ -public interface GreetingServiceAsync { +public interface GreetingServiceAsync +{ void greetServer(String input, AsyncCallback callback) - throws IllegalArgumentException; + throws IllegalArgumentException; } diff --git a/jetty-maven-plugin/src/it/run-mojo-gwt-it/pom.xml b/jetty-maven-plugin/src/it/run-mojo-gwt-it/pom.xml index ee8e2e8247a..9d310560684 100644 --- a/jetty-maven-plugin/src/it/run-mojo-gwt-it/pom.xml +++ b/jetty-maven-plugin/src/it/run-mojo-gwt-it/pom.xml @@ -1,6 +1,5 @@ - + 4.0.0 @@ -47,8 +46,7 @@ org.eclipse.jetty jetty-maven-plugin - - + net.ltgt.gwt.maven diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/AbstractJettyMojo.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/AbstractJettyMojo.java index face6ed10d0..ad7c6b4b667 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/AbstractJettyMojo.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/AbstractJettyMojo.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -62,202 +62,173 @@ public abstract class AbstractJettyMojo extends AbstractMojo /** * Whether or not to include dependencies on the plugin's classpath with <scope>provided</scope> * Use WITH CAUTION as you may wind up with duplicate jars/classes. - * + * * @since jetty-7.5.2 */ @Parameter(defaultValue = "false") protected boolean useProvidedScope; - + /** * List of goals that are NOT to be used - * + * * @since jetty-7.5.2 */ @Parameter protected String[] excludedGoals; - + /** * List of other contexts to set up. Consider using instead - * the <jettyXml> element to specify external jetty xml config file. + * the <jettyXml> element to specify external jetty xml config file. * Optional. - * */ @Parameter protected ContextHandler[] contextHandlers; - + /** * List of security realms to set up. Consider using instead - * the <jettyXml> element to specify external jetty xml config file. + * the <jettyXml> element to specify external jetty xml config file. * Optional. - * */ @Parameter protected LoginService[] loginServices; /** * A RequestLog implementation to use for the webapp at runtime. - * Consider using instead the <jettyXml> element to specify external jetty xml config file. + * Consider using instead the <jettyXml> element to specify external jetty xml config file. * Optional. - * */ @Parameter protected RequestLog requestLog; - + /** * An instance of org.eclipse.jetty.webapp.WebAppContext that represents the webapp. * Use any of its setters to configure the webapp. This is the preferred and most * flexible method of configuration, rather than using the (deprecated) individual * parameters like "tmpDirectory", "contextPath" etc. - * */ @Parameter(alias = "webAppConfig") protected JettyWebAppContext webApp; /** - * The interval in seconds to scan the webapp for changes + * The interval in seconds to scan the webapp for changes * and restart the context if necessary. Ignored if reload * is enabled. Disabled by default. - * */ @Parameter(property = "jetty.scanIntervalSeconds", defaultValue = "0", required = true) protected int scanIntervalSeconds; - + /** * reload can be set to either 'automatic' or 'manual' * * if 'manual' then the context can be reloaded by a linefeed in the console * if 'automatic' then traditional reloading on changed files is enabled. - * */ @Parameter(property = "jetty.reload", defaultValue = "automatic") protected String reload; - /** * File containing system properties to be set before execution - * + * * Note that these properties will NOT override System properties - * that have been set on the command line, by the JVM, or directly + * that have been set on the command line, by the JVM, or directly * in the POM via systemProperties. Optional. - * */ @Parameter(property = "jetty.systemPropertiesFile") protected File systemPropertiesFile; - /** - * System properties to set before execution. - * Note that these properties will NOT override System properties - * that have been set on the command line or by the JVM. They WILL + * System properties to set before execution. + * Note that these properties will NOT override System properties + * that have been set on the command line or by the JVM. They WILL * override System properties that have been set via systemPropertiesFile. * Optional. */ @Parameter protected SystemProperties systemProperties; - - + /** - * Comma separated list of a jetty xml configuration files whose contents + * Comma separated list of a jetty xml configuration files whose contents * will be applied before any plugin configuration. Optional. - * */ - @Parameter(alias="jettyConfig") + @Parameter(alias = "jettyConfig") protected String jettyXml; - - + /** - * Port to listen to stop jetty on executing -DSTOP.PORT=<stopPort> + * Port to listen to stop jetty on executing -DSTOP.PORT=<stopPort> * -DSTOP.KEY=<stopKey> -jar start.jar --stop - * */ @Parameter protected int stopPort; - - + /** - * Key to provide when stopping jetty on executing java -DSTOP.KEY=<stopKey> + * Key to provide when stopping jetty on executing java -DSTOP.KEY=<stopKey> * -DSTOP.PORT=<stopPort> -jar start.jar --stop - * */ @Parameter protected String stopKey; /** * Use the dump() facility of jetty to print out the server configuration to logging - * */ - @Parameter( property="dumponStart", defaultValue="false") + @Parameter(property = "dumponStart", defaultValue = "false") protected boolean dumpOnStart; - - - /** + + /** * Skip this mojo execution. */ - @Parameter(property="jetty.skip", defaultValue="false") + @Parameter(property = "jetty.skip", defaultValue = "false") protected boolean skip; - /** * Location of a context xml configuration file whose contents * will be applied to the webapp AFTER anything in <webApp>.Optional. - * */ - @Parameter(alias="webAppXml") + @Parameter(alias = "webAppXml") protected String contextXml; - /** * The maven project. - * */ - @Parameter(defaultValue="${project}", readonly = true) + @Parameter(defaultValue = "${project}", readonly = true) protected MavenProject project; - /** * The artifacts for the project. - * */ - @Parameter(defaultValue="${project.artifacts}", readonly = true) + @Parameter(defaultValue = "${project.artifacts}", readonly = true) protected Set projectArtifacts; - - - @Parameter(defaultValue="${mojoExecution}", readonly = true) + + @Parameter(defaultValue = "${mojoExecution}", readonly = true) protected MojoExecution execution; /** * The artifacts for the plugin itself. - * */ - @Parameter(defaultValue="${plugin.artifacts}", readonly = true) + @Parameter(defaultValue = "${plugin.artifacts}", readonly = true) protected List pluginArtifacts; /** * A ServerConnector to use. - * */ @Parameter protected MavenServerConnector httpConnector; - - + /** * A wrapper for the Server object */ @Parameter protected Server server; - - + /** * A scanner to check for changes to the webapp */ protected PathWatcher scanner; - /** * A scanner to check ENTER hits on the console */ protected Thread consoleScanner; - + protected ServerSupport serverSupport; /** @@ -265,8 +236,8 @@ public abstract class AbstractJettyMojo extends AbstractMojo * Determines whether or not the server blocks when started. The default * behavior (false) will cause the server to pause other processes * while it continues to handle web requests. This is useful when starting the - * server with the intent to work with it interactively. This is the - * behaviour of the jetty:run, jetty:run-war, jetty:run-war-exploded goals. + * server with the intent to work with it interactively. This is the + * behaviour of the jetty:run, jetty:run-war, jetty:run-war-exploded goals. *

        * If true, the server will not block the execution of subsequent code. This * is the behaviour of the jetty:start and default behaviour of the jetty:deploy goals. @@ -278,21 +249,18 @@ public abstract class AbstractJettyMojo extends AbstractMojo /** * Per default this goal support only war packaging. * If your project use an other type please configure it here. - * */ @Parameter - protected List supportedPackagings = Collections.singletonList( "war"); - - + protected List supportedPackagings = Collections.singletonList("war"); + public abstract void restartWebApp(boolean reconfigureScanner) throws Exception; - public boolean checkPomConfiguration() throws MojoExecutionException { return true; } - public abstract void configureScanner () throws MojoExecutionException; + public abstract void configureScanner() throws MojoExecutionException; protected String getSkipMessage(String reason) { @@ -306,7 +274,7 @@ public abstract class AbstractJettyMojo extends AbstractMojo public boolean checkPackagingConfiguration() { - if (!supportedPackagings.contains( project.getPackaging() )) + if (!supportedPackagings.contains(project.getPackaging())) { getLog().info(getSkipMessage("packaging type [" + project.getPackaging() + "] is unsupported")); return false; @@ -314,8 +282,7 @@ public abstract class AbstractJettyMojo extends AbstractMojo return true; } - - /** + /** * @see org.apache.maven.plugin.Mojo#execute() */ @Override @@ -333,8 +300,8 @@ public abstract class AbstractJettyMojo extends AbstractMojo if (isExcluded(execution.getMojoDescriptor().getGoal())) { - getLog().info("The goal \""+execution.getMojoDescriptor().getFullGoalName()+ - "\" has been made unavailable for this web application by an configuration."); + getLog().info("The goal \"" + execution.getMojoDescriptor().getFullGoalName() + + "\" has been made unavailable for this web application by an configuration."); return; } @@ -343,15 +310,14 @@ public abstract class AbstractJettyMojo extends AbstractMojo startJetty(); } } - + public boolean isConfigurationSupported() throws MojoExecutionException { return (checkPackagingConfiguration() && checkPomConfiguration()); } - - + public void configurePluginClasspath() throws MojoExecutionException - { + { //if we are configured to include the provided dependencies on the plugin's classpath //(which mimics being on jetty's classpath vs being on the webapp's classpath), we first //try and filter out ones that will clash with jars that are plugin dependencies, then @@ -362,21 +328,24 @@ public abstract class AbstractJettyMojo extends AbstractMojo { List provided = new ArrayList<>(); - for ( Artifact artifact : projectArtifacts) - { + for (Artifact artifact : projectArtifacts) + { if (Artifact.SCOPE_PROVIDED.equals(artifact.getScope()) && !isPluginArtifact(artifact)) { provided.add(artifact.getFile().toURI().toURL()); - if (getLog().isDebugEnabled()) { getLog().debug("Adding provided artifact: "+artifact);} + if (getLog().isDebugEnabled()) + { + getLog().debug("Adding provided artifact: " + artifact); + } } } if (!provided.isEmpty()) { URL[] urls = provided.stream().toArray(URL[]::new); - URLClassLoader loader = new URLClassLoader(urls, getClass().getClassLoader()); + URLClassLoader loader = new URLClassLoader(urls, getClass().getClassLoader()); Thread.currentThread().setContextClassLoader(loader); - getLog().info("Plugin classpath augmented with provided dependencies: "+Arrays.toString(urls)); + getLog().info("Plugin classpath augmented with provided dependencies: " + Arrays.toString(urls)); } } catch (MalformedURLException e) @@ -385,62 +354,65 @@ public abstract class AbstractJettyMojo extends AbstractMojo } } } - + public boolean isPluginArtifact(Artifact artifact) { if (pluginArtifacts == null || pluginArtifacts.isEmpty()) return false; - - for (Artifact pluginArtifact : pluginArtifacts ) + + for (Artifact pluginArtifact : pluginArtifacts) { - if (getLog().isDebugEnabled()) { getLog().debug("Checking "+pluginArtifact);} - if (pluginArtifact.getGroupId().equals(artifact.getGroupId()) // - && pluginArtifact.getArtifactId().equals(artifact.getArtifactId())) + if (getLog().isDebugEnabled()) + { + getLog().debug("Checking " + pluginArtifact); + } + if (pluginArtifact.getGroupId().equals(artifact.getGroupId()) && + pluginArtifact.getArtifactId().equals(artifact.getArtifactId())) return true; } - + return false; } public void finishConfigurationBeforeStart() throws Exception { HandlerCollection contexts = server.getChildHandlerByClass(ContextHandlerCollection.class); - if (contexts==null) + if (contexts == null) contexts = server.getChildHandlerByClass(HandlerCollection.class); - - for (int i=0; (this.contextHandlers != null) && (i < this.contextHandlers.length); i++) + + for (int i = 0; (this.contextHandlers != null) && (i < this.contextHandlers.length); i++) { contexts.addHandler(this.contextHandlers[i]); } } public void applyJettyXml() throws Exception - { + { Server tmp = ServerSupport.applyXmlConfigurations(server, getJettyXmlFiles()); if (server == null) server = tmp; - + if (server == null) server = new Server(); } - public void startJetty () throws MojoExecutionException + public void startJetty() throws MojoExecutionException { try { getLog().debug("Starting Jetty Server ..."); - + //make sure Jetty does not use URLConnection caches with the plugin Resource.setDefaultUseCaches(false); - + configureMonitor(); - + printSystemProperties(); - + //apply any config from a jetty.xml file first which is able to //be overwritten by config in the pom.xml - applyJettyXml (); - + applyJettyXml(); + // if a was specified in the pom, use it if (httpConnector != null) { @@ -450,9 +422,9 @@ public abstract class AbstractJettyMojo extends AbstractMojo { //use any jetty.http.port settings provided String tmp = System.getProperty(MavenServerConnector.PORT_SYSPROPERTY, // - System.getProperty("jetty.port", MavenServerConnector.DEFAULT_PORT_STR)); + System.getProperty("jetty.port", MavenServerConnector.DEFAULT_PORT_STR)); httpConnector.setPort(Integer.parseInt(tmp.trim())); - } + } httpConnector.setServer(server); } @@ -460,7 +432,7 @@ public abstract class AbstractJettyMojo extends AbstractMojo //set up a RequestLog if one is provided and the handle structure ServerSupport.configureHandlers(server, this.requestLog); - + //Set up list of default Configurations to apply to a webapp ServerSupport.configureDefaultConfigurationClasses(server); configureWebApplication(); @@ -476,9 +448,9 @@ public abstract class AbstractJettyMojo extends AbstractMojo // start Jetty this.server.start(); - getLog().info( "Started Jetty Server" ); + getLog().info("Started Jetty Server"); - if ( dumpOnStart ) + if (dumpOnStart) { getLog().info(this.server.dump()); } @@ -487,7 +459,7 @@ public abstract class AbstractJettyMojo extends AbstractMojo if (isScanningEnabled()) { scanner = new PathWatcher(); - configureScanner (); + configureScanner(); startScanner(); } @@ -495,11 +467,10 @@ public abstract class AbstractJettyMojo extends AbstractMojo startConsoleScanner(); // keep the thread going if not in daemon mode - if (!nonBlocking ) + if (!nonBlocking) { server.join(); } - } catch (Exception e) { @@ -507,42 +478,36 @@ public abstract class AbstractJettyMojo extends AbstractMojo } finally { - if (!nonBlocking ) + if (!nonBlocking) { getLog().info("Jetty server exiting."); - } - } + } + } } - - + public void configureMonitor() - { - if(stopPort>0 && stopKey!=null) + { + if (stopPort > 0 && stopKey != null) { ShutdownMonitor monitor = ShutdownMonitor.getInstance(); monitor.setPort(stopPort); monitor.setKey(stopKey); - monitor.setExitVm(!nonBlocking ); + monitor.setExitVm(!nonBlocking); } } - - - - - /** * Subclasses should invoke this to setup basic info * on the webapp - * - * @throws Exception if unable to configure web application + * + * @throws Exception if unable to configure web application */ - public void configureWebApplication () throws Exception + public void configureWebApplication() throws Exception { //As of jetty-7, you must use a element if (webApp == null) webApp = new JettyWebAppContext(); - + //Apply any context xml file to set up the webapp //CAUTION: if you've defined a element then the //context xml file can OVERRIDE those settings @@ -555,44 +520,42 @@ public abstract class AbstractJettyMojo extends AbstractMojo path = workDir.resolve(path); contextXml = path.toFile().getAbsolutePath(); } - + XmlConfiguration xmlConfiguration = new XmlConfiguration(Resource.toURL(path.toFile())); - getLog().info("Applying context xml file "+contextXml); - xmlConfiguration.configure(webApp); + getLog().info("Applying context xml file " + contextXml); + xmlConfiguration.configure(webApp); } - + //If no contextPath was specified, go with default of project artifactid String cp = webApp.getContextPath(); if (cp == null || "".equals(cp)) { - cp = "/"+project.getArtifactId(); + cp = "/" + project.getArtifactId(); webApp.setContextPath(cp); - } + } //If no tmp directory was specified, and we have one, use it if (webApp.getTempDirectory() == null) { File target = new File(project.getBuild().getDirectory()); - File tmp = new File(target,"tmp"); + File tmp = new File(target, "tmp"); if (!tmp.exists()) - tmp.mkdirs(); + tmp.mkdirs(); webApp.setTempDirectory(tmp); } - + getLog().info("Context path = " + webApp.getContextPath()); - getLog().info("Tmp directory = "+ (webApp.getTempDirectory()== null? " determined at runtime": webApp.getTempDirectory())); - getLog().info("Web defaults = "+(webApp.getDefaultsDescriptor()==null?" jetty default":webApp.getDefaultsDescriptor())); - getLog().info("Web overrides = "+(webApp.getOverrideDescriptor()==null?" none":webApp.getOverrideDescriptor())); + getLog().info("Tmp directory = " + (webApp.getTempDirectory() == null ? " determined at runtime" : webApp.getTempDirectory())); + getLog().info("Web defaults = " + (webApp.getDefaultsDescriptor() == null ? " jetty default" : webApp.getDefaultsDescriptor())); + getLog().info("Web overrides = " + (webApp.getOverrideDescriptor() == null ? " none" : webApp.getOverrideDescriptor())); } - - - /** * Run a scanner thread on the given list of files and directories, calling * stop/start on the given list of LifeCycle objects if any of the watched * files change. - * @throws Exception if unable to start scanner + * + * @throws Exception if unable to start scanner */ public void startScanner() throws Exception { @@ -600,53 +563,50 @@ public abstract class AbstractJettyMojo extends AbstractMojo return; scanner.setNotifyExistingOnStart(false); - - + scanner.start(); } - - - public boolean isScanningEnabled () + + public boolean isScanningEnabled() { - if (scanIntervalSeconds <=0 || "manual".equalsIgnoreCase( reload )) - return false; - return true; + return scanIntervalSeconds > 0 && !"manual".equalsIgnoreCase(reload); } - + public void stopScanner() throws Exception { if (!isScanningEnabled()) return; - + if (scanner != null) scanner.stop(); } - - + /** * Run a thread that monitors the console input to detect ENTER hits. + * * @throws Exception if unable to start the console */ protected void startConsoleScanner() throws Exception { - if ( "manual".equalsIgnoreCase( reload ) ) + if ("manual".equalsIgnoreCase(reload)) { getLog().info("Console reloading is ENABLED. Hit ENTER on the console to restart the context."); consoleScanner = new ConsoleScanner(this); consoleScanner.start(); - } + } } - protected void printSystemProperties () + protected void printSystemProperties() { // print out which system properties were set up if (getLog().isDebugEnabled()) { if (systemProperties != null) { - systemProperties.getSystemProperties().stream().forEach( prop -> { - getLog().debug("Property "+prop.getName()+"="+prop.getValue()+" was "+ (prop.isSet() ? "set" : "skipped")); - } ); + systemProperties.getSystemProperties().stream().forEach(prop -> + { + getLog().debug("Property " + prop.getName() + "=" + prop.getValue() + " was " + (prop.isSet() ? "set" : "skipped")); + }); } } } @@ -654,25 +614,26 @@ public abstract class AbstractJettyMojo extends AbstractMojo /** * Try and find a jetty-web.xml file, using some * historical naming conventions if necessary. + * * @param webInfDir the web inf directory * @return the jetty web xml file */ - public File findJettyWebXmlFile (File webInfDir) + public File findJettyWebXmlFile(File webInfDir) { if (webInfDir == null) return null; if (!webInfDir.exists()) return null; - File f = new File (webInfDir, "jetty-web.xml"); + File f = new File(webInfDir, "jetty-web.xml"); if (f.exists()) return f; //try some historical alternatives - f = new File (webInfDir, "web-jetty.xml"); + f = new File(webInfDir, "web-jetty.xml"); if (f.exists()) return f; - + return null; } @@ -684,78 +645,78 @@ public abstract class AbstractJettyMojo extends AbstractMojo { properties.load(propFile); } - if (this.systemProperties == null ) + if (this.systemProperties == null) this.systemProperties = new SystemProperties(); - - for (Enumeration keys = properties.keys(); keys.hasMoreElements(); ) + + for (Enumeration keys = properties.keys(); keys.hasMoreElements(); ) { String key = (String)keys.nextElement(); - if ( ! systemProperties.containsSystemProperty(key) ) + if (!systemProperties.containsSystemProperty(key)) { SystemProperty prop = new SystemProperty(); prop.setKey(key); prop.setValue(properties.getProperty(key)); - + this.systemProperties.setSystemProperty(prop); } - } + } } - + public void setSystemProperties(SystemProperties systemProperties) { if (this.systemProperties == null) this.systemProperties = systemProperties; else { - for (SystemProperty prop: systemProperties.getSystemProperties()) + for (SystemProperty prop : systemProperties.getSystemProperties()) { this.systemProperties.setSystemProperty(prop); - } + } } } - + public List getJettyXmlFiles() { - if ( this.jettyXml == null ) + if (this.jettyXml == null) { return null; } - + List jettyXmlFiles = new ArrayList(); - - if ( this.jettyXml.indexOf(',') == -1 ) + + if (this.jettyXml.indexOf(',') == -1) { - jettyXmlFiles.add( new File( this.jettyXml ) ); + jettyXmlFiles.add(new File(this.jettyXml)); } else { String[] files = StringUtil.csvSplit(this.jettyXml); - - for ( String file : files ) + + for (String file : files) { - jettyXmlFiles.add( new File(file) ); + jettyXmlFiles.add(new File(file)); } } - + return jettyXmlFiles; } - public boolean isExcluded (String goal) + public boolean isExcluded(String goal) { if (excludedGoals == null || goal == null) return false; - + goal = goal.trim(); if ("".equals(goal)) return false; - + boolean excluded = false; - for (int i=0; i 0) { + + private void checkSystemInput() throws IOException + { + while (System.in.available() > 0) + { int inputByte = System.in.read(); - if (inputByte >= 0) + if (inputByte >= 0) { char c = (char)inputByte; - if (c == '\n') { + if (c == '\n') + { restartWebApp(); } } } } - + /** * Skip buffered bytes of system console. */ - private void clearInputBuffer() + private void clearInputBuffer() { try { @@ -102,9 +104,9 @@ public class ConsoleScanner extends Thread catch (IOException e) { mojo.getLog().warn("Error discarding console input buffer", e); - } + } } - + private void restartWebApp() { try @@ -117,8 +119,8 @@ public class ConsoleScanner extends Thread catch (Exception e) { mojo.getLog().error( - "Error reconfiguring/restarting webapp after a new line on the console", - e); + "Error reconfiguring/restarting webapp after a new line on the console", + e); } } } diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyDeployWar.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyDeployWar.java index bc608a2bc9e..6e414007d2a 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyDeployWar.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyDeployWar.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -31,35 +31,31 @@ import org.apache.maven.plugins.annotations.ResolutionScope; * This goal is used to run Jetty with a pre-assembled war. *

        *

        - * It accepts exactly the same options as the run-war goal. + * It accepts exactly the same options as the run-war goal. * However, it doesn't assume that the current artifact is a - * webapp and doesn't try to assemble it into a war before its execution. - * So using it makes sense only when used in conjunction with the + * webapp and doesn't try to assemble it into a war before its execution. + * So using it makes sense only when used in conjunction with the * war configuration parameter pointing to a pre-built WAR. *

        *

        - * This goal is useful e.g. for launching a web app in Jetty as a target for unit-tested + * This goal is useful e.g. for launching a web app in Jetty as a target for unit-tested * HTTP client components. *

        * Deploy a pre-assembled war - * */ -@Mojo( name = "deploy-war", requiresDependencyResolution = ResolutionScope.RUNTIME) +@Mojo(name = "deploy-war", requiresDependencyResolution = ResolutionScope.RUNTIME) @Execute(phase = LifecyclePhase.VALIDATE) public class JettyDeployWar extends JettyRunWarMojo { - /** * If true, the plugin should continue and not block. Otherwise the * plugin will block further execution and you will need to use * cntrl-c to stop it. - * */ @Parameter(defaultValue = "true") protected boolean daemon = true; - - + @Override public void execute() throws MojoExecutionException, MojoFailureException { @@ -67,14 +63,11 @@ public class JettyDeployWar extends JettyRunWarMojo super.execute(); } - - @Override public void finishConfigurationBeforeStart() throws Exception { super.finishConfigurationBeforeStart(); //only stop the server at shutdown if we are blocking - server.setStopAtShutdown(!nonBlocking ); + server.setStopAtShutdown(!nonBlocking); } - } diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyEffectiveWebXml.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyEffectiveWebXml.java index 8208290abea..24ee46dec34 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyEffectiveWebXml.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyEffectiveWebXml.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,7 +16,6 @@ // ======================================================================== // - package org.eclipse.jetty.maven.plugin; import java.io.File; @@ -39,12 +38,12 @@ import org.eclipse.jetty.util.thread.QueuedThreadPool; * a comprehensive web.xml that combines all information from annotations, webdefault.xml and all web-fragment.xml * files. By default, the web.xml is generated to the console output only. Use the effectiveWebXml parameter * to provide a file name into which to save the output. - * + * * See http://www.eclipse.org/jetty/documentation for more information on this and other jetty plugins. * * Runs jetty on the unassembled webapp to generate the effective web.xml */ -@Mojo( name = "effective-web-xml", requiresDependencyResolution = ResolutionScope.TEST) +@Mojo(name = "effective-web-xml", requiresDependencyResolution = ResolutionScope.TEST) @Execute(phase = LifecyclePhase.TEST_COMPILE) public class JettyEffectiveWebXml extends JettyRunMojo { @@ -53,16 +52,14 @@ public class JettyEffectiveWebXml extends JettyRunMojo */ @Parameter(defaultValue = "${project.build.directory}", readonly = true, required = true) protected File target; - + /** * The name of the file to generate into - * */ @Parameter protected File effectiveWebXml; protected boolean deleteOnExit = true; - /** * @see org.apache.maven.plugin.Mojo#execute() @@ -72,35 +69,33 @@ public class JettyEffectiveWebXml extends JettyRunMojo { super.execute(); } - - + @Override public void startJetty() throws MojoExecutionException { //Only do enough setup to be able to produce a quickstart-web.xml file QueuedThreadPool tpool = null; - + try { printSystemProperties(); //apply any config from a jetty.xml file first to our "fake" server instance //TODO probably not necessary - applyJettyXml (); - + applyJettyXml(); + ServerSupport.configureHandlers(server, null); ServerSupport.configureDefaultConfigurationClasses(server); - + //ensure config of the webapp based on settings in plugin configureWebApplication(); - + //set the webapp up to do very little other than generate the quickstart-web.xml webApp.setCopyWebDir(false); webApp.setCopyWebInf(false); webApp.setGenerateQuickStart(true); - //if the user didn't nominate a file to generate into, pick the name and //make sure that it is deleted on exit if (webApp.getQuickStartWebDescriptor() == null) @@ -121,9 +116,9 @@ public class JettyEffectiveWebXml extends JettyRunMojo webApp.setQuickStartWebDescriptor(descriptor); } - + ServerSupport.addWebApplication(server, webApp); - + //if our server has a thread pool associated we can do any annotation scanning multithreaded, //otherwise scanning will be single threaded tpool = server.getBean(QueuedThreadPool.class); @@ -131,9 +126,8 @@ public class JettyEffectiveWebXml extends JettyRunMojo tpool.start(); else webApp.setAttribute(AnnotationConfiguration.MULTI_THREADED, Boolean.FALSE.toString()); - - webApp.start(); //just enough to generate the quickstart - + + webApp.start(); //just enough to generate the quickstart } catch (Exception e) { @@ -141,12 +135,24 @@ public class JettyEffectiveWebXml extends JettyRunMojo } finally { - try {webApp.stop();}catch (Exception x) {}; - - try {if (tpool != null) tpool.stop();} catch (Exception x) {}; + try + { + webApp.stop(); + } + catch (Exception ignored) + { + } + + try + { + if (tpool != null) + tpool.stop(); + } + catch (Exception ignored) + { + } } - - + if (deleteOnExit) { try @@ -156,10 +162,8 @@ public class JettyEffectiveWebXml extends JettyRunMojo } catch (IOException e) { - throw new MojoExecutionException("Unable to output effective web.xml", e); + throw new MojoExecutionException("Unable to output effective web.xml", e); } - } - } } diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunDistro.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunDistro.java index 1a1fc463be4..aa02c304aca 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunDistro.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunDistro.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,7 +16,6 @@ // ======================================================================== // - package org.eclipse.jetty.maven.plugin; import java.io.File; @@ -66,87 +65,76 @@ import org.eclipse.jetty.util.resource.JarResource; import org.eclipse.jetty.util.resource.Resource; /** - * * This goal is used to deploy the unassembled webapp into a jetty distribution. If the location - * of an existing unpacked distribution is not supplied as the configuration param jettyHome, + * of an existing unpacked distribution is not supplied as the configuration param jettyHome, * this goal will download and unpack the jetty distro matching the version of this plugin before deploying the webapp. - * + * * The webapp will execute in the distro in a forked process. - * + * * The stopKey, stopPort configuration elements can be used to control the stopping of the forked process. By default, this plugin will launch * the forked jetty instance and wait for it to complete (in which case it acts much like the jetty:run goal, and you will need to Cntrl-C to stop). * By setting the configuration element waitForChild to false, the plugin will terminate after having forked the jetty process. In this case * you can use the jetty:stop goal to terminate the process. - * + * * This goal does NOT support the scanIntervalSeconds parameter: the webapp will be deployed only once. - * + * * See http://www.eclipse.org/jetty/documentation for more information on this and other jetty plugins. - * + * * Runs unassembled webapp in a locally installed jetty distro - * */ -@Mojo( name = "run-distro", requiresDependencyResolution = ResolutionScope.TEST) +@Mojo(name = "run-distro", requiresDependencyResolution = ResolutionScope.TEST) @Execute(phase = LifecyclePhase.TEST_COMPILE) public class JettyRunDistro extends JettyRunMojo { - + public static final String JETTY_HOME_GROUPID = "org.eclipse.jetty"; public static final String JETTY_HOME_ARTIFACTID = "jetty-home"; - - + /** * This plugin */ @Parameter(defaultValue = "${plugin}", required = true, readonly = true) protected PluginDescriptor plugin; - + /** * The target directory */ @Parameter(defaultValue = "${project.build.directory}", readonly = true, required = true) protected File target; - - + /** * Optional jetty.home dir - * */ @Parameter private File jettyHome; - - + /** * Optional jetty.base dir - * */ @Parameter private File jettyBase; - + /** * Optional list of other modules to * activate. */ @Parameter private String[] modules; - + /** * Arbitrary jvm args to pass to the forked process - * */ @Parameter(property = "jetty.jvmArgs") private String jvmArgs; - + /** * Extra environment variables to be passed to the forked process - * */ @Parameter - private Map env = new HashMap<>(); - - + private Map env = new HashMap<>(); + /** * Optional list of jetty properties to put on the command line - * */ @Parameter private String[] jettyProperties; @@ -156,51 +144,48 @@ public class JettyRunDistro extends JettyRunMojo /** * The project's remote repositories to use for the resolution. - * */ - @Parameter(defaultValue="${project.remoteArtifactRepositories}", required = true, readonly = true) + @Parameter(defaultValue = "${project.remoteArtifactRepositories}", required = true, readonly = true) private List remoteRepositories; @Component private ArtifactResolver artifactResolver; - - @Parameter( defaultValue="${plugin.version}", readonly = true) + @Parameter(defaultValue = "${plugin.version}", readonly = true) private String pluginVersion; - - + /** * Whether to wait for the child to finish or not. - * */ - @Parameter(defaultValue="true") + @Parameter(defaultValue = "true") private boolean waitForChild; - + /** * Max number of times to try checking if the * child has started successfully. - * */ - @Parameter(defaultValue="10") + @Parameter(defaultValue = "10") private int maxChildChecks; - + /** * Millisecs to wait between each * check to see if the child started successfully. */ - @Parameter(defaultValue="100") + @Parameter(defaultValue = "100") private long maxChildCheckInterval; - + private File targetBase; - + private List libExtJars; - + private Random random; - + private Path tokenFile; - - - /** + + @Parameter(property = "jetty.javaPath") + private String javaPath; + + /** * @see org.eclipse.jetty.maven.plugin.JettyRunMojo#execute() */ @Override @@ -211,7 +196,7 @@ public class JettyRunDistro extends JettyRunMojo if (pdeps != null && !pdeps.isEmpty()) { boolean warned = false; - for (Dependency d:pdeps) + for (Dependency d : pdeps) { if (d.getGroupId().equalsIgnoreCase("org.eclipse.jetty")) { @@ -228,14 +213,12 @@ public class JettyRunDistro extends JettyRunMojo libExtJars.add(d); } } - } super.execute(); } - - /** + /** * @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#startJetty() */ @Override @@ -246,7 +229,7 @@ public class JettyRunDistro extends JettyRunMojo try { printSystemProperties(); - + //download and install jetty-home if necessary configureJettyHome(); @@ -258,9 +241,7 @@ public class JettyRunDistro extends JettyRunMojo //create the command to run the new process ProcessBuilder command = configureCommand(); - - - + if (waitForChild) { command.inheritIO(); @@ -270,9 +251,9 @@ public class JettyRunDistro extends JettyRunMojo command.redirectOutput(new File(target, "jetty.out")); command.redirectErrorStream(true); } - + Process process = command.start(); - + if (waitForChild) //keep executing until the child dies process.waitFor(); @@ -282,26 +263,23 @@ public class JettyRunDistro extends JettyRunMojo int attempts = maxChildChecks; while (!Files.exists(tokenFile) && attempts > 0) { - Thread.currentThread().sleep(maxChildCheckInterval); + Thread.sleep(maxChildCheckInterval); --attempts; } - if (attempts <=0 ) + if (attempts <= 0) getLog().info("Couldn't verify success of child startup"); } - } catch (Exception e) { throw new MojoExecutionException("Failed to start Jetty", e); } - } - /** * If jetty home does not exist, download it and * unpack to build dir. - * + * * @throws Exception if jetty distribution cannot be found neither downloaded */ public void configureJettyHome() throws Exception @@ -309,25 +287,24 @@ public class JettyRunDistro extends JettyRunMojo if (jettyHome == null) { //no jetty home, download from repo and unpack it. Get the same version as the plugin - Artifact jettyHomeArtifact = resolveArtifact(JETTY_HOME_GROUPID, JETTY_HOME_ARTIFACTID, pluginVersion, "zip"); - JarResource res = (JarResource) JarResource.newJarResource(Resource.newResource(jettyHomeArtifact.getFile())); + Artifact jettyHomeArtifact = resolveArtifact(JETTY_HOME_GROUPID, JETTY_HOME_ARTIFACTID, pluginVersion, "zip"); + JarResource res = (JarResource)JarResource.newJarResource(Resource.newResource(jettyHomeArtifact.getFile())); res.copyTo(target); //zip will unpack to target/jetty-home- - jettyHome = new File (target, JETTY_HOME_ARTIFACTID+"-"+pluginVersion); + jettyHome = new File(target, JETTY_HOME_ARTIFACTID + "-" + pluginVersion); } else { - if (!jettyHome.exists()) - throw new IllegalStateException(jettyHome.getAbsolutePath()+" does not exist"); + if (!jettyHome.exists()) + throw new IllegalStateException(jettyHome.getAbsolutePath() + " does not exist"); } - - getLog().info("jetty.home = "+jettyHome.getAbsolutePath()); - } + getLog().info("jetty.home = " + jettyHome.getAbsolutePath()); + } /** * Resolve an Artifact from remote repo if necessary. - * + * * @param groupId the groupid of the artifact * @param artifactId the artifactId of the artifact * @param version the version of the artifact @@ -335,8 +312,8 @@ public class JettyRunDistro extends JettyRunMojo * @return the artifact from the local or remote repo * @throws ArtifactResolverException in case of an error while resolving the artifact */ - public Artifact resolveArtifact (String groupId, String artifactId, String version, String extension) - throws ArtifactResolverException + public Artifact resolveArtifact(String groupId, String artifactId, String version, String extension) + throws ArtifactResolverException { DefaultArtifactCoordinate coordinate = new DefaultArtifactCoordinate(); coordinate.setGroupId(groupId); @@ -349,66 +326,65 @@ public class JettyRunDistro extends JettyRunMojo buildingRequest.setRemoteRepositories(remoteRepositories); - return artifactResolver.resolveArtifact( buildingRequest, coordinate ).getArtifact(); + return artifactResolver.resolveArtifact(buildingRequest, coordinate).getArtifact(); } /** * Create or configure a jetty base. - * + * * @throws Exception if any error occurred while copying files */ public void configureJettyBase() throws Exception { if (jettyBase != null && !jettyBase.exists()) - throw new IllegalStateException(jettyBase.getAbsolutePath() +" does not exist"); - + throw new IllegalStateException(jettyBase.getAbsolutePath() + " does not exist"); + targetBase = new File(target, "jetty-base"); Path targetBasePath = targetBase.toPath(); Files.deleteIfExists(targetBase.toPath()); targetBase.mkdirs(); - + if (jettyBase != null) { Path jettyBasePath = jettyBase.toPath(); - + //copy the existing jetty base - Files.walkFileTree(jettyBasePath,EnumSet.of(FileVisitOption.FOLLOW_LINKS), - Integer.MAX_VALUE, - new SimpleFileVisitor() - { - /** - * @see java.nio.file.SimpleFileVisitor#preVisitDirectory(java.lang.Object, java.nio.file.attribute.BasicFileAttributes) - */ - @Override - public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException + Files.walkFileTree(jettyBasePath, EnumSet.of(FileVisitOption.FOLLOW_LINKS), + Integer.MAX_VALUE, + new SimpleFileVisitor() { - Path targetDir = targetBasePath.resolve(jettyBasePath.relativize(dir)); - try + /** + * @see java.nio.file.SimpleFileVisitor#preVisitDirectory(java.lang.Object, java.nio.file.attribute.BasicFileAttributes) + */ + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { - Files.copy(dir, targetDir); - } - catch (FileAlreadyExistsException e) - { - if (!Files.isDirectory(targetDir)) //ignore attempt to recreate dir + Path targetDir = targetBasePath.resolve(jettyBasePath.relativize(dir)); + try + { + Files.copy(dir, targetDir); + } + catch (FileAlreadyExistsException e) + { + if (!Files.isDirectory(targetDir)) //ignore attempt to recreate dir throw e; + } + return FileVisitResult.CONTINUE; } - return FileVisitResult.CONTINUE; - } - /** - * @see java.nio.file.SimpleFileVisitor#visitFile(java.lang.Object, java.nio.file.attribute.BasicFileAttributes) - */ - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException - { - if (contextXml != null && Files.isSameFile(Paths.get(contextXml), file)) - return FileVisitResult.CONTINUE; //skip copying the context xml file - Files.copy(file, targetBasePath.resolve(jettyBasePath.relativize(file))); - return FileVisitResult.CONTINUE; - } - - }); + /** + * @see java.nio.file.SimpleFileVisitor#visitFile(java.lang.Object, java.nio.file.attribute.BasicFileAttributes) + */ + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException + { + if (contextXml != null && Files.isSameFile(Paths.get(contextXml), file)) + return FileVisitResult.CONTINUE; //skip copying the context xml file + Files.copy(file, targetBasePath.resolve(jettyBasePath.relativize(file))); + return FileVisitResult.CONTINUE; + } + }); } //make the jetty base structure @@ -423,135 +399,141 @@ public class JettyRunDistro extends JettyRunMojo if (thisJar == null) throw new IllegalStateException("Can't find jar for jetty-maven-plugin"); - try(InputStream jarStream = thisJar.toURL().openStream(); - FileOutputStream fileStream = new FileOutputStream(mavenLibPath.resolve("plugin.jar").toFile())) + try (InputStream jarStream = thisJar.toURL().openStream(); + FileOutputStream fileStream = new FileOutputStream(mavenLibPath.resolve("plugin.jar").toFile())) { - IO.copy(jarStream,fileStream); + IO.copy(jarStream, fileStream); } //copy in the maven.xml webapp file - try (InputStream mavenXmlStream = getClass().getClassLoader().getResourceAsStream("maven.xml"); + try (InputStream mavenXmlStream = getClass().getClassLoader().getResourceAsStream("maven.xml"); FileOutputStream fileStream = new FileOutputStream(webappPath.resolve("maven.xml").toFile())) { IO.copy(mavenXmlStream, fileStream); } - + //copy in the maven.mod file try (InputStream mavenModStream = getClass().getClassLoader().getResourceAsStream("maven.mod"); - FileOutputStream fileStream = new FileOutputStream(modulesPath.resolve("maven.mod").toFile())) + FileOutputStream fileStream = new FileOutputStream(modulesPath.resolve("maven.mod").toFile())) { IO.copy(mavenModStream, fileStream); } - + //copy in the jetty-maven.xml file try (InputStream jettyMavenStream = getClass().getClassLoader().getResourceAsStream("jetty-maven.xml"); - FileOutputStream fileStream = new FileOutputStream(etcPath.resolve("jetty-maven.xml").toFile())) + FileOutputStream fileStream = new FileOutputStream(etcPath.resolve("jetty-maven.xml").toFile())) { IO.copy(jettyMavenStream, fileStream); } - + //if there were plugin dependencies, copy them into lib/ext if (libExtJars != null && !libExtJars.isEmpty()) { Path libExtPath = Files.createDirectories(libPath.resolve("ext")); - for (Dependency d:libExtJars) + for (Dependency d : libExtJars) { Artifact a = resolveArtifact(d.getGroupId(), d.getArtifactId(), d.getVersion(), d.getType()); try (InputStream jarStream = new FileInputStream(a.getFile()); - FileOutputStream fileStream = new FileOutputStream(libExtPath.resolve(d.getGroupId()+"."+d.getArtifactId()+"-"+d.getVersion()+"."+d.getType()).toFile())) + FileOutputStream fileStream = new FileOutputStream(libExtPath.resolve(d.getGroupId() + "." + d.getArtifactId() + "-" + d.getVersion() + "." + d.getType()).toFile())) { IO.copy(jarStream, fileStream); } } } - + //create properties file that describes the webapp createPropertiesFile(etcPath.resolve("maven.props").toFile()); } - - + /** * Convert webapp config to properties - * + * * @param file the file to place the properties into * @throws Exception if any I/O exception during generating the properties file */ - public void createPropertiesFile (File file) - throws Exception + public void createPropertiesFile(File file) + throws Exception { WebAppPropertyConverter.toProperties(webApp, file, contextXml); } - - + /** * Make the command to spawn a process to * run jetty from a distro. - * + * * @return the command configured */ public ProcessBuilder configureCommand() { List cmd = new ArrayList<>(); - cmd.add("java"); + if (StringUtil.isNotBlank(javaPath)) + { + cmd.add(javaPath); + } + else + { + cmd.add(getJavaBin()); + } cmd.add("-jar"); cmd.add(new File(jettyHome, "start.jar").getAbsolutePath()); - - cmd.add("-DSTOP.PORT="+stopPort); + + cmd.add("-DSTOP.PORT=" + stopPort); if (stopKey != null) - cmd.add("-DSTOP.KEY="+stopKey); - + cmd.add("-DSTOP.KEY=" + stopKey); + //add any args to the jvm if (jvmArgs != null) { String[] args = jvmArgs.split(" "); - for (String a:args) + for (String a : args) { if (!StringUtil.isBlank(a)) cmd.add(a.trim()); } } - + //set up enabled jetty modules StringBuilder tmp = new StringBuilder(); tmp.append("--module="); tmp.append("server,http,webapp,deploy"); if (modules != null) { - for (String m:modules) + for (String m : modules) { if (tmp.indexOf(m) < 0) - tmp.append(","+m); + tmp.append("," + m); } } - + if (libExtJars != null && !libExtJars.isEmpty() && tmp.indexOf("ext") < 0) tmp.append(",ext"); tmp.append(",maven"); cmd.add(tmp.toString()); - + //put any jetty properties onto the command line if (jettyProperties != null) { - for (String p:jettyProperties) + for (String p : jettyProperties) + { cmd.add(p); + } } - + //existence of this file signals process started - tokenFile = target.toPath().resolve(createToken()+".txt"); - cmd.add("jetty.token.file="+tokenFile.toAbsolutePath().toString()); + tokenFile = target.toPath().resolve(createToken() + ".txt"); + cmd.add("jetty.token.file=" + tokenFile.toAbsolutePath().toString()); ProcessBuilder builder = new ProcessBuilder(cmd); builder.directory(targetBase); - + //set up extra environment vars if there are any if (!env.isEmpty()) builder.environment().putAll(env); return builder; } - - /** + /** * @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#startScanner() */ @Override @@ -560,9 +542,7 @@ public class JettyRunDistro extends JettyRunMojo //don't scan } - - - /** + /** * @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#stopScanner() */ @Override @@ -571,9 +551,7 @@ public class JettyRunDistro extends JettyRunMojo //don't scan } - - - /** + /** * @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#restartWebApp(boolean) */ @Override @@ -582,7 +560,7 @@ public class JettyRunDistro extends JettyRunMojo //do nothing } - /** + /** * @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#configureScanner() */ @Override @@ -590,11 +568,9 @@ public class JettyRunDistro extends JettyRunMojo { //do nothing } - - private String createToken () - { - return Long.toString(random.nextLong()^System.currentTimeMillis(), 36).toUpperCase(Locale.ENGLISH); - } - + private String createToken() + { + return Long.toString(random.nextLong() ^ System.currentTimeMillis(), 36).toUpperCase(Locale.ENGLISH); + } } diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunForkedMojo.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunForkedMojo.java index e0df458fdf9..d6fe1298ef8 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunForkedMojo.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunForkedMojo.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -44,16 +44,16 @@ import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; import org.eclipse.jetty.annotations.AnnotationConfiguration; import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.thread.QueuedThreadPool; - /** * This goal is used to deploy your unassembled webapp into a forked JVM. *

        * You need to define a jetty.xml file to configure connectors etc. You can use the normal setters of o.e.j.webapp.WebAppContext on the webApp * configuration element for this plugin. You may also need context xml file for any particularly complex webapp setup. - * + * *

        * Unlike the other jetty goals, this does NOT support the scanIntervalSeconds parameter: the webapp will be deployed only once. *

        @@ -63,86 +63,75 @@ import org.eclipse.jetty.util.thread.QueuedThreadPool; * you can use the jetty:stop goal to terminate the process. *

        * See http://www.eclipse.org/jetty/documentation for more information on this and other jetty plugins. - * - * Runs Jetty in forked JVM on an unassembled webapp * + * Runs Jetty in forked JVM on an unassembled webapp */ -@Mojo( name = "run-forked", requiresDependencyResolution = ResolutionScope.TEST) +@Mojo(name = "run-forked", requiresDependencyResolution = ResolutionScope.TEST) @Execute(phase = LifecyclePhase.TEST_COMPILE) public class JettyRunForkedMojo extends JettyRunMojo -{ +{ /** * The target directory */ - @Parameter(defaultValue="${project.build.directory}", readonly = true, required = true) + @Parameter(defaultValue = "${project.build.directory}", readonly = true, required = true) protected File target; - + /** * The file into which to generate the quickstart web xml for the forked process to use - * */ - @Parameter(defaultValue="${project.build.directory}/fork-web.xml") + @Parameter(defaultValue = "${project.build.directory}/fork-web.xml") protected File forkWebXml; - - + /** * Arbitrary jvm args to pass to the forked process - * */ - @Parameter(property="jetty.jvmArgs") + @Parameter(property = "jetty.jvmArgs") private String jvmArgs; - - + /** * Optional list of jetty properties to put on the command line - * */ @Parameter private String[] jettyProperties; - - @Parameter(defaultValue="${plugin.artifacts}",readonly = true) + + @Parameter(defaultValue = "${plugin.artifacts}", readonly = true) private List pluginArtifacts; - @Parameter(defaultValue="${plugin}", readonly = true) + @Parameter(defaultValue = "${plugin}", readonly = true) private PluginDescriptor plugin; - @Parameter(defaultValue="true") + @Parameter(defaultValue = "true") private boolean waitForChild; - /** * Max number of times to try checking if the * child has started successfully. - * */ - @Parameter(alias="maxStartupLines", defaultValue="50") + @Parameter(alias = "maxStartupLines", defaultValue = "50") private int maxChildChecks; - + /** * Millisecs to wait between each * check to see if the child started successfully. */ - @Parameter(defaultValue="100") + @Parameter(defaultValue = "100") private long maxChildCheckInterval; - + /** * Extra environment variables to be passed to the forked process - * */ @Parameter - private Map env = new HashMap<>(); + private Map env = new HashMap<>(); /** * The forked jetty instance */ private Process forkedProcess; - - + /** * Random number generator */ - private Random random; - + private Random random; /** * Whether or not the plugin has explicit slf4j dependencies. @@ -151,12 +140,12 @@ public class JettyRunForkedMojo extends JettyRunMojo * pom has an explicit dependency on it. */ private boolean hasSlf4jDeps; - + + @Parameter(property = "jetty.javaPath") + private String javaPath; /** * ShutdownThread - * - * */ public class ShutdownThread extends Thread { @@ -164,9 +153,9 @@ public class JettyRunForkedMojo extends JettyRunMojo { super("RunForkedShutdown"); } - + @Override - public void run () + public void run() { if (forkedProcess != null && waitForChild) { @@ -174,11 +163,7 @@ public class JettyRunForkedMojo extends JettyRunMojo } } } - - - - - + /** * @see org.apache.maven.plugin.Mojo#execute() */ @@ -187,9 +172,9 @@ public class JettyRunForkedMojo extends JettyRunMojo { Runtime.getRuntime().addShutdownHook(new ShutdownThread()); random = new Random(); - + List deps = plugin.getPlugin().getDependencies(); - for (Dependency d:deps) + for (Dependency d : deps) { if (d.getGroupId().contains("slf4j")) { @@ -197,12 +182,9 @@ public class JettyRunForkedMojo extends JettyRunMojo break; } } - + super.execute(); } - - - @Override public void startJetty() throws MojoExecutionException @@ -220,9 +202,9 @@ public class JettyRunForkedMojo extends JettyRunMojo //ensure handler structure enabled ServerSupport.configureHandlers(server, null); - + ServerSupport.configureDefaultConfigurationClasses(server); - + //ensure config of the webapp based on settings in plugin configureWebApplication(); @@ -234,7 +216,7 @@ public class JettyRunForkedMojo extends JettyRunMojo if (webApp.getQuickStartWebDescriptor() == null) { if (forkWebXml == null) - forkWebXml = new File (target, "fork-web.xml"); + forkWebXml = new File(target, "fork-web.xml"); if (!forkWebXml.getParentFile().exists()) forkWebXml.getParentFile().mkdirs(); @@ -243,10 +225,10 @@ public class JettyRunForkedMojo extends JettyRunMojo webApp.setQuickStartWebDescriptor(Resource.newResource(forkWebXml)); } - + //add webapp to our fake server instance ServerSupport.addWebApplication(server, webApp); - + //if our server has a thread pool associated we can do annotation scanning multithreaded, //otherwise scanning will be single threaded QueuedThreadPool tpool = server.getBean(QueuedThreadPool.class); @@ -257,32 +239,37 @@ public class JettyRunForkedMojo extends JettyRunMojo //leave everything unpacked for the forked process to use webApp.setPersistTempDirectory(true); - + webApp.start(); //just enough to generate the quickstart - + //save config of the webapp BEFORE we stop File props = prepareConfiguration(); - + webApp.stop(); - - - + if (tpool != null) tpool.stop(); - + List cmd = new ArrayList<>(); - cmd.add(getJavaBin()); - + if (StringUtil.isNotBlank(javaPath)) + { + cmd.add(javaPath); + } + else + { + cmd.add(getJavaBin()); + } + if (jvmArgs != null) { String[] args = jvmArgs.split(" "); - for (int i=0;args != null && i 0) { @@ -290,7 +277,7 @@ public class JettyRunForkedMojo extends JettyRunMojo cmd.add(classPath); } cmd.add(Starter.class.getCanonicalName()); - + if (stopPort > 0 && stopKey != null) { cmd.add("--stop-port"); @@ -303,37 +290,36 @@ public class JettyRunForkedMojo extends JettyRunMojo cmd.add("--jetty-xml"); cmd.add(jettyXml); } - + cmd.add("--props"); cmd.add(props.getAbsolutePath()); - - String token = createToken(); - Path tokenFile = target.toPath().resolve(createToken()+".txt"); + + Path tokenFile = target.toPath().resolve(createToken() + ".txt"); cmd.add("--token"); cmd.add(tokenFile.toAbsolutePath().toString()); - + if (jettyProperties != null) { - for (String jettyProp:jettyProperties) + for (String jettyProp : jettyProperties) { cmd.add(jettyProp); } } - + ProcessBuilder builder = new ProcessBuilder(cmd); builder.directory(project.getBasedir()); - + if (PluginLog.getLog().isDebugEnabled()) - PluginLog.getLog().debug("Forked cli:"+Arrays.toString(cmd.toArray())); - + PluginLog.getLog().debug("Forked cli:" + Arrays.toString(cmd.toArray())); + PluginLog.getLog().info("Forked process starting"); - + //set up extra environment vars if there are any if (!env.isEmpty()) { builder.environment().putAll(env); } - + if (waitForChild) { builder.inheritIO(); @@ -343,24 +329,24 @@ public class JettyRunForkedMojo extends JettyRunMojo builder.redirectOutput(new File(target, "jetty.out")); builder.redirectErrorStream(true); } - + forkedProcess = builder.start(); - + if (waitForChild) { - int exitcode = forkedProcess.waitFor(); - PluginLog.getLog().info("Forked execution exit: "+exitcode); + int exitcode = forkedProcess.waitFor(); + PluginLog.getLog().info("Forked execution exit: " + exitcode); } else - { + { //just wait until the child has started successfully int attempts = maxChildChecks; while (!Files.exists(tokenFile) && attempts > 0) { - Thread.currentThread().sleep(maxChildCheckInterval); + Thread.sleep(maxChildCheckInterval); --attempts; } - if (attempts <=0 ) + if (attempts <= 0) getLog().info("Couldn't verify success of child startup"); } } @@ -368,49 +354,51 @@ public class JettyRunForkedMojo extends JettyRunMojo { if (forkedProcess != null && waitForChild) forkedProcess.destroy(); - + throw new MojoExecutionException("Failed to start Jetty within time limit"); } catch (Exception ex) { if (forkedProcess != null && waitForChild) forkedProcess.destroy(); - + throw new MojoExecutionException("Failed to create Jetty process", ex); } } public List getProvidedJars() throws MojoExecutionException - { + { //if we are configured to include the provided dependencies on the plugin's classpath //(which mimics being on jetty's classpath vs being on the webapp's classpath), we first //try and filter out ones that will clash with jars that are plugin dependencies, then //create a new classloader that we setup in the parent chain. if (useProvidedScope) { - + List provided = new ArrayList<>(); - for ( Artifact artifact : project.getArtifacts()) + for (Artifact artifact : project.getArtifacts()) { if (Artifact.SCOPE_PROVIDED.equals(artifact.getScope()) && !isPluginArtifact(artifact)) { provided.add(artifact.getFile().getAbsolutePath()); - if (getLog().isDebugEnabled()) { getLog().debug("Adding provided artifact: "+artifact);} + if (getLog().isDebugEnabled()) + { + getLog().debug("Adding provided artifact: " + artifact); + } } } return provided; - } else return null; } - + public File prepareConfiguration() throws MojoExecutionException { try - { + { //work out the configuration based on what is configured in the pom - File propsFile = new File (target, "fork.props"); + File propsFile = new File(target, "fork.props"); WebAppPropertyConverter.toProperties(webApp, propsFile, contextXml); return propsFile; } @@ -419,31 +407,31 @@ public class JettyRunForkedMojo extends JettyRunMojo throw new MojoExecutionException("Prepare webapp configuration", e); } } - - @Override public boolean isPluginArtifact(Artifact artifact) { if (pluginArtifacts == null || pluginArtifacts.isEmpty()) return false; - + for (Artifact pluginArtifact : pluginArtifacts) { - if (getLog().isDebugEnabled()) { getLog().debug("Checking "+pluginArtifact);} + if (getLog().isDebugEnabled()) + { + getLog().debug("Checking " + pluginArtifact); + } if (pluginArtifact.getGroupId().equals(artifact.getGroupId()) && pluginArtifact.getArtifactId().equals(artifact.getArtifactId())) return true; } - + return false; } - + private Set getExtraJars() - throws Exception + throws Exception { Set extraJars = new HashSet<>(); - - + List l = pluginArtifacts; Artifact pluginArtifact = null; @@ -452,7 +440,7 @@ public class JettyRunForkedMojo extends JettyRunMojo Iterator itor = l.iterator(); while (itor.hasNext() && pluginArtifact == null) - { + { Artifact a = (Artifact)itor.next(); if (a.getArtifactId().equals(plugin.getArtifactId())) //get the jetty-maven-plugin jar { @@ -473,82 +461,39 @@ public class JettyRunForkedMojo extends JettyRunMojo { //ignore slf4j from inside maven if (artifact.getGroupId().contains("slf4j") && !hasSlf4jDeps) - continue; + continue; if (classPath.length() > 0) { classPath.append(File.pathSeparator); } classPath.append(artifact.getFile().getAbsolutePath()); - } } - //Any jars that we need from the plugin environment (like the ones containing Starter class) Set extraJars = getExtraJars(); - for (Artifact a:extraJars) - { + for (Artifact a : extraJars) + { classPath.append(File.pathSeparator); classPath.append(a.getFile().getAbsolutePath()); } - - + //Any jars that we need from the project's dependencies because we're useProvided List providedJars = getProvidedJars(); if (providedJars != null && !providedJars.isEmpty()) { - for (String jar:providedJars) + for (String jar : providedJars) { classPath.append(File.pathSeparator); classPath.append(jar); - if (getLog().isDebugEnabled()) getLog().debug("Adding provided jar: "+jar); + if (getLog().isDebugEnabled()) + getLog().debug("Adding provided jar: " + jar); } } return classPath.toString(); } - - - - /** - * @return - */ - private String getJavaBin() - { - String javaexes[] = new String[] - { "java", "java.exe" }; - - File javaHomeDir = new File(System.getProperty("java.home")); - for (String javaexe : javaexes) - { - File javabin = new File(javaHomeDir,fileSeparators("bin/" + javaexe)); - if (javabin.exists() && javabin.isFile()) - { - return javabin.getAbsolutePath(); - } - } - - return "java"; - } - - public static String fileSeparators(String path) - { - StringBuilder ret = new StringBuilder(); - for (char c : path.toCharArray()) - { - if ((c == '/') || (c == '\\')) - { - ret.append(File.separatorChar); - } - else - { - ret.append(c); - } - } - return ret.toString(); - } - public static String pathSeparators(String path) { StringBuilder ret = new StringBuilder(); @@ -566,8 +511,8 @@ public class JettyRunForkedMojo extends JettyRunMojo return ret.toString(); } - private String createToken () + private String createToken() { - return Long.toString(random.nextLong()^System.currentTimeMillis(), 36).toUpperCase(Locale.ENGLISH); + return Long.toString(random.nextLong() ^ System.currentTimeMillis(), 36).toUpperCase(Locale.ENGLISH); } } diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunMojo.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunMojo.java index feffd9547f3..8e6d5277266 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunMojo.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunMojo.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -21,13 +21,15 @@ package org.eclipse.jetty.maven.plugin; import java.io.File; import java.io.IOException; import java.net.URL; -import java.nio.file.Paths; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; import org.apache.maven.artifact.Artifact; import org.apache.maven.plugin.MojoExecutionException; @@ -38,120 +40,104 @@ import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; import org.apache.maven.project.MavenProject; -import org.codehaus.plexus.util.StringUtils; +import org.eclipse.jetty.maven.plugin.utils.MavenProjectHelper; import org.eclipse.jetty.util.PathWatcher; import org.eclipse.jetty.util.PathWatcher.PathWatchEvent; +import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.ResourceCollection; import org.eclipse.jetty.webapp.WebAppContext; - /** - * This goal is used in-situ on a Maven project without first requiring that the project - * is assembled into a war, saving time during the development cycle. - *

        - * The plugin forks a parallel lifecycle to ensure that the "compile" phase has been completed before invoking Jetty. This means - * that you do not need to explicitly execute a "mvn compile" first. It also means that a "mvn clean jetty:run" will ensure that - * a full fresh compile is done before invoking Jetty. - *

        - * Once invoked, the plugin can be configured to run continuously, scanning for changes in the project and automatically performing a - * hot redeploy when necessary. This allows the developer to concentrate on coding changes to the project using their IDE of choice and have those changes - * immediately and transparently reflected in the running web container, eliminating development time that is wasted on rebuilding, reassembling and redeploying. - *

        - * You may also specify the location of a jetty.xml file whose contents will be applied before any plugin configuration. - * This can be used, for example, to deploy a static webapp that is not part of your maven build. - *

        - * There is a reference guide to the configuration parameters for this plugin. - * - * Runs jetty directly from a maven project + * This goal is used in-situ on a Maven project without first requiring that the project + * is assembled into a war, saving time during the development cycle. + *

        + * The plugin forks a parallel lifecycle to ensure that the "compile" phase has been completed before invoking Jetty. This means + * that you do not need to explicitly execute a "mvn compile" first. It also means that a "mvn clean jetty:run" will ensure that + * a full fresh compile is done before invoking Jetty. + *

        + * Once invoked, the plugin can be configured to run continuously, scanning for changes in the project and automatically performing a + * hot redeploy when necessary. This allows the developer to concentrate on coding changes to the project using their IDE of choice and have those changes + * immediately and transparently reflected in the running web container, eliminating development time that is wasted on rebuilding, reassembling and redeploying. + *

        + * You may also specify the location of a jetty.xml file whose contents will be applied before any plugin configuration. + * This can be used, for example, to deploy a static webapp that is not part of your maven build. + *

        + * There is a reference guide to the configuration parameters for this plugin. + * + * Runs jetty directly from a maven project */ -@Mojo( name = "run", requiresDependencyResolution = ResolutionScope.TEST) +@Mojo(name = "run", requiresDependencyResolution = ResolutionScope.TEST) @Execute(phase = LifecyclePhase.TEST_COMPILE) public class JettyRunMojo extends AbstractJettyMojo { - public static final String DEFAULT_WEBAPP_SRC = "src"+File.separator+"main"+File.separator+"webapp"; + public static final String DEFAULT_WEBAPP_SRC = "src" + File.separator + "main" + File.separator + "webapp"; public static final String FAKE_WEBAPP = "webapp-tmp"; - - /** * If true, the <testOutputDirectory> * and the dependencies of <scope>test<scope> * will be put first on the runtime classpath. - * */ - @Parameter(alias="useTestClasspath", defaultValue="false") + @Parameter(alias = "useTestClasspath", defaultValue = "false") protected boolean useTestScope; - - + /** * The default location of the web.xml file. Will be used * if <webApp><descriptor> is not set. - * */ - @Parameter(defaultValue="${maven.war.webxml}", readonly = true) + @Parameter(defaultValue = "${maven.war.webxml}", readonly = true) protected String webXml; - - + /** * The directory containing generated classes. - * */ - @Parameter(defaultValue="${project.build.outputDirectory}", required = true) + @Parameter(defaultValue = "${project.build.outputDirectory}", required = true) protected File classesDirectory; - + /** * An optional pattern for includes/excludes of classes in the classesDirectory - * */ @Parameter protected ScanPattern scanClassesPattern; /** * The directory containing generated test classes. - * */ - @Parameter(defaultValue="${project.build.testOutputDirectory}", required = true) + @Parameter(defaultValue = "${project.build.testOutputDirectory}", required = true) protected File testClassesDirectory; - + /** * An optional pattern for includes/excludes of classes in the testClassesDirectory - * */ @Parameter protected ScanPattern scanTestClassesPattern; /** * Root directory for all html/jsp etc files - * */ - @Parameter(defaultValue="${maven.war.src}") + @Parameter(defaultValue = "${maven.war.src}") protected File webAppSourceDirectory; - - + /** * List of files or directories to additionally periodically scan for changes. Optional. */ @Parameter protected File[] scanTargets; - - + /** * List of directories with ant-style <include> and <exclude> patterns * for extra targets to periodically scan for changes. Can be used instead of, * or in conjunction with <scanTargets>.Optional. - * */ @Parameter protected ScanTargetPattern[] scanTargetPatterns; - /** * maven-war-plugin reference */ protected WarPluginInfo warPluginInfo; - - + /** * List of deps that are wars */ @@ -159,7 +145,7 @@ public class JettyRunMojo extends AbstractJettyMojo protected Resource originalBaseResource; - /** + /** * @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#execute() */ @Override @@ -171,48 +157,48 @@ public class JettyRunMojo extends AbstractJettyMojo /** * Verify the configuration given in the pom. - * + * * @see AbstractJettyMojo#checkPomConfiguration() */ @Override - public boolean checkPomConfiguration () throws MojoExecutionException + public boolean checkPomConfiguration() throws MojoExecutionException { // check the location of the static content/jsps etc try { if ((webAppSourceDirectory == null) || !webAppSourceDirectory.exists()) - { - getLog().info("webAppSourceDirectory"+(webAppSourceDirectory == null ? " not set." : (webAppSourceDirectory.getAbsolutePath()+" does not exist."))+" Trying "+DEFAULT_WEBAPP_SRC); - webAppSourceDirectory = new File (project.getBasedir(), DEFAULT_WEBAPP_SRC); + { + getLog().info("webAppSourceDirectory" + (webAppSourceDirectory == null ? " not set." : (webAppSourceDirectory.getAbsolutePath() + " does not exist.")) + " Trying " + DEFAULT_WEBAPP_SRC); + webAppSourceDirectory = new File(project.getBasedir(), DEFAULT_WEBAPP_SRC); if (!webAppSourceDirectory.exists()) { - getLog().info("webAppSourceDirectory "+webAppSourceDirectory.getAbsolutePath()+" does not exist. Trying "+project.getBuild().getDirectory()+File.separator+FAKE_WEBAPP); - + getLog().info("webAppSourceDirectory " + webAppSourceDirectory.getAbsolutePath() + " does not exist. Trying " + project.getBuild().getDirectory() + File.separator + FAKE_WEBAPP); + //try last resort of making a fake empty dir File target = new File(project.getBuild().getDirectory()); webAppSourceDirectory = new File(target, FAKE_WEBAPP); if (!webAppSourceDirectory.exists()) - webAppSourceDirectory.mkdirs(); + webAppSourceDirectory.mkdirs(); } } else - getLog().info( "Webapp source directory = " + webAppSourceDirectory.getCanonicalPath()); + getLog().info("Webapp source directory = " + webAppSourceDirectory.getCanonicalPath()); } catch (IOException e) { throw new MojoExecutionException("Webapp source directory does not exist", e); } - + // check reload mechanic - if ( !"automatic".equalsIgnoreCase( reload ) && !"manual".equalsIgnoreCase( reload ) ) + if (!"automatic".equalsIgnoreCase(reload) && !"manual".equalsIgnoreCase(reload)) { - throw new MojoExecutionException( "invalid reload mechanic specified, must be 'automatic' or 'manual'" ); + throw new MojoExecutionException("invalid reload mechanic specified, must be 'automatic' or 'manual'"); } else { - getLog().info("Reload Mechanic: " + reload ); + getLog().info("Reload Mechanic: " + reload); } - getLog().info( "nonBlocking:" + nonBlocking ); + getLog().info("nonBlocking:" + nonBlocking); // check the classes to form a classpath with try @@ -221,12 +207,12 @@ public class JettyRunMojo extends AbstractJettyMojo if (classesDirectory != null) { if (!classesDirectory.exists()) - getLog().info( "Classes directory "+ classesDirectory.getCanonicalPath()+ " does not exist"); + getLog().info("Classes directory " + classesDirectory.getCanonicalPath() + " does not exist"); else getLog().info("Classes = " + classesDirectory.getCanonicalPath()); } else - getLog().info("Classes directory not set"); + getLog().info("Classes directory not set"); } catch (IOException e) { @@ -236,9 +222,6 @@ public class JettyRunMojo extends AbstractJettyMojo return true; } - - - @Override public void finishConfigurationBeforeStart() throws Exception { @@ -246,52 +229,57 @@ public class JettyRunMojo extends AbstractJettyMojo super.finishConfigurationBeforeStart(); } - - - - /** + /** * @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#configureWebApplication() */ @Override public void configureWebApplication() throws Exception { - super.configureWebApplication(); - - //Set up the location of the webapp. - //There are 2 parts to this: setWar() and setBaseResource(). On standalone jetty, - //the former could be the location of a packed war, while the latter is the location - //after any unpacking. With this mojo, you are running an unpacked, unassembled webapp, - //so the two locations should be equal. - Resource webAppSourceDirectoryResource = Resource.newResource(webAppSourceDirectory.getCanonicalPath()); - if (webApp.getWar() == null) - webApp.setWar(webAppSourceDirectoryResource.toString()); + super.configureWebApplication(); - //The first time we run, remember the original base dir - if (originalBaseResource == null) - { - if (webApp.getBaseResource() == null) - originalBaseResource = webAppSourceDirectoryResource; - else - originalBaseResource = webApp.getBaseResource(); - } + //Set up the location of the webapp. + //There are 2 parts to this: setWar() and setBaseResource(). On standalone jetty, + //the former could be the location of a packed war, while the latter is the location + //after any unpacking. With this mojo, you are running an unpacked, unassembled webapp, + //so the two locations should be equal. + Resource webAppSourceDirectoryResource = Resource.newResource(webAppSourceDirectory.getCanonicalPath()); + if (webApp.getWar() == null) + webApp.setWar(webAppSourceDirectoryResource.toString()); - //On every subsequent re-run set it back to the original base dir before - //we might have applied any war overlays onto it - webApp.setBaseResource(originalBaseResource); + //The first time we run, remember the original base dir + if (originalBaseResource == null) + { + if (webApp.getBaseResource() == null) + originalBaseResource = webAppSourceDirectoryResource; + else + originalBaseResource = webApp.getBaseResource(); + } - if (classesDirectory != null) - webApp.setClasses (classesDirectory); - if (useTestScope && (testClassesDirectory != null)) - webApp.setTestClasses (testClassesDirectory); + //On every subsequent re-run set it back to the original base dir before + //we might have applied any war overlays onto it + webApp.setBaseResource(originalBaseResource); - webApp.setWebInfLib(getDependencyFiles()); + if (classesDirectory != null) + webApp.setClasses(classesDirectory); + if (useTestScope && (testClassesDirectory != null)) + webApp.setTestClasses(testClassesDirectory); + MavenProjectHelper mavenProjectHelper = new MavenProjectHelper(project); + List webInfLibs = getWebInfLibArtifacts(project).stream() + .map(a -> + { + Path p = mavenProjectHelper.getArtifactPath(a); + getLog().debug("Artifact " + a.getId() + " loaded from " + p + " added to WEB-INF/lib"); + return p.toFile(); + }).collect(Collectors.toList()); + getLog().debug("WEB-INF/lib initialized (at root)"); + webApp.setWebInfLib(webInfLibs); - //if we have not already set web.xml location, need to set one up - if (webApp.getDescriptor() == null) - { - //Has an explicit web.xml file been configured to use? - if (webXml != null) + //if we have not already set web.xml location, need to set one up + if (webApp.getDescriptor() == null) + { + //Has an explicit web.xml file been configured to use? + if (webXml != null) { Resource r = Resource.newResource(webXml); if (r.exists() && !r.isDirectory()) @@ -299,7 +287,7 @@ public class JettyRunMojo extends AbstractJettyMojo webApp.setDescriptor(r.toString()); } } - + //Still don't have a web.xml file: try the resourceBase of the webapp, if it is set if (webApp.getDescriptor() == null && webApp.getBaseResource() != null) { @@ -309,32 +297,32 @@ public class JettyRunMojo extends AbstractJettyMojo webApp.setDescriptor(r.toString()); } } - + //Still don't have a web.xml file: finally try the configured static resource directory if there is one if (webApp.getDescriptor() == null && (webAppSourceDirectory != null)) { - File f = new File (new File (webAppSourceDirectory, "WEB-INF"), "web.xml"); + File f = new File(new File(webAppSourceDirectory, "WEB-INF"), "web.xml"); if (f.exists() && f.isFile()) { - webApp.setDescriptor(f.getCanonicalPath()); + webApp.setDescriptor(f.getCanonicalPath()); } } - } + } - //process any overlays and the war type artifacts - List overlays = getOverlays(); - unpackOverlays(overlays); //this sets up the base resource collection + //process any overlays and the war type artifacts + List overlays = getOverlays(); + unpackOverlays(overlays); //this sets up the base resource collection - getLog().info( "web.xml file = "+webApp.getDescriptor()); - getLog().info("Webapp directory = " + webAppSourceDirectory.getCanonicalPath()); + getLog().info("web.xml file = " + webApp.getDescriptor()); + getLog().info("Webapp directory = " + webAppSourceDirectory.getCanonicalPath()); } - /** + /** * @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#configureScanner() */ @Override - public void configureScanner () - throws MojoExecutionException + public void configureScanner() + throws MojoExecutionException { try { @@ -345,7 +333,7 @@ public class JettyRunMojo extends AbstractJettyMojo throw new MojoExecutionException("Error forming scan list", e); } - scanner.addListener( new PathWatcher.EventListListener() + scanner.addListener(new PathWatcher.EventListListener() { @Override @@ -356,7 +344,7 @@ public class JettyRunMojo extends AbstractJettyMojo boolean reconfigure = false; if (events != null) { - for (PathWatchEvent e:events) + for (PathWatchEvent e : events) { if (e.getPath().equals(project.getFile().toPath())) { @@ -370,13 +358,12 @@ public class JettyRunMojo extends AbstractJettyMojo } catch (Exception e) { - getLog().error("Error reconfiguring/restarting webapp after change in watched files",e); + getLog().error("Error reconfiguring/restarting webapp after change in watched files", e); } } }); } - public void gatherScannables() throws Exception { if (webApp.getDescriptor() != null) @@ -384,7 +371,7 @@ public class JettyRunMojo extends AbstractJettyMojo Resource r = Resource.newResource(webApp.getDescriptor()); scanner.watch(r.getFile().toPath()); } - + if (webApp.getJettyEnvXml() != null) scanner.watch(new File(webApp.getJettyEnvXml()).toPath()); @@ -398,23 +385,23 @@ public class JettyRunMojo extends AbstractJettyMojo { scanner.watch(new File(webApp.getOverrideDescriptor()).toPath()); } - - File jettyWebXmlFile = findJettyWebXmlFile(new File(webAppSourceDirectory,"WEB-INF")); + + File jettyWebXmlFile = findJettyWebXmlFile(new File(webAppSourceDirectory, "WEB-INF")); if (jettyWebXmlFile != null) { scanner.watch(jettyWebXmlFile.toPath()); } - + //make sure each of the war artifacts is added to the scanner - for (Artifact a:getWarArtifacts()) + for (Artifact a : getWarArtifacts()) { scanner.watch(a.getFile().toPath()); } - + //handle the explicit extra scan targets if (scanTargets != null) { - for (File f:scanTargets) + for (File f : scanTargets) { if (f.isDirectory()) { @@ -426,58 +413,68 @@ public class JettyRunMojo extends AbstractJettyMojo scanner.watch(f.toPath()); } } - + //handle the extra scan patterns if (scanTargetPatterns != null) { - for (ScanTargetPattern p:scanTargetPatterns) + for (ScanTargetPattern p : scanTargetPatterns) { PathWatcher.Config config = new PathWatcher.Config(p.getDirectory().toPath()); config.setRecurseDepth(PathWatcher.Config.UNLIMITED_DEPTH); - for (String pattern:p.getExcludes()) + for (String pattern : p.getExcludes()) + { config.addExcludeGlobRelative(pattern); - for (String pattern:p.getIncludes()) + } + for (String pattern : p.getIncludes()) + { config.addIncludeGlobRelative(pattern); + } scanner.watch(config); } } - scanner.watch(project.getFile().toPath()); if (webApp.getTestClasses() != null && webApp.getTestClasses().exists()) { PathWatcher.Config config = new PathWatcher.Config(webApp.getTestClasses().toPath()); - config.setRecurseDepth(PathWatcher.Config.UNLIMITED_DEPTH); + config.setRecurseDepth(PathWatcher.Config.UNLIMITED_DEPTH); if (scanTestClassesPattern != null) { - for (String p:scanTestClassesPattern.getExcludes()) + for (String p : scanTestClassesPattern.getExcludes()) + { config.addExcludeGlobRelative(p); - for (String p:scanTestClassesPattern.getIncludes()) + } + for (String p : scanTestClassesPattern.getIncludes()) + { config.addIncludeGlobRelative(p); + } } scanner.watch(config); } - + if (webApp.getClasses() != null && webApp.getClasses().exists()) { PathWatcher.Config config = new PathWatcher.Config(webApp.getClasses().toPath()); config.setRecurseDepth(PathWatcher.Config.UNLIMITED_DEPTH); if (scanClassesPattern != null) { - for (String p:scanClassesPattern.getExcludes()) + for (String p : scanClassesPattern.getExcludes()) + { config.addExcludeGlobRelative(p); + } - for (String p:scanClassesPattern.getIncludes()) + for (String p : scanClassesPattern.getIncludes()) + { config.addIncludeGlobRelative(p); - + } } scanner.watch(config); } if (webApp.getWebInfLib() != null) { - for (File f:webApp.getWebInfLib()) + for (File f : webApp.getWebInfLib()) { PathWatcher.Config config = new PathWatcher.Config(f.toPath()); config.setRecurseDepth(PathWatcher.Config.UNLIMITED_DEPTH); @@ -486,20 +483,19 @@ public class JettyRunMojo extends AbstractJettyMojo } } - - /** + /** * @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#restartWebApp(boolean) */ @Override - public void restartWebApp(boolean reconfigureScanner) throws Exception + public void restartWebApp(boolean reconfigureScanner) throws Exception { - getLog().info("restarting "+webApp); + getLog().info("restarting " + webApp); getLog().debug("Stopping webapp ..."); stopScanner(); webApp.stop(); getLog().debug("Reconfiguring webapp ..."); - + checkPomConfiguration(); configureWebApplication(); @@ -516,74 +512,46 @@ public class JettyRunMojo extends AbstractJettyMojo getLog().debug("Restarting webapp ..."); webApp.start(); startScanner(); - getLog().info("Restart completed at "+new Date().toString()); + getLog().info("Restart completed at " + new Date().toString()); } - - - - - /** - * @return - */ - private List getDependencyFiles() + + private Collection getWebInfLibArtifacts(Set artifacts) { - List dependencyFiles = new ArrayList<>(); - for ( Artifact artifact : projectArtifacts) - { - // Include runtime and compile time libraries, and possibly test libs too - if(artifact.getType().equals("war")) - { - continue; - } - MavenProject mavenProject = getProjectReference( artifact, project ); - if (mavenProject != null) - { - File projectPath = Paths.get(mavenProject.getBuild().getOutputDirectory()).toFile(); - getLog().debug( "Adding project directory " + projectPath.toString() ); - dependencyFiles.add( projectPath ); - continue; - } - - if (Artifact.SCOPE_PROVIDED.equals(artifact.getScope())) - continue; //never add dependencies of scope=provided to the webapp's classpath (see also param) - - if (Artifact.SCOPE_TEST.equals(artifact.getScope()) && !useTestScope) - continue; //only add dependencies of scope=test if explicitly required - - dependencyFiles.add(artifact.getFile()); - getLog().debug( "Adding artifact " + artifact.getFile().getName() + " with scope "+artifact.getScope()+" for WEB-INF/lib " ); - } - - return dependencyFiles; + return artifacts.stream() + .filter(this::canPutArtifactInWebInfLib) + .collect(Collectors.toList()); } - protected MavenProject getProjectReference(Artifact artifact, MavenProject project ) + private Collection getWebInfLibArtifacts(MavenProject mavenProject) { - if ( project.getProjectReferences() == null || project.getProjectReferences().isEmpty() ) + String type = mavenProject.getArtifact().getType(); + if (!"war".equalsIgnoreCase(type) && !"zip".equalsIgnoreCase(type)) { - return null; + return Collections.emptyList(); } - Collection mavenProjects = project.getProjectReferences().values(); - for ( MavenProject mavenProject : mavenProjects ) - { - if ( StringUtils.equals( mavenProject.getId(), artifact.getId() ) ) - { - return mavenProject; - } - } - return null; + return getWebInfLibArtifacts(mavenProject.getArtifacts()); } + private boolean canPutArtifactInWebInfLib(Artifact artifact) + { + if ("war".equalsIgnoreCase(artifact.getType())) + { + return false; + } + if (Artifact.SCOPE_PROVIDED.equals(artifact.getScope())) + { + return false; + } + return !Artifact.SCOPE_TEST.equals(artifact.getScope()) || useTestScope; + } - - private List getOverlays() - throws Exception + throws Exception { //get copy of a list of war artifacts Set matchedWarArtifacts = new HashSet<>(); List overlays = new ArrayList<>(); - for (OverlayConfig config:warPluginInfo.getMavenWarOverlayConfigs()) + for (OverlayConfig config : warPluginInfo.getMavenWarOverlayConfigs()) { //overlays can be individually skipped if (config.isSkip()) @@ -602,7 +570,7 @@ public class JettyRunMojo extends AbstractJettyMojo if (a != null) { matchedWarArtifacts.add(a); - SelectiveJarResource r = new SelectiveJarResource(new URL("jar:"+Resource.toURL(a.getFile()).toString()+"!/")); + SelectiveJarResource r = new SelectiveJarResource(new URL("jar:" + Resource.toURL(a.getFile()).toString() + "!/")); r.setIncludes(config.getIncludes()); r.setExcludes(config.getExcludes()); Overlay overlay = new Overlay(config, r); @@ -611,32 +579,31 @@ public class JettyRunMojo extends AbstractJettyMojo } //iterate over the left over war artifacts and unpack them (without include/exclude processing) as necessary - for (Artifact a: getWarArtifacts()) + for (Artifact a : getWarArtifacts()) { if (!matchedWarArtifacts.contains(a)) { - Overlay overlay = new Overlay(null, Resource.newResource(new URL("jar:"+Resource.toURL(a.getFile()).toString()+"!/"))); + Overlay overlay = new Overlay(null, Resource.newResource(new URL("jar:" + Resource.toURL(a.getFile()).toString() + "!/"))); overlays.add(overlay); } } return overlays; } - - public void unpackOverlays (List overlays) - throws Exception + public void unpackOverlays(List overlays) + throws Exception { if (overlays == null || overlays.isEmpty()) return; List resourceBaseCollection = new ArrayList<>(); - for (Overlay o:overlays) + for (Overlay o : overlays) { //can refer to the current project in list of overlays for ordering purposes if (o.getConfig() != null && o.getConfig().isCurrentProject() && webApp.getBaseResource().exists()) { - resourceBaseCollection.add(webApp.getBaseResource()); + resourceBaseCollection.add(webApp.getBaseResource()); continue; } @@ -658,64 +625,61 @@ public class JettyRunMojo extends AbstractJettyMojo } webApp.setBaseResource(new ResourceCollection(resourceBaseCollection.toArray(new Resource[resourceBaseCollection.size()]))); } - - - - public Resource unpackOverlay (Overlay overlay) - throws IOException - { + public Resource unpackOverlay(Overlay overlay) + throws IOException + { if (overlay.getResource() == null) return null; //nothing to unpack - + //Get the name of the overlayed war and unpack it to a dir of the //same name in the temporary directory String name = overlay.getResource().getName(); if (name.endsWith("!/")) - name = name.substring(0,name.length()-2); + name = name.substring(0, name.length() - 2); int i = name.lastIndexOf('/'); - if (i>0) - name = name.substring(i+1,name.length()); - name = name.replace('.', '_'); + if (i > 0) + name = name.substring(i + 1); + name = StringUtil.replace(name, '.', '_'); //name = name+(++COUNTER); //add some digits to ensure uniqueness - File overlaysDir = new File (project.getBuild().getDirectory(), "jetty_overlays"); + File overlaysDir = new File(project.getBuild().getDirectory(), "jetty_overlays"); File dir = new File(overlaysDir, name); //if specified targetPath, unpack to that subdir instead File unpackDir = dir; if (overlay.getConfig() != null && overlay.getConfig().getTargetPath() != null) - unpackDir = new File (dir, overlay.getConfig().getTargetPath()); + unpackDir = new File(dir, overlay.getConfig().getTargetPath()); //only unpack if the overlay is newer if (!unpackDir.exists() || (overlay.getResource().lastModified() > unpackDir.lastModified())) { - boolean made=unpackDir.mkdirs(); + boolean made = unpackDir.mkdirs(); overlay.getResource().copyTo(unpackDir); } //use top level of unpacked content - return Resource.newResource(dir.getCanonicalPath()); + return Resource.newResource(dir.getCanonicalPath()); } - + /** - * @return + * */ - private List getWarArtifacts () + private List getWarArtifacts() { if (warArtifacts != null) - return warArtifacts; - + return warArtifacts; + warArtifacts = new ArrayList<>(); - for ( Artifact artifact : projectArtifacts) + for (Artifact artifact : projectArtifacts) { if (artifact.getType().equals("war") || artifact.getType().equals("zip")) { try - { + { warArtifacts.add(artifact); - getLog().info("Dependent war artifact "+artifact.getId()); + getLog().info("Dependent war artifact " + artifact.getId()); } - catch(Exception e) + catch (Exception e) { throw new RuntimeException(e); } @@ -724,19 +688,57 @@ public class JettyRunMojo extends AbstractJettyMojo return warArtifacts; } - protected Artifact getArtifactForOverlay (OverlayConfig o, List warArtifacts) + protected Artifact getArtifactForOverlay(OverlayConfig o, List warArtifacts) { if (o == null || warArtifacts == null || warArtifacts.isEmpty()) return null; - - for (Artifact a:warArtifacts) + + for (Artifact a : warArtifacts) { - if (o.matchesArtifact (a.getGroupId(), a.getArtifactId(), a.getClassifier())) + if (o.matchesArtifact(a.getGroupId(), a.getArtifactId(), a.getClassifier())) { - return a; + return a; } } - + return null; } + + /** + * + */ + protected String getJavaBin() + { + String[] javaexes = new String[] + {"java", "java.exe"}; + + File javaHomeDir = new File(System.getProperty("java.home")); + for (String javaexe : javaexes) + { + File javabin = new File(javaHomeDir, fileSeparators("bin/" + javaexe)); + if (javabin.exists() && javabin.isFile()) + { + return javabin.getAbsolutePath(); + } + } + + return "java"; + } + + public static String fileSeparators(String path) + { + StringBuilder ret = new StringBuilder(); + for (char c : path.toCharArray()) + { + if ((c == '/') || (c == '\\')) + { + ret.append(File.separatorChar); + } + else + { + ret.append(c); + } + } + return ret.toString(); + } } diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunWarExplodedMojo.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunWarExplodedMojo.java index 0b7b910bfe4..e41aa04f7ee 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunWarExplodedMojo.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunWarExplodedMojo.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -32,40 +32,37 @@ import org.eclipse.jetty.util.PathWatcher; import org.eclipse.jetty.util.PathWatcher.PathWatchEvent; /** - * - *

        - * This goal is used to assemble your webapp into an exploded war and automatically deploy it to Jetty. - *

        - *

        - * Once invoked, the plugin runs continuously, and can be configured to scan for changes in the pom.xml and - * to WEB-INF/web.xml, WEB-INF/classes or WEB-INF/lib and hot redeploy when a change is detected. - *

        - *

        - * You may also specify the location of a jetty.xml file whose contents will be applied before any plugin configuration. - * This can be used, for example, to deploy a static webapp that is not part of your maven build. - *

        + *

        + * This goal is used to assemble your webapp into an exploded war and automatically deploy it to Jetty. + *

        + *

        + * Once invoked, the plugin runs continuously, and can be configured to scan for changes in the pom.xml and + * to WEB-INF/web.xml, WEB-INF/classes or WEB-INF/lib and hot redeploy when a change is detected. + *

        + *

        + * You may also specify the location of a jetty.xml file whose contents will be applied before any plugin configuration. + * This can be used, for example, to deploy a static webapp that is not part of your maven build. + *

        */ -@Mojo( name = "run-exploded", requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME) +@Mojo(name = "run-exploded", requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME) @Execute(phase = LifecyclePhase.PACKAGE) public class JettyRunWarExplodedMojo extends AbstractJettyMojo { - + /** * The location of the war file. */ - @Parameter(defaultValue="${project.build.directory}/${project.build.finalName}", required = true) + @Parameter(defaultValue = "${project.build.directory}/${project.build.finalName}", required = true) private File war; - /** + /** * @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#execute() */ @Override - public void execute () throws MojoExecutionException, MojoFailureException + public void execute() throws MojoExecutionException, MojoFailureException { super.execute(); } - - @Override public void finishConfigurationBeforeStart() throws Exception @@ -73,7 +70,6 @@ public class JettyRunWarExplodedMojo extends AbstractJettyMojo server.setStopAtShutdown(true); //as we will normally be stopped with a cntrl-c, ensure server stopped super.finishConfigurationBeforeStart(); } - /** * @see AbstractJettyMojo#configureScanner() @@ -82,7 +78,7 @@ public class JettyRunWarExplodedMojo extends AbstractJettyMojo public void configureScanner() throws MojoExecutionException { scanner.watch(project.getFile().toPath()); - File webInfDir = new File(war,"WEB-INF"); + File webInfDir = new File(war, "WEB-INF"); File webXml = new File(webInfDir, "web.xml"); if (webXml.exists()) scanner.watch(webXml.toPath()); @@ -106,7 +102,7 @@ public class JettyRunWarExplodedMojo extends AbstractJettyMojo { PathWatcher.Config libConfig = new PathWatcher.Config(lib.toPath()); libConfig.setRecurseDepth(PathWatcher.Config.UNLIMITED_DEPTH); - scanner.watch(libConfig); + scanner.watch(libConfig); } scanner.addListener(new PathWatcher.EventListListener() @@ -118,7 +114,7 @@ public class JettyRunWarExplodedMojo extends AbstractJettyMojo try { boolean reconfigure = false; - for (PathWatchEvent e:events) + for (PathWatchEvent e : events) { if (e.getPath().equals(project.getFile().toPath())) { @@ -130,20 +126,17 @@ public class JettyRunWarExplodedMojo extends AbstractJettyMojo } catch (Exception e) { - getLog().error("Error reconfiguring/restarting webapp after change in watched files",e); + getLog().error("Error reconfiguring/restarting webapp after change in watched files", e); } } }); } - - - - /** + /** * @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#restartWebApp(boolean) */ @Override - public void restartWebApp(boolean reconfigureScanner) throws Exception + public void restartWebApp(boolean reconfigureScanner) throws Exception { getLog().info("Restarting webapp"); getLog().debug("Stopping webapp ..."); @@ -168,16 +161,13 @@ public class JettyRunWarExplodedMojo extends AbstractJettyMojo getLog().info("Restart completed."); } - - - - /** + /** * @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#configureWebApplication() */ @Override - public void configureWebApplication () throws Exception + public void configureWebApplication() throws Exception { - super.configureWebApplication(); + super.configureWebApplication(); webApp.setWar(war.getCanonicalPath()); } } diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunWarMojo.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunWarMojo.java index c4e8f04f746..df69738a26a 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunWarMojo.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunWarMojo.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -33,28 +33,27 @@ import org.eclipse.jetty.util.PathWatcher.PathWatchEvent; /** *

        - * This goal is used to assemble your webapp into a war and automatically deploy it to Jetty. - *

        - *

        - * Once invoked, the plugin runs continuously and can be configured to scan for changes in the project and to the - * war file and automatically perform a hot redeploy when necessary. - *

        - *

        - * You may also specify the location of a jetty.xml file whose contents will be applied before any plugin configuration. - * This can be used, for example, to deploy a static webapp that is not part of your maven build. - *

        - * Runs jetty on a war file + * This goal is used to assemble your webapp into a war and automatically deploy it to Jetty. + *

        + *

        + * Once invoked, the plugin runs continuously and can be configured to scan for changes in the project and to the + * war file and automatically perform a hot redeploy when necessary. + *

        + *

        + * You may also specify the location of a jetty.xml file whose contents will be applied before any plugin configuration. + * This can be used, for example, to deploy a static webapp that is not part of your maven build. + *

        + * Runs jetty on a war file */ -@Mojo( name = "run-war", requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME) +@Mojo(name = "run-war", requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME) @Execute(phase = LifecyclePhase.PACKAGE) public class JettyRunWarMojo extends AbstractJettyMojo { /** * The location of the war file. - * */ - @Parameter(defaultValue="${project.build.directory}/${project.build.finalName}.war", required = true) + @Parameter(defaultValue = "${project.build.directory}/${project.build.finalName}.war", required = true) private File war; /** @@ -63,10 +62,9 @@ public class JettyRunWarMojo extends AbstractJettyMojo @Override public void execute() throws MojoExecutionException, MojoFailureException { - super.execute(); + super.execute(); } - @Override public void finishConfigurationBeforeStart() throws Exception { @@ -74,17 +72,13 @@ public class JettyRunWarMojo extends AbstractJettyMojo super.finishConfigurationBeforeStart(); } - - @Override - public void configureWebApplication () throws Exception + public void configureWebApplication() throws Exception { super.configureWebApplication(); - + webApp.setWar(war.getCanonicalPath()); } - - /** * @see AbstractJettyMojo#configureScanner() @@ -104,7 +98,7 @@ public class JettyRunWarMojo extends AbstractJettyMojo try { boolean reconfigure = false; - for (PathWatchEvent e:events) + for (PathWatchEvent e : events) { if (e.getPath().equals(project.getFile().toPath())) { @@ -116,20 +110,17 @@ public class JettyRunWarMojo extends AbstractJettyMojo } catch (Exception e) { - getLog().error("Error reconfiguring/restarting webapp after change in watched files",e); + getLog().error("Error reconfiguring/restarting webapp after change in watched files", e); } } }); } - - - - /** + /** * @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#restartWebApp(boolean) */ @Override - public void restartWebApp(boolean reconfigureScanner) throws Exception + public void restartWebApp(boolean reconfigureScanner) throws Exception { getLog().info("Restarting webapp ..."); getLog().debug("Stopping webapp ..."); @@ -153,5 +144,4 @@ public class JettyRunWarMojo extends AbstractJettyMojo startScanner(); getLog().info("Restart completed."); } - } diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyStartMojo.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyStartMojo.java index 70fe508dace..239a6d3389c 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyStartMojo.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyStartMojo.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -25,21 +25,20 @@ import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.ResolutionScope; - /** - *

        - * This goal is similar to the jetty:run goal, EXCEPT that it is designed to be bound to an execution inside your pom, rather - * than being run from the command line. - *

        - *

        - * When using it, be careful to ensure that you bind it to a phase in which all necessary generated files and classes for the webapp - * will have been created. If you run it from the command line, then also ensure that all necessary generated files and classes for - * the webapp already exist. - *

        - * - * Runs jetty directly from a maven project from a binding to an execution in your pom + *

        + * This goal is similar to the jetty:run goal, EXCEPT that it is designed to be bound to an execution inside your pom, rather + * than being run from the command line. + *

        + *

        + * When using it, be careful to ensure that you bind it to a phase in which all necessary generated files and classes for the webapp + * will have been created. If you run it from the command line, then also ensure that all necessary generated files and classes for + * the webapp already exist. + *

        + * + * Runs jetty directly from a maven project from a binding to an execution in your pom */ -@Mojo( name = "start", requiresDependencyResolution = ResolutionScope.TEST) +@Mojo(name = "start", requiresDependencyResolution = ResolutionScope.TEST) @Execute(phase = LifecyclePhase.VALIDATE) public class JettyStartMojo extends JettyRunMojo { @@ -50,12 +49,11 @@ public class JettyStartMojo extends JettyRunMojo nonBlocking = true; //ensure that starting jetty won't hold up the thread super.execute(); } - + @Override public void finishConfigurationBeforeStart() throws Exception { super.finishConfigurationBeforeStart(); server.setStopAtShutdown(false); //as we will normally be stopped with a cntrl-c, ensure server stopped } - } diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyStopMojo.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyStopMojo.java index 57550e16b1d..79716ff6c0c 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyStopMojo.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyStopMojo.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -33,62 +33,59 @@ import org.apache.maven.plugins.annotations.Parameter; /** * This goal stops a running instance of jetty. - * + * * The stopPort and stopKey parameters can be used to * configure which jetty to stop. - * + * * Stops jetty that is configured with <stopKey> and <stopPort>. */ -@Mojo( name = "stop") +@Mojo(name = "stop") public class JettyStopMojo extends AbstractMojo { - + /** * Port to listen to stop jetty on sending stop command */ @Parameter(required = true) protected int stopPort; - + /** - * Key to provide when stopping jetty on executing java -DSTOP.KEY=<stopKey> + * Key to provide when stopping jetty on executing java -DSTOP.KEY=<stopKey> * -DSTOP.PORT=<stopPort> -jar start.jar --stop */ @Parameter(required = true) protected String stopKey; - + /** * Max time in seconds that the plugin will wait for confirmation that jetty has stopped. */ @Parameter protected int stopWait; - - - @Override - public void execute() throws MojoExecutionException, MojoFailureException + public void execute() throws MojoExecutionException, MojoFailureException { if (stopPort <= 0) - throw new MojoExecutionException("Please specify a valid port"); + throw new MojoExecutionException("Please specify a valid port"); if (stopKey == null) - throw new MojoExecutionException("Please specify a valid stopKey"); + throw new MojoExecutionException("Please specify a valid stopKey"); //Ensure jetty Server instance stops. Whether or not the remote process //also stops depends whether or not it was started with ShutdownMonitor.exitVm=true - String command = "forcestop"; - - try(Socket s=new Socket(InetAddress.getByName("127.0.0.1"),stopPort);) - { - OutputStream out=s.getOutputStream(); - out.write((stopKey+"\r\n"+command+"\r\n").getBytes()); + String command = "forcestop"; + + try (Socket s = new Socket(InetAddress.getByName("127.0.0.1"), stopPort)) + { + OutputStream out = s.getOutputStream(); + out.write((stopKey + "\r\n" + command + "\r\n").getBytes()); out.flush(); if (stopWait > 0) - { + { s.setSoTimeout(stopWait * 1000); s.getInputStream(); - getLog().info("Waiting "+stopWait+" seconds for jetty to stop"); + getLog().info("Waiting " + stopWait + " seconds for jetty to stop"); LineNumberReader lin = new LineNumberReader(new InputStreamReader(s.getInputStream())); String response; boolean stopped = false; @@ -98,7 +95,7 @@ public class JettyStopMojo extends AbstractMojo { stopped = true; getLog().info("Server reports itself as stopped"); - } + } } } } @@ -112,19 +109,23 @@ public class JettyStopMojo extends AbstractMojo } } - public int getStopPort() { + public int getStopPort() + { return stopPort; } - public void setStopPort(int stopPort) { + public void setStopPort(int stopPort) + { this.stopPort = stopPort; } - public String getStopKey() { + public String getStopKey() + { return stopKey; } - public void setStopKey(String stopKey) { + public void setStopKey(String stopKey) + { this.stopKey = stopKey; } } diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyWebAppContext.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyWebAppContext.java index 92982799df8..9dcca13ae69 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyWebAppContext.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyWebAppContext.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -50,49 +50,44 @@ import org.eclipse.jetty.webapp.WebInfConfiguration; /** * JettyWebAppContext - * + * * Extends the WebAppContext to specialize for the maven environment. * We pass in the list of files that should form the classpath for * the webapp when executing in the plugin, and any jetty-env.xml file * that may have been configured. - * */ public class JettyWebAppContext extends WebAppContext { private static final Logger LOG = Log.getLogger(JettyWebAppContext.class); - - private static final String DEFAULT_CONTAINER_INCLUDE_JAR_PATTERN = ".*/javax.servlet-[^/]*\\.jar$|.*/servlet-api-[^/]*\\.jar$|.*javax.servlet.jsp.jstl-[^/]*\\.jar|.*taglibs-standard-impl-.*\\.jar"; private static final String WEB_INF_CLASSES_PREFIX = "/WEB-INF/classes"; private static final String WEB_INF_LIB_PREFIX = "/WEB-INF/lib"; - public static final String[] MINIMUM_CONFIGURATION_CLASSES = { - "org.eclipse.jetty.maven.plugin.MavenWebInfConfiguration", - "org.eclipse.jetty.webapp.WebXmlConfiguration", - "org.eclipse.jetty.webapp.MetaInfConfiguration", - "org.eclipse.jetty.webapp.FragmentConfiguration", - "org.eclipse.jetty.webapp.JettyWebXmlConfiguration" - }; - public static final String[] DEFAULT_CONFIGURATION_CLASSES = { - "org.eclipse.jetty.maven.plugin.MavenWebInfConfiguration", - "org.eclipse.jetty.webapp.WebXmlConfiguration", - "org.eclipse.jetty.webapp.MetaInfConfiguration", - "org.eclipse.jetty.webapp.FragmentConfiguration", - "org.eclipse.jetty.plus.webapp.EnvConfiguration", - "org.eclipse.jetty.plus.webapp.PlusConfiguration", - "org.eclipse.jetty.annotations.AnnotationConfiguration", - "org.eclipse.jetty.webapp.JettyWebXmlConfiguration" - }; - + "org.eclipse.jetty.maven.plugin.MavenWebInfConfiguration", + "org.eclipse.jetty.webapp.WebXmlConfiguration", + "org.eclipse.jetty.webapp.MetaInfConfiguration", + "org.eclipse.jetty.webapp.FragmentConfiguration", + "org.eclipse.jetty.webapp.JettyWebXmlConfiguration" + }; + public static final String[] DEFAULT_CONFIGURATION_CLASSES = { + "org.eclipse.jetty.maven.plugin.MavenWebInfConfiguration", + "org.eclipse.jetty.webapp.WebXmlConfiguration", + "org.eclipse.jetty.webapp.MetaInfConfiguration", + "org.eclipse.jetty.webapp.FragmentConfiguration", + "org.eclipse.jetty.plus.webapp.EnvConfiguration", + "org.eclipse.jetty.plus.webapp.PlusConfiguration", + "org.eclipse.jetty.annotations.AnnotationConfiguration", + "org.eclipse.jetty.webapp.JettyWebXmlConfiguration" + }; public static final String[] QUICKSTART_CONFIGURATION_CLASSES = { - "org.eclipse.jetty.maven.plugin.MavenQuickStartConfiguration", - "org.eclipse.jetty.plus.webapp.EnvConfiguration", - "org.eclipse.jetty.plus.webapp.PlusConfiguration", - "org.eclipse.jetty.webapp.JettyWebXmlConfiguration" - }; + "org.eclipse.jetty.maven.plugin.MavenQuickStartConfiguration", + "org.eclipse.jetty.plus.webapp.EnvConfiguration", + "org.eclipse.jetty.plus.webapp.PlusConfiguration", + "org.eclipse.jetty.webapp.JettyWebXmlConfiguration" + }; private File _classes = null; private File _testClasses = null; @@ -105,128 +100,108 @@ public class JettyWebAppContext extends WebAppContext private Resource _quickStartWebXml; private String _originAttribute; private boolean _generateOrigin; - + /** * Set the "org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern" with a pattern for matching jars on * container classpath to scan. This is analogous to the WebAppContext.setAttribute() call. */ private String _containerIncludeJarPattern = null; - + /** * Set the "org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern" with a pattern for matching jars on * webapp's classpath to scan. This is analogous to the WebAppContext.setAttribute() call. */ private String _webInfIncludeJarPattern = null; - - /** * If there is no maven-war-plugin config for ordering of the current project in the - * sequence of overlays, use this to control whether the current project is added + * sequence of overlays, use this to control whether the current project is added * first or last in list of overlaid resources */ private boolean _baseAppFirst = true; - - private boolean _isGenerateQuickStart; private PreconfigureDescriptorProcessor _preconfigProcessor; - - - /* ------------------------------------------------------------ */ - public JettyWebAppContext () - throws Exception + public JettyWebAppContext() + throws Exception { - super(); + super(); // Turn off copyWebInf option as it is not applicable for plugin. super.setCopyWebInf(false); } - - /* ------------------------------------------------------------ */ + public void setContainerIncludeJarPattern(String pattern) { _containerIncludeJarPattern = pattern; } - - /* ------------------------------------------------------------ */ + public String getContainerIncludeJarPattern() { return _containerIncludeJarPattern; } - - /* ------------------------------------------------------------ */ + public String getWebInfIncludeJarPattern() { return _webInfIncludeJarPattern; } - - /* ------------------------------------------------------------ */ + public void setWebInfIncludeJarPattern(String pattern) { _webInfIncludeJarPattern = pattern; } - - /* ------------------------------------------------------------ */ + public List getClassPathFiles() { return this._classpathFiles; } - - /* ------------------------------------------------------------ */ - public void setJettyEnvXml (String jettyEnvXml) + + public void setJettyEnvXml(String jettyEnvXml) { this._jettyEnvXml = jettyEnvXml; } - - /* ------------------------------------------------------------ */ + public String getJettyEnvXml() { return this._jettyEnvXml; } - /* ------------------------------------------------------------ */ public void setClasses(File dir) { _classes = dir; } - - /* ------------------------------------------------------------ */ + public File getClasses() { return _classes; } - - /* ------------------------------------------------------------ */ - public void setWebInfLib (List jars) + + public void setWebInfLib(List jars) { _webInfJars.addAll(jars); } - - /* ------------------------------------------------------------ */ - public void setTestClasses (File dir) + + public void setTestClasses(File dir) { _testClasses = dir; } - - /* ------------------------------------------------------------ */ - public File getTestClasses () + + public File getTestClasses() { return _testClasses; } - - - /* ------------------------------------------------------------ */ + /** * Ordered list of wars to overlay on top of the current project. The list * may contain an overlay that represents the current project. + * * @param overlays the list of overlays */ - public void setOverlays (List overlays) + public void setOverlays(List overlays) { _overlays = overlays; } - + /** * @return the originAttribute */ @@ -259,62 +234,57 @@ public class JettyWebAppContext extends WebAppContext _generateOrigin = generateOrigin; } - /* ------------------------------------------------------------ */ public List getOverlays() { return _overlays; } - /* ------------------------------------------------------------ */ public void setBaseAppFirst(boolean value) { _baseAppFirst = value; } - /* ------------------------------------------------------------ */ public boolean getBaseAppFirst() { return _baseAppFirst; } - - /* ------------------------------------------------------------ */ - public void setQuickStartWebDescriptor (String quickStartWebXml) throws Exception + + public void setQuickStartWebDescriptor(String quickStartWebXml) throws Exception { setQuickStartWebDescriptor(Resource.newResource(quickStartWebXml)); } - - /* ------------------------------------------------------------ */ - protected void setQuickStartWebDescriptor (Resource quickStartWebXml) + + protected void setQuickStartWebDescriptor(Resource quickStartWebXml) { _quickStartWebXml = quickStartWebXml; } - - /* ------------------------------------------------------------ */ - public Resource getQuickStartWebDescriptor () + + public Resource getQuickStartWebDescriptor() { return _quickStartWebXml; } - - /* ------------------------------------------------------------ */ + /** - * This method is provided as a convenience for jetty maven plugin configuration + * This method is provided as a convenience for jetty maven plugin configuration + * * @param resourceBases Array of resources strings to set as a {@link ResourceCollection}. Each resource string may be a comma separated list of resources * @see Resource */ public void setResourceBases(String[] resourceBases) { List resources = new ArrayList(); - for (String rl:resourceBases) + for (String rl : resourceBases) { String[] rs = StringUtil.csvSplit(rl); - for (String r:rs) + for (String r : rs) + { resources.add(r); + } } - + setBaseResource(new ResourceCollection(resources.toArray(new String[resources.size()]))); } - - /* ------------------------------------------------------------ */ + public List getWebInfLib() { return _webInfJars; @@ -324,29 +294,24 @@ public class JettyWebAppContext extends WebAppContext { return _webInfClasses; } - - /* ------------------------------------------------------------ */ - public void setGenerateQuickStart (boolean quickStart) + + public void setGenerateQuickStart(boolean quickStart) { _isGenerateQuickStart = quickStart; } - - /* ------------------------------------------------------------ */ + public boolean isGenerateQuickStart() { return _isGenerateQuickStart; } - - - /* ------------------------------------------------------------ */ @Override protected void startWebapp() throws Exception { if (isGenerateQuickStart()) { if (getQuickStartWebDescriptor() == null) - throw new IllegalStateException ("No location to generate quickstart descriptor"); + throw new IllegalStateException("No location to generate quickstart descriptor"); QuickStartDescriptorGenerator generator = new QuickStartDescriptorGenerator(this, _preconfigProcessor.getXML(), _originAttribute, _generateOrigin); try (FileOutputStream fos = new FileOutputStream(getQuickStartWebDescriptor().getFile())) @@ -356,25 +321,29 @@ public class JettyWebAppContext extends WebAppContext } else { - if (LOG.isDebugEnabled()) { LOG.debug("Calling full start on webapp");} + if (LOG.isDebugEnabled()) + { + LOG.debug("Calling full start on webapp"); + } super.startWebapp(); } } - - /* ------------------------------------------------------------ */ + @Override protected void stopWebapp() throws Exception { if (isGenerateQuickStart()) return; - if (LOG.isDebugEnabled()) { LOG.debug("Calling stop of fully started webapp");} + if (LOG.isDebugEnabled()) + { + LOG.debug("Calling stop of fully started webapp"); + } super.stopWebapp(); } - - /* ------------------------------------------------------------ */ + @Override - public void doStart () throws Exception + public void doStart() throws Exception { if (isGenerateQuickStart()) @@ -388,24 +357,24 @@ public class JettyWebAppContext extends WebAppContext //Allow user to set up pattern for names of jars from the container classpath //that will be scanned - note that by default NO jars are scanned String tmp = _containerIncludeJarPattern; - if (tmp==null || "".equals(tmp)) - tmp = (String)getAttribute(WebInfConfiguration.CONTAINER_JAR_PATTERN); - + if (tmp == null || "".equals(tmp)) + tmp = (String)getAttribute(WebInfConfiguration.CONTAINER_JAR_PATTERN); + tmp = addPattern(tmp, DEFAULT_CONTAINER_INCLUDE_JAR_PATTERN); setAttribute(WebInfConfiguration.CONTAINER_JAR_PATTERN, tmp); - + //Allow user to set up pattern of jar names from WEB-INF that will be scanned. //Note that by default ALL jars considered to be in WEB-INF will be scanned - setting //a pattern restricts scanning if (_webInfIncludeJarPattern != null) setAttribute(WebInfConfiguration.WEBINF_JAR_PATTERN, _webInfIncludeJarPattern); - + //Set up the classes dirs that comprises the equivalent of WEB-INF/classes if (_testClasses != null) _webInfClasses.add(_testClasses); if (_classes != null) _webInfClasses.add(_classes); - + // Set up the classpath _classpathFiles = new ArrayList<>(); _classpathFiles.addAll(_webInfClasses); @@ -420,51 +389,46 @@ public class JettyWebAppContext extends WebAppContext if (fileName.endsWith(".jar")) _webInfJarMap.put(fileName, file); } - + //check for CDI initCDI(); - + // CHECK setShutdown(false); super.doStart(); } - - + @Override protected void loadConfigurations() throws Exception { super.loadConfigurations(); - + //inject configurations with config from maven plugin - for (Configuration c:getConfigurations()) + for (Configuration c : getConfigurations()) { if (c instanceof EnvConfiguration && getJettyEnvXml() != null) - ((EnvConfiguration)c).setJettyEnvXml(Resource.toURL(new File(getJettyEnvXml()))); + ((EnvConfiguration)c).setJettyEnvXml(Resource.toURL(new File(getJettyEnvXml()))); } } - - /* ------------------------------------------------------------ */ @Override - public void doStop () throws Exception - { + public void doStop() throws Exception + { if (_classpathFiles != null) _classpathFiles.clear(); _classpathFiles = null; - + _classes = null; _testClasses = null; - + if (_webInfJarMap != null) _webInfJarMap.clear(); - + _webInfClasses.clear(); _webInfJars.clear(); - - - + // CHECK setShutdown(true); //just wait a little while to ensure no requests are still being processed - Thread.currentThread().sleep(500L); + Thread.sleep(500L); super.doStop(); @@ -476,9 +440,7 @@ public class JettyWebAppContext extends WebAppContext getServletHandler().setServlets(new ServletHolder[0]); getServletHandler().setServletMappings(new ServletMapping[0]); } - - - /* ------------------------------------------------------------ */ + @Override public Resource getResource(String uriInContext) throws MalformedURLException { @@ -498,7 +460,7 @@ public class JettyWebAppContext extends WebAppContext // Replace /WEB-INF/classes with candidates for the classpath if (uri.startsWith(WEB_INF_CLASSES_PREFIX)) { - if (uri.equalsIgnoreCase(WEB_INF_CLASSES_PREFIX) || uri.equalsIgnoreCase(WEB_INF_CLASSES_PREFIX+"/")) + if (uri.equalsIgnoreCase(WEB_INF_CLASSES_PREFIX) || uri.equalsIgnoreCase(WEB_INF_CLASSES_PREFIX + "/")) { //exact match for a WEB-INF/classes, so preferentially return the resource matching the web-inf classes //rather than the test classes @@ -511,28 +473,28 @@ public class JettyWebAppContext extends WebAppContext { //try matching Resource res = null; - int i=0; + int i = 0; while (res == null && (i < _webInfClasses.size())) { - String newPath = uri.replace(WEB_INF_CLASSES_PREFIX, _webInfClasses.get(i).getPath()); + String newPath = StringUtil.replace(uri, WEB_INF_CLASSES_PREFIX, _webInfClasses.get(i).getPath()); res = Resource.newResource(newPath); if (!res.exists()) { - res = null; + res = null; i++; } } return res; } - } + } else if (uri.startsWith(WEB_INF_LIB_PREFIX)) { // Return the real jar file for all accesses to // /WEB-INF/lib/*.jar - String jarName = uri.replace(WEB_INF_LIB_PREFIX, ""); - if (jarName.startsWith("/") || jarName.startsWith("\\")) + String jarName = StringUtil.strip(uri, WEB_INF_LIB_PREFIX); + if (jarName.startsWith("/") || jarName.startsWith("\\")) jarName = jarName.substring(1); - if (jarName.length()==0) + if (jarName.length() == 0) return null; File jarFile = _webInfJarMap.get(jarName); if (jarFile != null) @@ -552,20 +514,18 @@ public class JettyWebAppContext extends WebAppContext } return resource; } - - - /* ------------------------------------------------------------ */ + @Override public Set getResourcePaths(String path) { // Try to get regular resource paths - this will get appropriate paths from any overlaid wars etc Set paths = super.getResourcePaths(path); - + if (path != null) { TreeSet allPaths = new TreeSet<>(); allPaths.addAll(paths); - + //add in the dependency jars as a virtual WEB-INF/lib entry if (path.startsWith(WEB_INF_LIB_PREFIX)) { @@ -577,11 +537,11 @@ public class JettyWebAppContext extends WebAppContext } else if (path.startsWith(WEB_INF_CLASSES_PREFIX)) { - int i=0; - + int i = 0; + while (i < _webInfClasses.size()) { - String newPath = path.replace(WEB_INF_CLASSES_PREFIX, _webInfClasses.get(i).getPath()); + String newPath = StringUtil.replace(path, WEB_INF_CLASSES_PREFIX, _webInfClasses.get(i).getPath()); allPaths.addAll(super.getResourcePaths(newPath)); i++; } @@ -590,35 +550,32 @@ public class JettyWebAppContext extends WebAppContext } return paths; } - - /* ------------------------------------------------------------ */ - public String addPattern (String s, String pattern) + + public String addPattern(String s, String pattern) { if (s == null) s = ""; else s = s.trim(); - + if (!s.contains(pattern)) { if (s.length() != 0) s = s + "|"; s = s + pattern; } - + return s; } - - - /* ------------------------------------------------------------ */ + public void initCDI() { Class cdiInitializer = null; try { cdiInitializer = Thread.currentThread().getContextClassLoader().loadClass("org.eclipse.jetty.cdi.servlet.JettyWeldInitializer"); - Method initWebAppMethod = cdiInitializer.getMethod("initWebApp", new Class[]{WebAppContext.class}); - initWebAppMethod.invoke(null, new Object[]{this}); + Method initWebAppMethod = cdiInitializer.getMethod("initWebApp", WebAppContext.class); + initWebAppMethod.invoke(null, this); } catch (ClassNotFoundException e) { @@ -630,7 +587,7 @@ public class JettyWebAppContext extends WebAppContext } catch (Exception e) { - LOG.warn("Problem initializing cdi", e); + LOG.warn("Problem initializing cdi", e); } } } diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/MavenQuickStartConfiguration.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/MavenQuickStartConfiguration.java index f7533e33b5d..03450a04954 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/MavenQuickStartConfiguration.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/MavenQuickStartConfiguration.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,11 +16,9 @@ // ======================================================================== // - package org.eclipse.jetty.maven.plugin; import java.io.File; -import java.util.Iterator; import org.eclipse.jetty.quickstart.QuickStartConfiguration; import org.eclipse.jetty.util.IO; @@ -33,63 +31,62 @@ import org.eclipse.jetty.webapp.WebAppContext; /** * MavenQuickStartConfiguration - * - * */ public class MavenQuickStartConfiguration extends QuickStartConfiguration { private static final Logger LOG = Log.getLogger(QuickStartConfiguration.class); - - @Override public void preConfigure(WebAppContext context) throws Exception { //check that webapp is suitable for quick start if (context.getBaseResource() == null) - throw new IllegalStateException ("No location for webapp"); + throw new IllegalStateException("No location for webapp"); - //look for quickstart-web.xml in WEB-INF of webapp Resource quickStartWebXml = ((JettyWebAppContext)context).getQuickStartWebDescriptor(); - LOG.debug("quickStartWebXml={}",quickStartWebXml); - + LOG.debug("quickStartWebXml={}", quickStartWebXml); + context.getMetaData().setWebXml(quickStartWebXml); } - @Override public void configure(WebAppContext context) throws Exception { - - JettyWebAppContext jwac = (JettyWebAppContext)context; - + + JettyWebAppContext jwac = (JettyWebAppContext)context; + //put the classes dir and all dependencies into the classpath if (jwac.getClassPathFiles() != null) { - if (LOG.isDebugEnabled()) LOG.debug("Setting up classpath ..."); - for(File classPathFile:jwac.getClassPathFiles()) + if (LOG.isDebugEnabled()) + LOG.debug("Setting up classpath ..."); + for (File classPathFile : jwac.getClassPathFiles()) + { ((WebAppClassLoader)context.getClassLoader()).addClassPath(classPathFile.getCanonicalPath()); + } } - + //Set up the quickstart environment for the context super.configure(context); - + // knock out environmental maven and plexus classes from webAppContext String[] existingServerClasses = context.getServerClasses(); - String[] newServerClasses = new String[2+(existingServerClasses==null?0:existingServerClasses.length)]; + String[] newServerClasses = new String[2 + (existingServerClasses == null ? 0 : existingServerClasses.length)]; newServerClasses[0] = "org.apache.maven."; newServerClasses[1] = "org.codehaus.plexus."; - System.arraycopy( existingServerClasses, 0, newServerClasses, 2, existingServerClasses.length ); + System.arraycopy(existingServerClasses, 0, newServerClasses, 2, existingServerClasses.length); if (LOG.isDebugEnabled()) { LOG.debug("Server classes:"); - for (int i=0;i findJars (WebAppContext context) - throws Exception + protected List findJars(WebAppContext context) + throws Exception { List list = new ArrayList<>(); JettyWebAppContext jwac = (JettyWebAppContext)context; List files = jwac.getWebInfLib(); if (files != null) { - files.forEach( file -> { - if (file.getName().toLowerCase(Locale.ENGLISH).endsWith(".jar") - || file.isDirectory()) + files.forEach(file -> + { + if (file.getName().toLowerCase(Locale.ENGLISH).endsWith(".jar") || file.isDirectory()) { try { - LOG.debug( " add resource to resources to examine {}", file ); + LOG.debug(" add resource to resources to examine {}", file); list.add(Resource.newResource(file.toURI())); } catch (Exception e) @@ -109,7 +113,7 @@ public class MavenWebInfConfiguration extends WebInfConfiguration LOG.warn("Bad url ", e); } } - } ); + }); } List superList = super.findJars(context); @@ -117,25 +121,23 @@ public class MavenWebInfConfiguration extends WebInfConfiguration list.addAll(superList); return list; } - - - - - /** + /** * Add in the classes dirs from test/classes and target/classes + * * @see org.eclipse.jetty.webapp.WebInfConfiguration#findClassDirs(org.eclipse.jetty.webapp.WebAppContext) */ @Override protected List findClassDirs(WebAppContext context) throws Exception { List list = new ArrayList<>(); - + JettyWebAppContext jwac = (JettyWebAppContext)context; List files = jwac.getWebInfClasses(); if (files != null) { - files.forEach( file -> { + files.forEach(file -> + { if (file.exists() && file.isDirectory()) { try @@ -147,16 +149,12 @@ public class MavenWebInfConfiguration extends WebInfConfiguration LOG.warn("Bad url ", e); } } - } ); - + }); } - + List classesDirs = super.findClassDirs(context); if (classesDirs != null) list.addAll(classesDirs); return list; } - - - } diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/Overlay.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/Overlay.java index e507d4f04e9..0378897af24 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/Overlay.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/Overlay.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,48 +16,44 @@ // ======================================================================== // - package org.eclipse.jetty.maven.plugin; import org.eclipse.jetty.util.resource.Resource; /** * Overlay - * - * */ public class Overlay { private OverlayConfig _config; private Resource _resource; - - public Overlay (OverlayConfig config, Resource resource) + + public Overlay(OverlayConfig config, Resource resource) { _config = config; _resource = resource; } - public Overlay (OverlayConfig config) + public Overlay(OverlayConfig config) { _config = config; } - - - public void setResource (Resource r) + + public void setResource(Resource r) { _resource = r; } - - public Resource getResource () + + public Resource getResource() { return _resource; } - - public OverlayConfig getConfig () + + public OverlayConfig getConfig() { return _config; } - + @Override public String toString() { diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/OverlayConfig.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/OverlayConfig.java index bdc11cc9fd6..cf7bde6ece5 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/OverlayConfig.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/OverlayConfig.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,7 +16,6 @@ // ======================================================================== // - package org.eclipse.jetty.maven.plugin; import java.util.ArrayList; @@ -40,20 +39,22 @@ public class OverlayConfig private List excludes; private boolean skip; private boolean filtered; - - public OverlayConfig() {} - + + public OverlayConfig() + { + } + public OverlayConfig(String fmt, List defaultIncludes, List defaultExcludes) { if (fmt == null) return; String[] atoms = StringUtil.csvSplit(fmt); - for (int i=0;i defaultIncludes, List defaultExcludes) { Xpp3Dom node = root.getChild("groupId"); - setGroupId(node==null?null:node.getValue()); - + setGroupId(node == null ? null : node.getValue()); + node = root.getChild("artifactId"); - setArtifactId(node==null?null:node.getValue()); - + setArtifactId(node == null ? null : node.getValue()); + node = root.getChild("classifier"); - setClassifier(node==null?null:node.getValue()); - + setClassifier(node == null ? null : node.getValue()); + node = root.getChild("targetPath"); - setTargetPath(node==null?null:node.getValue()); - + setTargetPath(node == null ? null : node.getValue()); + node = root.getChild("skip"); - setSkip(node==null?false:Boolean.valueOf(node.getValue())); + setSkip(node == null ? false : Boolean.valueOf(node.getValue())); node = root.getChild("filtered"); - setFiltered(node==null?false:Boolean.valueOf(node.getValue())); + setFiltered(node == null ? false : Boolean.valueOf(node.getValue())); node = root.getChild("includes"); List includes = null; if (node != null && node.getChildCount() > 0) { Xpp3Dom[] list = node.getChildren("include"); - for (int j=0; list != null && j < list.length;j++) + for (int j = 0; list != null && j < list.length; j++) { if (includes == null) includes = new ArrayList<>(); @@ -153,14 +154,13 @@ public class OverlayConfig includes.addAll(defaultIncludes); } setIncludes(includes); - - + node = root.getChild("excludes"); List excludes = null; if (node != null && node.getChildCount() > 0) { Xpp3Dom[] list = node.getChildren("exclude"); - for (int j=0; list != null && j < list.length;j++) + for (int j = 0; list != null && j < list.length; j++) { if (excludes == null) excludes = new ArrayList<>(); @@ -174,7 +174,7 @@ public class OverlayConfig } setExcludes(excludes); } - + public String getTargetPath() { return targetPath; @@ -254,60 +254,51 @@ public class OverlayConfig { this.filtered = filtered; } - + public boolean isCurrentProject() { - if (this.groupId == null && this.artifactId == null) - return true; - return false; + return this.groupId == null && this.artifactId == null; } - /** * Check if this overlay configuration matches an Artifact's info - * + * * @param gid Artifact groupId * @param aid Artifact artifactId * @param cls Artifact classifier * @return true if matched */ - public boolean matchesArtifact (String gid, String aid, String cls) + public boolean matchesArtifact(String gid, String aid, String cls) { - if (((getGroupId() == null && gid == null) || (getGroupId() != null && getGroupId().equals(gid))) - &&((getArtifactId() == null && aid == null) || (getArtifactId() != null && getArtifactId().equals(aid))) - &&((getClassifier() == null) || (getClassifier().equals(cls)))) - return true; - - return false; + return ((getGroupId() == null && gid == null) || (getGroupId() != null && getGroupId().equals(gid))) && + ((getArtifactId() == null && aid == null) || (getArtifactId() != null && getArtifactId().equals(aid))) && + ((getClassifier() == null) || (getClassifier().equals(cls))); } - + /** * Check if this overlay configuration matches an Artifact's info - * + * * @param gid the group id * @param aid the artifact id * @return true if matched */ - public boolean matchesArtifact (String gid, String aid) + public boolean matchesArtifact(String gid, String aid) { - if (((getGroupId() == null && gid == null) || (getGroupId() != null && getGroupId().equals(gid))) - &&((getArtifactId() == null && aid == null) || (getArtifactId() != null && getArtifactId().equals(aid)))) - return true; - - return false; + return ((getGroupId() == null && gid == null) || (getGroupId() != null && getGroupId().equals(gid))) && + ((getArtifactId() == null && aid == null) || (getArtifactId() != null && getArtifactId().equals(aid))); } - + @Override public String toString() { StringBuilder strbuff = new StringBuilder(); - strbuff.append((groupId != null ? groupId : "")+","); - strbuff.append((artifactId != null ? artifactId : "")+","); - strbuff.append((classifier != null ? classifier : "")+","); - strbuff.append((targetPath != null ? targetPath : "")+","); - strbuff.append(""+skip+","); - strbuff.append(""+filtered+","); - + strbuff.append((groupId != null ? groupId : "") + ","); + strbuff.append((artifactId != null ? artifactId : "") + ","); + strbuff.append((classifier != null ? classifier : "") + ","); + strbuff.append((targetPath != null ? targetPath : "") + ","); + strbuff.append("" + skip + ","); + strbuff.append("" + filtered + ","); + if (includes != null) { Iterator itor = includes.iterator(); @@ -318,7 +309,7 @@ public class OverlayConfig strbuff.append(";"); } } - + strbuff.append(", "); if (excludes != null) @@ -331,7 +322,7 @@ public class OverlayConfig strbuff.append(";"); } } - + return strbuff.toString(); } } diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/PluginLog.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/PluginLog.java index ec0ae63e628..0cd98fe0634 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/PluginLog.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/PluginLog.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -22,23 +22,21 @@ import org.apache.maven.plugin.logging.Log; /** * PluginLog - * + * * Convenience class to provide access to the plugin * Log for non-mojo classes. - * */ public class PluginLog { private static Log log = null; - + public static void setLog(Log l) { log = l; } - + public static Log getLog() { return log; } - } diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ScanPattern.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ScanPattern.java index 9c420348d9d..61fb6c166ac 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ScanPattern.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ScanPattern.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -30,22 +30,22 @@ public class ScanPattern { private List _includes = Collections.emptyList(); private List _excludes = Collections.emptyList(); - - public void setIncludes (List includes) + + public void setIncludes(List includes) { - _includes= includes; + _includes = includes; } - + public void setExcludes(List excludes) { _excludes = excludes; } - + public List getIncludes() { return _includes; } - + public List getExcludes() { return _excludes; diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ScanTargetPattern.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ScanTargetPattern.java index c25c3d63661..567a66113ba 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ScanTargetPattern.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ScanTargetPattern.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -25,22 +25,22 @@ import java.util.List; /** * ScanTargetPattern * - * Utility class to provide the ability for the mvn jetty:run - * mojo to be able to specify filesets of extra files to + * Utility class to provide the ability for the mvn jetty:run + * mojo to be able to specify filesets of extra files to * regularly scan for changes in order to redeploy the webapp. - * + * * For example: - * + * * <scanTargetPattern> - * <directory>/some/place</directory> - * <includes> - * <include>some ant pattern here </include> - * <include>some ant pattern here </include> - * </includes> - * <excludes> - * <exclude>some ant pattern here </exclude> - * <exclude>some ant pattern here </exclude> - * </excludes> + * <directory>/some/place</directory> + * <includes> + * <include>some ant pattern here </include> + * <include>some ant pattern here </include> + * </includes> + * <excludes> + * <exclude>some ant pattern here </exclude> + * <exclude>some ant pattern here </exclude> + * </excludes> * </scanTargetPattern> */ public class ScanTargetPattern @@ -63,29 +63,28 @@ public class ScanTargetPattern { this._directory = directory; } - - public void setIncludes (List includes) + + public void setIncludes(List includes) { if (_pattern == null) _pattern = new ScanPattern(); _pattern.setIncludes(includes); } - + public void setExcludes(List excludes) { if (_pattern == null) _pattern = new ScanPattern(); _pattern.setExcludes(excludes); } - + public List getIncludes() { - return (_pattern == null? Collections.emptyList() : _pattern.getIncludes()); - } - - public List getExcludes() - { - return (_pattern == null? Collections.emptyList() : _pattern.getExcludes()); + return (_pattern == null ? Collections.emptyList() : _pattern.getIncludes()); } + public List getExcludes() + { + return (_pattern == null ? Collections.emptyList() : _pattern.getExcludes()); + } } diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/SelectiveJarResource.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/SelectiveJarResource.java index 104ef924fa1..b33f9ef832c 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/SelectiveJarResource.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/SelectiveJarResource.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -33,59 +33,55 @@ import java.util.jar.Manifest; import org.codehaus.plexus.util.SelectorUtils; import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.resource.JarResource; - - /** * SelectiveJarResource * * Selectively copies resources from a jar file based on includes/excludes. - * */ public class SelectiveJarResource extends JarResource -{ +{ private static final Logger LOG = Log.getLogger(SelectiveJarResource.class); - public static final List DEFAULT_INCLUDES = Arrays.asList(new String[]{"**"});// No includes supplied, so set it to 'matches all' + public static final List DEFAULT_INCLUDES = Arrays.asList("**");// No includes supplied, so set it to 'matches all' public static final List DEFAULT_EXCLUDES = Collections.emptyList(); //No includes, set to no exclusions List _includes = null; List _excludes = null; boolean _caseSensitive = false; - + public SelectiveJarResource(URL url) { super(url); } - + public SelectiveJarResource(URL url, boolean useCaches) { super(url, useCaches); } - - public void setCaseSensitive (boolean caseSensitive) + + public void setCaseSensitive(boolean caseSensitive) { _caseSensitive = caseSensitive; } - - public void setIncludes (List patterns) + + public void setIncludes(List patterns) { _includes = patterns; } - - - public void setExcludes (List patterns) + + public void setExcludes(List patterns) { _excludes = patterns; } - - - protected boolean isIncluded (String name) - { - for (String include:_includes) + + protected boolean isIncluded(String name) + { + for (String include : _includes) { if (SelectorUtils.matchPath(include, name, _caseSensitive)) { @@ -94,23 +90,20 @@ public class SelectiveJarResource extends JarResource } return false; } - - protected boolean isExcluded (String name) + + protected boolean isExcluded(String name) { - for (String exclude:_excludes) + for (String exclude : _excludes) { - if (SelectorUtils.matchPath (exclude, name, _caseSensitive)) + if (SelectorUtils.matchPath(exclude, name, _caseSensitive)) { return true; } } return false; } - - - - /** + /** * @see org.eclipse.jetty.util.resource.JarResource#copyTo(java.io.File) */ @Override @@ -120,41 +113,41 @@ public class SelectiveJarResource extends JarResource _includes = DEFAULT_INCLUDES; if (_excludes == null) _excludes = DEFAULT_EXCLUDES; - + //Copy contents of the jar file to the given directory, //using the includes and excludes patterns to control which //parts of the jar file are copied if (!exists()) return; - + String urlString = this.getURL().toExternalForm().trim(); int endOfJarUrl = urlString.indexOf("!/"); - int startOfJarUrl = (endOfJarUrl >= 0?4:0); - + int startOfJarUrl = (endOfJarUrl >= 0 ? 4 : 0); + if (endOfJarUrl < 0) - throw new IOException("Not a valid jar url: "+urlString); - + throw new IOException("Not a valid jar url: " + urlString); + URL jarFileURL = new URL(urlString.substring(startOfJarUrl, endOfJarUrl)); - + try (InputStream is = jarFileURL.openConnection().getInputStream(); - JarInputStream jin = new JarInputStream(is)) + JarInputStream jin = new JarInputStream(is)) { JarEntry entry; - while((entry=jin.getNextJarEntry())!=null) + while ((entry = jin.getNextJarEntry()) != null) { String entryName = entry.getName(); - LOG.debug("Looking at "+entryName); - String dotCheck = entryName.replace('\\', '/'); + LOG.debug("Looking at " + entryName); + String dotCheck = StringUtil.replace(entryName, '\\', '/'); dotCheck = URIUtil.canonicalPath(dotCheck); if (dotCheck == null) { - LOG.info("Invalid entry: "+entryName); + LOG.info("Invalid entry: " + entryName); continue; } - File file=new File(directory,entryName); + File file = new File(directory, entryName); if (entry.isDirectory()) { @@ -187,11 +180,11 @@ public class SelectiveJarResource extends JarResource // Make file try (OutputStream fout = new FileOutputStream(file)) { - IO.copy(jin,fout); + IO.copy(jin, fout); } // touch the file. - if (entry.getTime()>=0) + if (entry.getTime() >= 0) file.setLastModified(entry.getTime()); } else @@ -207,7 +200,7 @@ public class SelectiveJarResource extends JarResource { if (isIncluded("META-INF") && !isExcluded("META-INF")) { - File metaInf = new File (directory, "META-INF"); + File metaInf = new File(directory, "META-INF"); metaInf.mkdir(); File f = new File(metaInf, "MANIFEST.MF"); try (OutputStream fout = new FileOutputStream(f)) @@ -218,5 +211,4 @@ public class SelectiveJarResource extends JarResource } } } - } diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ServerConnectorListener.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ServerConnectorListener.java index e55fb8b389b..48e913e3bb4 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ServerConnectorListener.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ServerConnectorListener.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,13 +16,8 @@ // ======================================================================== // - package org.eclipse.jetty.maven.plugin; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.util.component.AbstractLifeCycle.AbstractLifeCycleListener; -import org.eclipse.jetty.util.component.LifeCycle; - import java.io.Writer; import java.nio.file.AtomicMoveNotSupportedException; import java.nio.file.Files; @@ -30,10 +25,14 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.util.component.AbstractLifeCycle.AbstractLifeCycleListener; +import org.eclipse.jetty.util.component.LifeCycle; + /** * ServerConnectorListener * - * This is for test support, where we need jetty to run on a random port, and we need + * This is for test support, where we need jetty to run on a random port, and we need * a client to be able to find out which port was picked. */ public class ServerConnectorListener extends AbstractLifeCycleListener @@ -42,9 +41,7 @@ public class ServerConnectorListener extends AbstractLifeCycleListener private String _fileName; private String _sysPropertyName; - - - /** + /** * @see org.eclipse.jetty.util.component.AbstractLifeCycle.AbstractLifeCycleListener#lifeCycleStarted(org.eclipse.jetty.util.component.LifeCycle) */ @Override @@ -54,32 +51,32 @@ public class ServerConnectorListener extends AbstractLifeCycleListener { try { - Path tmp = Files.createTempFile( "jettyport", ".tmp" ); - try (Writer writer = Files.newBufferedWriter( tmp )) + Path tmp = Files.createTempFile("jettyport", ".tmp"); + try (Writer writer = Files.newBufferedWriter(tmp)) { - writer.write( String.valueOf( ( (ServerConnector) event ).getLocalPort() ) ); + writer.write(String.valueOf(((ServerConnector)event).getLocalPort())); } Path path = Paths.get(getFileName()); Files.deleteIfExists(path); try { - Files.move( tmp, path, StandardCopyOption.ATOMIC_MOVE ); + Files.move(tmp, path, StandardCopyOption.ATOMIC_MOVE); } - catch ( AtomicMoveNotSupportedException e ) // can append on some os (windows).. so try again without the option + catch (AtomicMoveNotSupportedException e) // can append on some os (windows).. so try again without the option { - Files.move( tmp, path); + Files.move(tmp, path); } } catch (Exception e) { - throw new RuntimeException (e); + throw new RuntimeException(e); } } - + if (getSysPropertyName() != null) { - System.setProperty(_sysPropertyName,String.valueOf(((ServerConnector)event).getLocalPort())); + System.setProperty(_sysPropertyName, String.valueOf(((ServerConnector)event).getLocalPort())); } super.lifeCycleStarted(event); } @@ -116,6 +113,4 @@ public class ServerConnectorListener extends AbstractLifeCycleListener { _sysPropertyName = sysPropertyName; } - - } diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ServerListener.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ServerListener.java index efc171834b9..0037e4f6cdf 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ServerListener.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ServerListener.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,7 +16,6 @@ // ======================================================================== // - package org.eclipse.jetty.maven.plugin; import org.eclipse.jetty.util.component.LifeCycle; @@ -31,29 +30,29 @@ import org.eclipse.jetty.util.resource.Resource; */ public class ServerListener implements LifeCycle.Listener { - + private String _tokenFile; - + public void setTokenFile(String file) { - _tokenFile = file; + _tokenFile = file; } - - public String getTokenFile () + public String getTokenFile() { return _tokenFile; } - /** + + /** * @see org.eclipse.jetty.util.component.LifeCycle.Listener#lifeCycleStarting(org.eclipse.jetty.util.component.LifeCycle) */ @Override public void lifeCycleStarting(LifeCycle event) { - + } - /** + /** * @see org.eclipse.jetty.util.component.LifeCycle.Listener#lifeCycleStarted(org.eclipse.jetty.util.component.LifeCycle) */ @Override @@ -71,35 +70,32 @@ public class ServerListener implements LifeCycle.Listener throw new IllegalStateException(e); } } - } - /** + /** * @see org.eclipse.jetty.util.component.LifeCycle.Listener#lifeCycleFailure(org.eclipse.jetty.util.component.LifeCycle, java.lang.Throwable) */ @Override public void lifeCycleFailure(LifeCycle event, Throwable cause) { - + } - /** + /** * @see org.eclipse.jetty.util.component.LifeCycle.Listener#lifeCycleStopping(org.eclipse.jetty.util.component.LifeCycle) */ @Override public void lifeCycleStopping(LifeCycle event) { - + } - /** + /** * @see org.eclipse.jetty.util.component.LifeCycle.Listener#lifeCycleStopped(org.eclipse.jetty.util.component.LifeCycle) */ @Override public void lifeCycleStopped(LifeCycle event) { - + } - - } diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ServerSupport.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ServerSupport.java index 36eab2e0418..58548a7f796 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ServerSupport.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ServerSupport.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,7 +16,6 @@ // ======================================================================== // - package org.eclipse.jetty.maven.plugin; import java.io.File; @@ -33,7 +32,6 @@ import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.ContextHandlerCollection; import org.eclipse.jetty.server.handler.DefaultHandler; import org.eclipse.jetty.server.handler.HandlerCollection; -import org.eclipse.jetty.server.handler.RequestLogHandler; import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.webapp.Configuration; import org.eclipse.jetty.webapp.WebAppContext; @@ -43,123 +41,116 @@ import org.eclipse.jetty.xml.XmlConfiguration; * ServerSupport * * Helps configure the Server instance. - * */ public class ServerSupport { - - public static void configureDefaultConfigurationClasses (Server server) + + public static void configureDefaultConfigurationClasses(Server server) { server.setAttribute(Configuration.ATTR, JettyWebAppContext.DEFAULT_CONFIGURATION_CLASSES); } - - + /** * Set up the handler structure to receive a webapp. * Also put in a DefaultHandler so we get a nice page * than a 404 if we hit the root and the webapp's * context isn't at root. + * * @param server the server * @param requestLog the request log * @throws Exception if unable to configure the handlers */ - public static void configureHandlers (Server server, RequestLog requestLog) throws Exception + public static void configureHandlers(Server server, RequestLog requestLog) throws Exception { if (server == null) - throw new IllegalArgumentException ("Server is null"); + throw new IllegalArgumentException("Server is null"); DefaultHandler defaultHandler = new DefaultHandler(); - RequestLogHandler requestLogHandler = new RequestLogHandler(); if (requestLog != null) - requestLogHandler.setRequestLog(requestLog); + server.setRequestLog(requestLog); ContextHandlerCollection contexts = findContextHandlerCollection(server); if (contexts == null) - { + { contexts = new ContextHandlerCollection(); - HandlerCollection handlers = (HandlerCollection)server.getChildHandlerByClass(HandlerCollection.class); + HandlerCollection handlers = server.getChildHandlerByClass(HandlerCollection.class); if (handlers == null) { - handlers = new HandlerCollection(); - server.setHandler(handlers); - handlers.setHandlers(new Handler[]{contexts, defaultHandler, requestLogHandler}); + handlers = new HandlerCollection(); + server.setHandler(handlers); + handlers.setHandlers(new Handler[]{contexts, defaultHandler}); } else { handlers.addHandler(contexts); } - } + } } - /** * Configure at least one connector for the server - * + * * @param server the server * @param connector the connector */ - public static void configureConnectors (Server server, Connector connector) + public static void configureConnectors(Server server, Connector connector) { if (server == null) throw new IllegalArgumentException("Server is null"); - + //if a connector is provided, use it if (connector != null) { server.addConnector(connector); return; } - - // if the user hasn't configured the connectors in a jetty.xml file so use a default one Connector[] connectors = server.getConnectors(); if (connectors == null || connectors.length == 0) { //Make a new default connector - MavenServerConnector tmp = new MavenServerConnector(); + MavenServerConnector tmp = new MavenServerConnector(); //use any jetty.http.port settings provided String port = System.getProperty(MavenServerConnector.PORT_SYSPROPERTY, System.getProperty("jetty.port", MavenServerConnector.DEFAULT_PORT_STR)); tmp.setPort(Integer.parseInt(port.trim())); tmp.setServer(server); - server.setConnectors(new Connector[] {tmp}); + server.setConnectors(new Connector[]{tmp}); } } - - + /** * Set up any security LoginServices provided. - * + * * @param server the server * @param loginServices the login services */ - public static void configureLoginServices (Server server, LoginService[] loginServices) + public static void configureLoginServices(Server server, LoginService[] loginServices) { if (server == null) - throw new IllegalArgumentException ("Server is null"); + throw new IllegalArgumentException("Server is null"); if (loginServices != null) { - for (LoginService loginService:loginServices) + for (LoginService loginService : loginServices) { - PluginLog.getLog().debug(loginService.getClass().getName() + ": "+ loginService.toString()); + PluginLog.getLog().debug(loginService.getClass().getName() + ": " + loginService.toString()); server.addBean(loginService); } } } - - public static void addWebApplication(Server server, WebAppContext webapp) throws Exception - { - if (server == null) - throw new IllegalArgumentException ("Server is null"); - ContextHandlerCollection contexts = findContextHandlerCollection(server); - if (contexts == null) - throw new IllegalStateException("ContextHandlerCollection is null"); - contexts.addHandler (webapp); - } - - public static ContextHandlerCollection findContextHandlerCollection (Server server) + public static void addWebApplication(Server server, WebAppContext webapp) throws Exception + { + if (server == null) + throw new IllegalArgumentException("Server is null"); + ContextHandlerCollection contexts = findContextHandlerCollection(server); + if (contexts == null) + throw new IllegalStateException("ContextHandlerCollection is null"); + contexts.addHandler(webapp); + } + + public static ContextHandlerCollection findContextHandlerCollection(Server server) { if (server == null) return null; @@ -167,40 +158,37 @@ public class ServerSupport return server.getChildHandlerByClass(ContextHandlerCollection.class); } - /** * Apply xml files to server instance. - * + * * @param server the server to apply the xml to * @param files the list of xml files * @param properties list of jetty properties * @return the Server implementation, after the xml is applied * @throws Exception if unable to apply the xml configuration */ - public static Server applyXmlConfigurations (Server server, List files, Map properties) - throws Exception + public static Server applyXmlConfigurations(Server server, List files, Map properties) + throws Exception { if (files == null || files.isEmpty()) return server; - Map lastMap = new HashMap<>(); + Map lastMap = new HashMap<>(); if (server != null) lastMap.put("Server", server); - - for ( File xmlFile : files ) + for (File xmlFile : files) { if (PluginLog.getLog() != null) - PluginLog.getLog().info( "Configuring Jetty from xml configuration file = " + xmlFile.getCanonicalPath() ); - + PluginLog.getLog().info("Configuring Jetty from xml configuration file = " + xmlFile.getCanonicalPath()); XmlConfiguration xmlConfiguration = new XmlConfiguration(Resource.toURL(xmlFile)); - + //add in any properties if (properties != null) { - for (Map.Entry e:properties.entrySet()) + for (Map.Entry e : properties.entrySet()) { xmlConfiguration.getProperties().put(e.getKey(), e.getValue()); } @@ -208,35 +196,33 @@ public class ServerSupport //chain ids from one config file to another if (lastMap != null) - xmlConfiguration.getIdMap().putAll(lastMap); + xmlConfiguration.getIdMap().putAll(lastMap); //Set the system properties each time in case the config file set a new one Enumeration ensysprop = System.getProperties().propertyNames(); while (ensysprop.hasMoreElements()) { String name = (String)ensysprop.nextElement(); - xmlConfiguration.getProperties().put(name,System.getProperty(name)); + xmlConfiguration.getProperties().put(name, System.getProperty(name)); } - xmlConfiguration.configure(); + xmlConfiguration.configure(); lastMap = xmlConfiguration.getIdMap(); } - + return (Server)lastMap.get("Server"); } /** * Apply xml files to server instance. - * + * * @param server the Server instance to configure * @param files the xml configs to apply * @return the Server after application of configs - * * @throws Exception if unable to apply the xml configuration */ - public static Server applyXmlConfigurations (Server server, List files) - throws Exception + public static Server applyXmlConfigurations(Server server, List files) + throws Exception { return applyXmlConfigurations(server, files, null); } - } diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/Starter.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/Starter.java index 91938bb2e05..7d76d8124a5 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/Starter.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/Starter.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -33,61 +33,56 @@ import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.resource.Resource; - - /** * Starter Class which is exec'ed to create a new jetty process. Used by the JettyRunForked mojo. */ public class Starter -{ +{ private static final Logger LOG = Log.getLogger(Starter.class); private List jettyXmls; // list of jetty.xml config files to apply private Server server; private JettyWebAppContext webApp; - private Map jettyProperties; //optional list of jetty properties to set - - private int stopPort=0; - private String stopKey=null; + private Map jettyProperties; //optional list of jetty properties to set + + private int stopPort = 0; + private String stopKey = null; private File propsFile; private String token; - - - - public void configureJetty () throws Exception + public void configureJetty() throws Exception { LOG.debug("Starting Jetty Server ..."); Resource.setDefaultUseCaches(false); - + //apply any configs from jetty.xml files first - applyJettyXml (); + applyJettyXml(); //ensure there's a connector ServerSupport.configureConnectors(server, null); //check if contexts already configured, create if not ServerSupport.configureHandlers(server, null); - + //Set up list of default Configurations to apply to a webapp ServerSupport.configureDefaultConfigurationClasses(server); - + webApp = new JettyWebAppContext(); - + //configure webapp from properties file describing unassembled webapp configureWebApp(); - + //make it a quickstart if the quickstart-web.xml file exists if (webApp.getTempDirectory() != null) { - File qs = new File (webApp.getTempDirectory(), "quickstart-web.xml"); + File qs = new File(webApp.getTempDirectory(), "quickstart-web.xml"); if (qs.exists() && qs.isFile()) webApp.setQuickStartWebDescriptor(Resource.newResource(qs)); } - + ServerSupport.addWebApplication(server, webApp); - if(stopPort>0 && stopKey!=null) + if (stopPort > 0 && stopKey != null) { ShutdownMonitor monitor = ShutdownMonitor.getInstance(); monitor.setPort(stopPort); @@ -96,20 +91,20 @@ public class Starter } } - public void configureWebApp () - throws Exception + public void configureWebApp() + throws Exception { if (propsFile == null) return; //apply a properties file that defines the things that we configure in the jetty:run plugin - WebAppPropertyConverter.fromProperties(webApp, propsFile, server, jettyProperties); + WebAppPropertyConverter.fromProperties(webApp, propsFile, server, jettyProperties); } - public void getConfiguration (String[] args) - throws Exception + public void getConfiguration(String[] args) + throws Exception { - for (int i=0; i(); String[] names = StringUtil.csvSplit(args[++i]); - for (int j=0; names!= null && j < names.length; j++) + for (int j = 0; names != null && j < names.length; j++) { jettyXmls.add(new File(names[j].trim())); } @@ -143,14 +138,13 @@ public class Starter propsFile = new File(args[++i].trim()); continue; } - + //--token if ("--token".equals(args[i])) { token = args[++i].trim(); continue; } - //assume everything else is a jetty property to be passed in if (jettyProperties == null) @@ -162,21 +156,18 @@ public class Starter } } - public void run() throws Exception { LOG.info("Started Jetty Server"); - server.start(); + server.start(); } - - public void join () throws Exception + public void join() throws Exception { server.join(); } - - public void communicateStartupResult () + public void communicateStartupResult() { if (token != null) { @@ -187,14 +178,14 @@ public class Starter } catch (Exception x) { - throw new IllegalStateException (x); + throw new IllegalStateException(x); } } } - - + /** * Apply any jetty xml files given + * * @throws Exception if unable to apply the xml */ public void applyJettyXml() throws Exception @@ -202,15 +193,12 @@ public class Starter Server tmp = ServerSupport.applyXmlConfigurations(server, jettyXmls, jettyProperties); if (server == null) server = tmp; - + if (server == null) server = new Server(); } - - - - protected void prependHandler (Handler handler, HandlerCollection handlers) + protected void prependHandler(Handler handler, HandlerCollection handlers) { if (handler == null || handlers == null) return; @@ -223,45 +211,43 @@ public class Starter } /** - * @param csv - * @return + * */ - private List fromCSV (String csv) + private List fromCSV(String csv) { if (csv == null || "".equals(csv.trim())) return null; String[] atoms = StringUtil.csvSplit(csv); List list = new ArrayList(); - for (String a:atoms) + for (String a : atoms) { list.add(a.trim()); } return list; } - + /** * @param args Starter arguments */ public static final void main(String[] args) { if (args == null) - System.exit(1); - - Starter starter = null; - try - { - starter = new Starter(); - starter.getConfiguration(args); - starter.configureJetty(); - starter.run(); - starter.communicateStartupResult(); - starter.join(); - } - catch (Exception e) - { - e.printStackTrace(); - System.exit(1); - } + System.exit(1); + Starter starter = null; + try + { + starter = new Starter(); + starter.getConfiguration(args); + starter.configureJetty(); + starter.run(); + starter.communicateStartupResult(); + starter.join(); + } + catch (Exception e) + { + e.printStackTrace(); + System.exit(1); + } } } diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/SystemProperties.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/SystemProperties.java index 240528a9002..ada9c59824b 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/SystemProperties.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/SystemProperties.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -27,7 +27,7 @@ import java.util.Map; * SystemProperties * * Map of name to SystemProperty. - * + * * When a SystemProperty instance is added, if it has not * been already set (eg via the command line java system property) * then it will be set. @@ -36,24 +36,23 @@ public class SystemProperties { private final Map properties; private boolean force; - + public SystemProperties() { properties = new HashMap<>(); } - - public void setForce (boolean force) + + public void setForce(boolean force) { this.force = force; } - - public boolean getForce () + + public boolean getForce() { return this.force; } - - - public void setSystemProperty (SystemProperty prop) + + public void setSystemProperty(SystemProperty prop) { properties.put(prop.getName(), prop); if (!force) @@ -61,18 +60,18 @@ public class SystemProperties else prop.setAnyway(); } - + public SystemProperty getSystemProperty(String name) { return properties.get(name); } - + public boolean containsSystemProperty(String name) { - return properties.containsKey(name); + return properties.containsKey(name); } - - public List getSystemProperties () + + public List getSystemProperties() { return new ArrayList<>(properties.values()); } diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/SystemProperty.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/SystemProperty.java index 7217ebe7942..73e83a67af6 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/SystemProperty.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/SystemProperty.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,23 +20,21 @@ package org.eclipse.jetty.maven.plugin; /** * SystemProperty - * + * * Provides the ability to set System properties - * for the mojo execution. A value will only + * for the mojo execution. A value will only * be set if it is not set already. That is, if * it was set on the command line or by the system, - * it won't be overridden by settings in the + * it won't be overridden by settings in the * plugin's configuration. - * */ public class SystemProperty { - private String name; private String value; private boolean isSet; - + /** * @return Returns the name. */ @@ -44,6 +42,7 @@ public class SystemProperty { return this.name; } + /** * @param name The name to set. */ @@ -57,10 +56,11 @@ public class SystemProperty return this.name; } - public void setKey (String name) + public void setKey(String name) { this.name = name; } + /** * @return Returns the value. */ @@ -68,6 +68,7 @@ public class SystemProperty { return this.value; } + /** * @param value The value to set. */ @@ -76,28 +77,27 @@ public class SystemProperty this.value = value; } - - public boolean isSet () + public boolean isSet() { return isSet; } - - /** Set a System.property with this value + + /** + * Set a System.property with this value * if it is not already set. */ void setIfNotSetAlready() { if (System.getProperty(getName()) == null) { - System.setProperty(getName(), (getValue()==null?"":getValue())); - isSet=true; + System.setProperty(getName(), (getValue() == null ? "" : getValue())); + isSet = true; } } - + void setAnyway() { - System.setProperty(getName(), (getValue()==null?"":getValue())); - isSet=true; + System.setProperty(getName(), (getValue() == null ? "" : getValue())); + isSet = true; } - } diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/WarPluginInfo.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/WarPluginInfo.java index 83ce7867c82..24026f87692 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/WarPluginInfo.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/WarPluginInfo.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,7 +16,6 @@ // ======================================================================== // - package org.eclipse.jetty.maven.plugin; import java.util.ArrayList; @@ -41,18 +40,15 @@ public class WarPluginInfo private List _dependentMavenWarIncludes; private List _dependentMavenWarExcludes; private List _overlayConfigs; - - - public WarPluginInfo (MavenProject project) + + public WarPluginInfo(MavenProject project) { _project = project; } - - - /** * Find the maven-war-plugin, if one is configured + * * @return the plugin */ public Plugin getPlugin() @@ -63,9 +59,8 @@ public class WarPluginInfo if (plugins == null) return null; - Iterator itor = plugins.iterator(); - while (itor.hasNext() && _plugin==null) + while (itor.hasNext() && _plugin == null) { Plugin plugin = (Plugin)itor.next(); if ("maven-war-plugin".equals(plugin.getArtifactId())) @@ -75,11 +70,9 @@ public class WarPluginInfo return _plugin; } - - - /** * Get value of dependentWarIncludes for maven-war-plugin + * * @return the list of dependent war includes */ public List getDependentMavenWarIncludes() @@ -99,16 +92,14 @@ public class WarPluginInfo if (node == null) return null; String val = node.getValue(); - _dependentMavenWarIncludes = StringUtil.csvSplit(null,val,0,val.length()); + _dependentMavenWarIncludes = StringUtil.csvSplit(null, val, 0, val.length()); } return _dependentMavenWarIncludes; } - - - /** * Get value of dependentWarExcludes for maven-war-plugin + * * @return the list of dependent war excludes */ public List getDependentMavenWarExcludes() @@ -128,20 +119,17 @@ public class WarPluginInfo if (node == null) return null; String val = node.getValue(); - _dependentMavenWarExcludes = StringUtil.csvSplit(null,val,0,val.length()); + _dependentMavenWarExcludes = StringUtil.csvSplit(null, val, 0, val.length()); } return _dependentMavenWarExcludes; } - - - /** * Get config for any overlays that have been declared for the maven-war-plugin. - * + * * @return the list of overlay configs */ - public List getMavenWarOverlayConfigs () + public List getMavenWarOverlayConfigs() { if (_overlayConfigs == null) { @@ -166,7 +154,7 @@ public class WarPluginInfo return Collections.emptyList(); _overlayConfigs = new ArrayList(); - for (int i=0;i deps = webApp.getWebInfLib(); StringBuilder strbuff = new StringBuilder(); if (deps != null) { - for (int i=0; i jettyProperties) - throws Exception + public static void fromProperties(JettyWebAppContext webApp, String resource, Server server, Map jettyProperties) + throws Exception { if (resource == null) throw new IllegalStateException("No resource"); - + fromProperties(webApp, Resource.newResource(resource).getFile(), server, jettyProperties); } - - + /** * Configure a webapp from a properties file + * * @param webApp the webapp to configure * @param propsFile the properties to apply * @param server the Server instance to use if there is a context xml file to apply * @param jettyProperties jetty properties to use if there is a context xml file to apply * @throws Exception if any I/O exception occurs */ - public static void fromProperties (JettyWebAppContext webApp, File propsFile, Server server, Map jettyProperties) - throws Exception + public static void fromProperties(JettyWebAppContext webApp, File propsFile, Server server, Map jettyProperties) + throws Exception { if (webApp == null) throw new IllegalArgumentException("No webapp"); if (propsFile == null) throw new IllegalArgumentException("No properties file"); - + if (!propsFile.exists()) - throw new IllegalArgumentException (propsFile.getCanonicalPath()+" does not exist"); - + throw new IllegalArgumentException(propsFile.getCanonicalPath() + " does not exist"); + Properties props = new Properties(); try (InputStream in = Files.newInputStream(propsFile.toPath())) { props.load(in); } - String str = props.getProperty("context.path"); if (!StringUtil.isBlank(str)) webApp.setContextPath(str); - // - web.xml str = props.getProperty("web.xml"); if (!StringUtil.isBlank(str)) - webApp.setDescriptor(str); + webApp.setDescriptor(str); //TODO the WebAppStarter class doesn't set up the QUICKSTART_CONFIGURATION_CLASSES, but the Starter class does!!! str = props.getProperty("quickstart.web.xml"); @@ -204,13 +193,13 @@ public class WebAppPropertyConverter // - the tmp directory str = props.getProperty("tmp.dir"); - if (!StringUtil.isBlank(str)) + if (!StringUtil.isBlank(str)) webApp.setTempDirectory(new File(str.trim())); str = props.getProperty("tmp.dir.persist"); if (!StringUtil.isBlank(str)) webApp.setPersistTempDirectory(Boolean.valueOf(str)); - + //Get the calculated base dirs which includes the overlays str = props.getProperty("base.dirs"); if (!StringUtil.isBlank(str)) @@ -218,7 +207,7 @@ public class WebAppPropertyConverter ResourceCollection bases = new ResourceCollection(StringUtil.csvSplit(str)); webApp.setWar(null); webApp.setBaseResource(bases); - } + } // - the equivalent of web-inf classes str = props.getProperty("classes.dir"); @@ -226,7 +215,7 @@ public class WebAppPropertyConverter { webApp.setClasses(new File(str)); } - + str = props.getProperty("testClasses.dir"); if (!StringUtil.isBlank(str)) { @@ -239,12 +228,13 @@ public class WebAppPropertyConverter { List jars = new ArrayList(); String[] names = StringUtil.csvSplit(str); - for (int j=0; names != null && j < names.length; j++) + for (int j = 0; names != null && j < names.length; j++) + { jars.add(new File(names[j].trim())); + } webApp.setWebInfLib(jars); } - - + //set up the webapp from the context xml file provided //NOTE: just like jetty:run mojo this means that the context file can //potentially override settings made in the pom. Ideally, we'd like @@ -255,11 +245,11 @@ public class WebAppPropertyConverter if (!StringUtil.isBlank(str)) { XmlConfiguration xmlConfiguration = new XmlConfiguration(Resource.newResource(str).getURI().toURL()); - xmlConfiguration.getIdMap().put("Server",server); + xmlConfiguration.getIdMap().put("Server", server); //add in any properties if (jettyProperties != null) { - for (Map.Entry prop:jettyProperties.entrySet()) + for (Map.Entry prop : jettyProperties.entrySet()) { xmlConfiguration.getProperties().put(prop.getKey(), prop.getValue()); } @@ -268,23 +258,22 @@ public class WebAppPropertyConverter } } - /** * Convert an array of Resources to csv file names - * + * * @param resources the resources to convert - * * @return csv string of resource filenames */ - private static String toCSV (Resource[] resources) + private static String toCSV(Resource[] resources) { StringBuilder rb = new StringBuilder(); - for (Resource r:resources) + for (Resource r : resources) { - if (rb.length() > 0) rb.append(","); + if (rb.length() > 0) + rb.append(","); rb.append(r.toString()); - } + } return rb.toString(); } diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/package-info.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/package-info.java index 33dff65294b..8bd40d96c9c 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/package-info.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/utils/MavenProjectHelper.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/utils/MavenProjectHelper.java new file mode 100644 index 00000000000..b705500278d --- /dev/null +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/utils/MavenProjectHelper.java @@ -0,0 +1,99 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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.maven.plugin.utils; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.project.MavenProject; + +public class MavenProjectHelper +{ + + private final Map artifactToLocalProjectMap; + + public MavenProjectHelper(MavenProject project) + { + Set mavenProjects = resolveProjectDependencies(project, new HashSet<>()); + artifactToLocalProjectMap = mavenProjects.stream() + .collect(Collectors.toMap(MavenProject::getId, Function.identity())); + artifactToLocalProjectMap.put(project.getArtifact().getId(), project); + } + + /** + * Gets maven project if referenced in reactor + * + * @param artifact - maven artifact + * @return {@link MavenProject} if artifact is referenced in reactor, otherwise null + */ + public MavenProject getMavenProject(Artifact artifact) + { + return artifactToLocalProjectMap.get(artifact.getId()); + } + + /** + * Gets path to artifact. + * If artifact is referenced in reactor, returns path to ${project.build.outputDirectory}. + * Otherwise, returns path to location in local m2 repo. + * + * Cannot return null - maven will complain about unsatisfied dependency during project built. + * + * @param artifact maven artifact + * @return path to artifact + */ + public Path getArtifactPath(Artifact artifact) + { + Path path = artifact.getFile().toPath(); + MavenProject mavenProject = getMavenProject(artifact); + if (mavenProject != null) + { + if ("test-jar".equals(artifact.getType())) + { + path = Paths.get(mavenProject.getBuild().getTestOutputDirectory()); + } + else + { + path = Paths.get(mavenProject.getBuild().getOutputDirectory()); + } + } + return path; + } + + private static Set resolveProjectDependencies(MavenProject project, Set visitedProjects) + { + if (visitedProjects.contains(project)) + { + return Collections.emptySet(); + } + visitedProjects.add(project); + Set availableProjects = new HashSet<>(project.getProjectReferences().values()); + for (MavenProject ref : project.getProjectReferences().values()) + { + availableProjects.addAll(resolveProjectDependencies(ref, visitedProjects)); + } + return availableProjects; + } +} diff --git a/jetty-maven-plugin/src/main/resources/jetty-maven.xml b/jetty-maven-plugin/src/main/resources/jetty-maven.xml index 5c107d8dd59..e37da0974b9 100644 --- a/jetty-maven-plugin/src/main/resources/jetty-maven.xml +++ b/jetty-maven-plugin/src/main/resources/jetty-maven.xml @@ -1,5 +1,4 @@ - - + diff --git a/jetty-maven-plugin/src/main/resources/maven.xml b/jetty-maven-plugin/src/main/resources/maven.xml index f4f94346e7d..8a454960d9d 100644 --- a/jetty-maven-plugin/src/main/resources/maven.xml +++ b/jetty-maven-plugin/src/main/resources/maven.xml @@ -1,5 +1,4 @@ - - + diff --git a/jetty-maven-plugin/src/test/java/org/eclipse/jetty/maven/plugin/it/TestGetContent.java b/jetty-maven-plugin/src/test/java/org/eclipse/jetty/maven/plugin/it/TestGetContent.java index 5c74d08c79f..1e3f34f8f80 100644 --- a/jetty-maven-plugin/src/test/java/org/eclipse/jetty/maven/plugin/it/TestGetContent.java +++ b/jetty-maven-plugin/src/test/java/org/eclipse/jetty/maven/plugin/it/TestGetContent.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,10 +18,6 @@ package org.eclipse.jetty.maven.plugin.it; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.LineNumberReader; import java.io.Reader; import java.nio.file.Files; @@ -32,6 +28,10 @@ import org.apache.commons.lang3.StringUtils; import org.eclipse.jetty.client.HttpClient; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + /** * */ @@ -42,33 +42,48 @@ public class TestGetContent throws Exception { int port = getPort(); - assertTrue( port > 0 ); + assertTrue(port > 0); HttpClient httpClient = new HttpClient(); try { httpClient.start(); - if (Boolean.getBoolean( "helloServlet" )) + if (Boolean.getBoolean("helloServlet")) { - String response = httpClient.GET( "http://localhost:" + port + "/hello?name=beer" ).getContentAsString(); - assertEquals( "Hello beer", response.trim() ); - response = httpClient.GET( "http://localhost:" + port + "/hello?name=foo" ).getContentAsString(); - assertEquals( "Hello foo", response.trim() ); - System.out.println( "helloServlet" ); + String response = httpClient.GET("http://localhost:" + port + "/hello?name=beer").getContentAsString(); + assertEquals("Hello beer", response.trim(), "it test " + System.getProperty("maven.it.name")); + response = httpClient.GET("http://localhost:" + port + "/hello?name=foo").getContentAsString(); + assertEquals("Hello foo", response.trim(), "it test " + System.getProperty("maven.it.name")); + System.out.println("helloServlet"); } - if (Boolean.getBoolean( "pingServlet" )) + if (Boolean.getBoolean("pingServlet")) { - System.out.println( "pingServlet ok" ); - String response = httpClient.GET( "http://localhost:" + port + "/ping?name=beer" ).getContentAsString(); - assertEquals( "pong beer", response.trim() ); - System.out.println( "pingServlet" ); + System.out.println("pingServlet"); + String response = httpClient.GET("http://localhost:" + port + "/ping?name=beer").getContentAsString(); + assertEquals("pong beer", response.trim(), "it test " + System.getProperty("maven.it.name")); + System.out.println("pingServlet ok"); } - String contentCheck = System.getProperty( "contentCheck" ); - if(StringUtils.isNotBlank( contentCheck ) ) + String contentCheck = System.getProperty("contentCheck"); + String pathToCheck = System.getProperty("pathToCheck"); + if (StringUtils.isNotBlank(contentCheck)) { - String response = httpClient.GET( "http://localhost:" + port ).getContentAsString(); - assertTrue(response.contains(contentCheck), "response not contentCheck: " + contentCheck + ", response:" + response); - System.out.println( "contentCheck" ); + String url = "http://localhost:" + port; + if (pathToCheck != null) + { + url += pathToCheck; + } + String response = httpClient.GET(url).getContentAsString(); + assertTrue(response.contains(contentCheck), "it test " + System.getProperty("maven.it.name") + + ", response not contentCheck: " + contentCheck + ", response:" + response); + System.out.println("contentCheck"); + } + if (Boolean.getBoolean("helloTestServlet")) + { + String response = httpClient.GET("http://localhost:" + port + "/testhello?name=beer").getContentAsString(); + assertEquals("Hello from test beer", response.trim(), "it test " + System.getProperty("maven.it.name")); + response = httpClient.GET("http://localhost:" + port + "/testhello?name=foo").getContentAsString(); + assertEquals("Hello from test foo", response.trim(), "it test " + System.getProperty("maven.it.name")); + System.out.println("helloServlet"); } } finally @@ -77,36 +92,36 @@ public class TestGetContent } } - public static int getPort() throws Exception { int attempts = 70; int port = -1; - String s = System.getProperty( "jetty.port.file" ); - assertNotNull( s ); - Path p = Paths.get( s ); - while ( true ) + String s = System.getProperty("jetty.port.file"); + assertNotNull(s); + Path p = Paths.get(s); + while (true) { - if ( Files.exists(p) ) + if (Files.exists(p)) { - try (Reader r = Files.newBufferedReader( p ); LineNumberReader lnr = new LineNumberReader( r );) + try (Reader r = Files.newBufferedReader(p); + LineNumberReader lnr = new LineNumberReader(r);) { s = lnr.readLine(); - assertNotNull( s ); - port = Integer.parseInt( s.trim() ); + assertNotNull(s); + port = Integer.parseInt(s.trim()); } break; } else { - if ( --attempts < 0 ) + if (--attempts < 0) { break; } else { - Thread.currentThread().sleep( 1000 ); + Thread.currentThread().sleep(1000); } } } diff --git a/jetty-memcached/jetty-memcached-sessions/pom.xml b/jetty-memcached/jetty-memcached-sessions/pom.xml index fe4b89009f4..d8b532e5e79 100644 --- a/jetty-memcached/jetty-memcached-sessions/pom.xml +++ b/jetty-memcached/jetty-memcached-sessions/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty.memcached memcached-parent - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 @@ -19,12 +19,12 @@ com.googlecode.xmemcached xmemcached - 2.0.0 + 2.4.5 org.slf4j slf4j-simple - 1.7.9 + ${slf4j.version} test @@ -46,42 +46,42 @@ - - ${project.groupId}.session - + + ${project.groupId}.session + - + org.apache.maven.plugins maven-surefire-plugin true - + - - memcached - - - memcached.enabled - true - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - false - - - - - + + memcached + + + memcached.enabled + true + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + false + + + + +
        diff --git a/jetty-memcached/jetty-memcached-sessions/src/main/config/etc/sessions/session-data-cache/xmemcached.xml b/jetty-memcached/jetty-memcached-sessions/src/main/config/etc/sessions/session-data-cache/xmemcached.xml index 60448c0ac06..3db1ba1be68 100644 --- a/jetty-memcached/jetty-memcached-sessions/src/main/config/etc/sessions/session-data-cache/xmemcached.xml +++ b/jetty-memcached/jetty-memcached-sessions/src/main/config/etc/sessions/session-data-cache/xmemcached.xml @@ -1,5 +1,4 @@ - - + diff --git a/jetty-memcached/jetty-memcached-sessions/src/main/config/modules/sessions/session-data-cache/xmemcached.mod b/jetty-memcached/jetty-memcached-sessions/src/main/config/modules/sessions/session-data-cache/xmemcached.mod index 0618c02950a..77a21ea759f 100644 --- a/jetty-memcached/jetty-memcached-sessions/src/main/config/modules/sessions/session-data-cache/xmemcached.mod +++ b/jetty-memcached/jetty-memcached-sessions/src/main/config/modules/sessions/session-data-cache/xmemcached.mod @@ -11,7 +11,7 @@ session-store slf4j-api [files] -maven://com.googlecode.xmemcached/xmemcached/2.0.0|lib/xmemcached/xmemcached-2.0.0.jar +maven://com.googlecode.xmemcached/xmemcached/2.4.5|lib/xmemcached/xmemcached-2.4.5.jar [lib] lib/jetty-memcached-sessions-${jetty.version}.jar diff --git a/jetty-memcached/jetty-memcached-sessions/src/main/java/org/eclipse/jetty/memcached/session/MemcachedSessionDataMap.java b/jetty-memcached/jetty-memcached-sessions/src/main/java/org/eclipse/jetty/memcached/session/MemcachedSessionDataMap.java index fbeff56d73d..2198a822934 100644 --- a/jetty-memcached/jetty-memcached-sessions/src/main/java/org/eclipse/jetty/memcached/session/MemcachedSessionDataMap.java +++ b/jetty-memcached/jetty-memcached-sessions/src/main/java/org/eclipse/jetty/memcached/session/MemcachedSessionDataMap.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,22 +18,22 @@ package org.eclipse.jetty.memcached.session; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.InetSocketAddress; import java.util.List; +import net.rubyeye.xmemcached.MemcachedClient; +import net.rubyeye.xmemcached.XMemcachedClientBuilder; +import net.rubyeye.xmemcached.transcoders.SerializingTranscoder; import org.eclipse.jetty.server.session.SessionContext; import org.eclipse.jetty.server.session.SessionData; import org.eclipse.jetty.server.session.SessionDataMap; +import org.eclipse.jetty.util.ClassLoadingObjectInputStream; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.component.AbstractLifeCycle; -import net.rubyeye.xmemcached.MemcachedClient; -import net.rubyeye.xmemcached.XMemcachedClientBuilder; - - - /** * MemcachedSessionDataMap * @@ -49,8 +49,39 @@ public class MemcachedSessionDataMap extends AbstractLifeCycle implements Sessio protected boolean _heartbeats = true; protected XMemcachedClientBuilder _builder; - - + /** + * SessionDataTranscoder + * + * We override memcached deserialization to use our classloader-aware + * ObjectInputStream. + */ + public static class SessionDataTranscoder extends SerializingTranscoder + { + + @Override + protected Object deserialize(byte[] in) + { + Object rv = null; + + if (in != null) + { + try (ByteArrayInputStream bis = new ByteArrayInputStream(in); + ClassLoadingObjectInputStream is = new ClassLoadingObjectInputStream(bis)) + { + rv = is.readObject(); + } + catch (IOException e) + { + log.error("Caught IOException decoding " + in.length + " bytes of data", e); + } + catch (ClassNotFoundException e) + { + log.error("Caught CNFE decoding " + in.length + " bytes of data", e); + } + } + return rv; + } + } /** * @param host address of memcache server @@ -59,22 +90,20 @@ public class MemcachedSessionDataMap extends AbstractLifeCycle implements Sessio public MemcachedSessionDataMap(String host, String port) { if (host == null || port == null) - throw new IllegalArgumentException("Host: "+host+" port: "+port); - _builder = new XMemcachedClientBuilder(host+":"+port); + throw new IllegalArgumentException("Host: " + host + " port: " + port); + _builder = new XMemcachedClientBuilder(host + ":" + port); } - - - public MemcachedSessionDataMap (List addresses) + + public MemcachedSessionDataMap(List addresses) { _builder = new XMemcachedClientBuilder(addresses); } - - - public MemcachedSessionDataMap (List addresses, int[] weights) + + public MemcachedSessionDataMap(List addresses, int[] weights) { _builder = new XMemcachedClientBuilder(addresses, weights); } - + /** * @return the builder */ @@ -83,48 +112,42 @@ public class MemcachedSessionDataMap extends AbstractLifeCycle implements Sessio return _builder; } - - - /** * @param sec the expiry to use in seconds */ - public void setExpirySec (int sec) + public void setExpirySec(int sec) { _expirySec = sec; } - + /** * Expiry time for memached entries. + * * @return memcached expiry time in sec */ - @ManagedAttribute(value="memcached expiry time in sec", readonly=true) - public int getExpirySec () + @ManagedAttribute(value = "memcached expiry time in sec", readonly = true) + public int getExpirySec() { return _expirySec; } - @ManagedAttribute(value="enable memcached heartbeats", readonly=true) + @ManagedAttribute(value = "enable memcached heartbeats", readonly = true) public boolean isHeartbeats() { return _heartbeats; } - public void setHeartbeats(boolean heartbeats) { _heartbeats = heartbeats; } - - /** - * @see org.eclipse.jetty.server.session.SessionDataMap#initialize(org.eclipse.jetty.server.session.SessionContext) - */ @Override public void initialize(SessionContext context) { try { + _builder.setTranscoder(new SessionDataTranscoder()); _client = _builder.build(); _client.setEnableHeartBeat(isHeartbeats()); } @@ -134,9 +157,6 @@ public class MemcachedSessionDataMap extends AbstractLifeCycle implements Sessio } } - /** - * @see org.eclipse.jetty.server.session.SessionDataMap#load(java.lang.String) - */ @Override public SessionData load(String id) throws Exception { @@ -144,20 +164,12 @@ public class MemcachedSessionDataMap extends AbstractLifeCycle implements Sessio return data; } - - /** - * @see org.eclipse.jetty.server.session.SessionDataMap#store(java.lang.String, org.eclipse.jetty.server.session.SessionData) - */ @Override public void store(String id, SessionData data) throws Exception { _client.set(id, _expirySec, data); - } + } - - /** - * @see org.eclipse.jetty.server.session.SessionDataMap#delete(java.lang.String) - */ @Override public boolean delete(String id) throws Exception { @@ -165,8 +177,6 @@ public class MemcachedSessionDataMap extends AbstractLifeCycle implements Sessio return true; //delete returns false if the value didn't exist } - - @Override protected void doStop() throws Exception { @@ -177,6 +187,4 @@ public class MemcachedSessionDataMap extends AbstractLifeCycle implements Sessio _client = null; } } - - } diff --git a/jetty-memcached/jetty-memcached-sessions/src/main/java/org/eclipse/jetty/memcached/session/MemcachedSessionDataMapFactory.java b/jetty-memcached/jetty-memcached-sessions/src/main/java/org/eclipse/jetty/memcached/session/MemcachedSessionDataMapFactory.java index 82f83928c39..c1714bd7e87 100644 --- a/jetty-memcached/jetty-memcached-sessions/src/main/java/org/eclipse/jetty/memcached/session/MemcachedSessionDataMapFactory.java +++ b/jetty-memcached/jetty-memcached-sessions/src/main/java/org/eclipse/jetty/memcached/session/MemcachedSessionDataMapFactory.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -27,16 +27,14 @@ import org.eclipse.jetty.server.session.SessionDataMapFactory; /** * MemcachedSessionDataMapFactory - * - * */ public class MemcachedSessionDataMapFactory implements SessionDataMapFactory { protected int _expiry; protected boolean _heartbeats = true; - protected int[] _weights; + protected int[] _weights; protected List _addresses; - + /** * @param addresses host and port address of memcached servers */ @@ -47,11 +45,13 @@ public class MemcachedSessionDataMapFactory implements SessionDataMapFactory else { _addresses = new ArrayList<>(); - for (InetSocketAddress a:addresses) + for (InetSocketAddress a : addresses) + { _addresses.add(a); + } } } - + /** * @param weights the relative weight to give each server in the list of addresses */ @@ -60,13 +60,11 @@ public class MemcachedSessionDataMapFactory implements SessionDataMapFactory _weights = weights; } - public int getExpirySec() { return _expiry; } - /** * @param expiry time in secs that memcached item remains valid */ @@ -74,7 +72,7 @@ public class MemcachedSessionDataMapFactory implements SessionDataMapFactory { _expiry = expiry; } - + public boolean isHeartbeats() { return _heartbeats; @@ -85,7 +83,7 @@ public class MemcachedSessionDataMapFactory implements SessionDataMapFactory _heartbeats = heartbeats; } - /** + /** * @see org.eclipse.jetty.server.session.SessionDataMapFactory#getSessionDataMap() */ @Override @@ -96,6 +94,4 @@ public class MemcachedSessionDataMapFactory implements SessionDataMapFactory m.setHeartbeats(isHeartbeats()); return m; } - - } diff --git a/jetty-memcached/jetty-memcached-sessions/src/test/java/org/eclipse/jetty/memcached/session/TestMemcachedSessions.java b/jetty-memcached/jetty-memcached-sessions/src/test/java/org/eclipse/jetty/memcached/session/TestMemcachedSessions.java index 6f640e4bf2b..ffc3d8d68f8 100644 --- a/jetty-memcached/jetty-memcached-sessions/src/test/java/org/eclipse/jetty/memcached/session/TestMemcachedSessions.java +++ b/jetty-memcached/jetty-memcached-sessions/src/test/java/org/eclipse/jetty/memcached/session/TestMemcachedSessions.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,15 +18,8 @@ package org.eclipse.jetty.memcached.session; - - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.IOException; import java.io.PrintWriter; - import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -48,10 +41,12 @@ import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + /** * TestMemcachedSessions - * - * */ public class TestMemcachedSessions { @@ -74,7 +69,7 @@ public class TestMemcachedSessions else if ("get".equals(arg)) { s = req.getSession(false); - System.err.println("GET: s="+s); + System.err.println("GET: s=" + s); } else if ("del".equals(arg)) { @@ -83,7 +78,7 @@ public class TestMemcachedSessions s.invalidate(); s = null; } - + resp.setContentType("text/html"); PrintWriter w = resp.getWriter(); if (s == null) @@ -91,10 +86,8 @@ public class TestMemcachedSessions else w.write((String)s.getAttribute("val")); } - } - - + public static class NullSessionCache extends AbstractSessionCache { @@ -143,12 +136,11 @@ public class TestMemcachedSessions { return null; } - } - + @Test - public void testMemcached () throws Exception - { + public void testMemcached() throws Exception + { String contextPath = "/"; Server server = new Server(0); @@ -173,40 +165,38 @@ public class TestMemcachedSessions client.start(); try { - + int value = 42; ContentResponse response = client.GET("http://localhost:" + port + contextPath + "?action=set&value=" + value); - assertEquals(HttpServletResponse.SC_OK,response.getStatus()); + assertEquals(HttpServletResponse.SC_OK, response.getStatus()); String sessionCookie = response.getHeaders().get("Set-Cookie"); assertTrue(sessionCookie != null); // Mangle the cookie, replacing Path with $Path, etc. sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); String resp = response.getContentAsString(); - assertEquals(resp.trim(),String.valueOf(value)); + assertEquals(resp.trim(), String.valueOf(value)); // Be sure the session value is still there - Request request = client.newRequest("http://localhost:" + port + contextPath + "?action=get"); + Request request = client.newRequest("http://localhost:" + port + contextPath + "?action=get"); request.header("Cookie", sessionCookie); response = request.send(); - assertEquals(HttpServletResponse.SC_OK,response.getStatus()); - + assertEquals(HttpServletResponse.SC_OK, response.getStatus()); + resp = response.getContentAsString(); - assertEquals(String.valueOf(value),resp.trim()); - - + assertEquals(String.valueOf(value), resp.trim()); + //Delete the session - request = client.newRequest("http://localhost:" + port + contextPath + "?action=del"); + request = client.newRequest("http://localhost:" + port + contextPath + "?action=del"); request.header("Cookie", sessionCookie); response = request.send(); - assertEquals(HttpServletResponse.SC_OK,response.getStatus()); - - + assertEquals(HttpServletResponse.SC_OK, response.getStatus()); + //Check that the session is gone - request = client.newRequest("http://localhost:" + port + contextPath + "?action=get"); + request = client.newRequest("http://localhost:" + port + contextPath + "?action=get"); request.header("Cookie", sessionCookie); response = request.send(); - assertEquals(HttpServletResponse.SC_OK,response.getStatus()); + assertEquals(HttpServletResponse.SC_OK, response.getStatus()); resp = response.getContentAsString(); assertEquals("No session", resp.trim()); } @@ -219,7 +209,5 @@ public class TestMemcachedSessions { server.stop(); } - } - } diff --git a/jetty-memcached/pom.xml b/jetty-memcached/pom.xml index 203343bfd97..0359e6c0c71 100644 --- a/jetty-memcached/pom.xml +++ b/jetty-memcached/pom.xml @@ -3,7 +3,7 @@ jetty-project org.eclipse.jetty - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 @@ -12,7 +12,6 @@ pom Jetty :: Memcached - jetty-memcached-sessions diff --git a/jetty-nosql/pom.xml b/jetty-nosql/pom.xml index ed0000fcbde..b92f55c5288 100644 --- a/jetty-nosql/pom.xml +++ b/jetty-nosql/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 jetty-nosql @@ -13,8 +13,7 @@ install - - + diff --git a/jetty-nosql/src/main/config/etc/sessions/mongo/session-store-by-address.xml b/jetty-nosql/src/main/config/etc/sessions/mongo/session-store-by-address.xml index 06c1aa6e261..830a81d86ba 100644 --- a/jetty-nosql/src/main/config/etc/sessions/mongo/session-store-by-address.xml +++ b/jetty-nosql/src/main/config/etc/sessions/mongo/session-store-by-address.xml @@ -1,5 +1,4 @@ - - + diff --git a/jetty-nosql/src/main/config/etc/sessions/mongo/session-store-by-uri.xml b/jetty-nosql/src/main/config/etc/sessions/mongo/session-store-by-uri.xml index e20eb0284e1..3bb15612a56 100644 --- a/jetty-nosql/src/main/config/etc/sessions/mongo/session-store-by-uri.xml +++ b/jetty-nosql/src/main/config/etc/sessions/mongo/session-store-by-uri.xml @@ -1,5 +1,4 @@ - - + diff --git a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSessionDataStore.java b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSessionDataStore.java index cbe769900b2..9444a3afa60 100644 --- a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSessionDataStore.java +++ b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSessionDataStore.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,7 +16,6 @@ // ======================================================================== // - package org.eclipse.jetty.nosql; import java.util.HashSet; @@ -25,33 +24,29 @@ import java.util.Set; import org.eclipse.jetty.server.session.AbstractSessionDataStore; import org.eclipse.jetty.server.session.SessionData; - /** * NoSqlSessionDataStore - * - * */ public abstract class NoSqlSessionDataStore extends AbstractSessionDataStore { - + public class NoSqlSessionData extends SessionData { private Object _version; private Set _dirtyAttributes = new HashSet<>(); - public NoSqlSessionData(String id, String cpath, String vhost, long created, long accessed, long lastAccessed, long maxInactiveMs) { super(id, cpath, vhost, created, accessed, lastAccessed, maxInactiveMs); - setVersion (new Long(0)); + setVersion(new Long(0)); } - - public void setVersion (Object v) + + public void setVersion(Object v) { _version = v; } - - public Object getVersion () + + public Object getVersion() { return _version; } @@ -62,29 +57,23 @@ public abstract class NoSqlSessionDataStore extends AbstractSessionDataStore super.setDirty(name); _dirtyAttributes.add(name); } - - + public Set takeDirtyAttributes() { Set copy = new HashSet<>(_dirtyAttributes); _dirtyAttributes.clear(); return copy; - } - - public Set getAllAttributeNames () + + public Set getAllAttributeNames() { return new HashSet(_attributes.keySet()); } } - @Override public SessionData newSessionData(String id, long created, long accessed, long lastAccessed, long maxInactiveMs) { return new NoSqlSessionData(id, _context.getCanonicalContextPath(), _context.getVhost(), created, accessed, lastAccessed, maxInactiveMs); } - - - } diff --git a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStore.java b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStore.java index 106df261ec1..0cbfc8d7650 100644 --- a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStore.java +++ b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStore.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,22 +16,15 @@ // ======================================================================== // - package org.eclipse.jetty.nosql.mongodb; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectOutputStream; import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; -import java.util.concurrent.atomic.AtomicReference; - -import org.eclipse.jetty.nosql.NoSqlSessionDataStore; -import org.eclipse.jetty.server.session.SessionContext; -import org.eclipse.jetty.server.session.SessionData; -import org.eclipse.jetty.server.session.UnreadableSessionDataException; -import org.eclipse.jetty.util.annotation.ManagedAttribute; -import org.eclipse.jetty.util.annotation.ManagedObject; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; import com.mongodb.BasicDBList; import com.mongodb.BasicDBObject; @@ -42,261 +35,254 @@ import com.mongodb.DBObject; import com.mongodb.MongoException; import com.mongodb.WriteConcern; import com.mongodb.WriteResult; +import org.eclipse.jetty.nosql.NoSqlSessionDataStore; +import org.eclipse.jetty.server.session.SessionContext; +import org.eclipse.jetty.server.session.SessionData; +import org.eclipse.jetty.server.session.UnreadableSessionDataException; +import org.eclipse.jetty.util.ClassLoadingObjectInputStream; +import org.eclipse.jetty.util.StringUtil; +import org.eclipse.jetty.util.annotation.ManagedAttribute; +import org.eclipse.jetty.util.annotation.ManagedObject; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; /** * MongoSessionDataStore * - * The document model is an outer object that contains the elements: + * The document model is an outer object that contains the elements: *
          - *
        • "id" : session_id
        • - *
        • "created" : create_time
        • - *
        • "accessed": last_access_time
        • - *
        • "maxIdle" : max_idle_time setting as session was created
        • - *
        • "expiry" : time at which session should expire
        • - *
        • "valid" : session_valid
        • - *
        • "context" : a nested object containing 1 nested object per context for which the session id is in use + *
        • "id" : session_id
        • + *
        • "created" : create_time
        • + *
        • "accessed": last_access_time
        • + *
        • "maxIdle" : max_idle_time setting as session was created
        • + *
        • "expiry" : time at which session should expire
        • + *
        • "valid" : session_valid
        • + *
        • "context" : a nested object containing 1 nested object per context for which the session id is in use *
        * Each of the nested objects inside the "context" element contains: *
          - *
        • unique_context_name : nested object containing name:value pairs of the session attributes for that context
        • - *
        • unique_context_name: vhost:contextpath, where no vhosts="0_0_0_0", root context = "", contextpath "/" replaced by "_" + *
        • unique_context_name : nested object containing name:value pairs of the session attributes for that context
        • + *
        • unique_context_name: vhost:contextpath, where no vhosts="0_0_0_0", root context = "", contextpath "/" replaced by "_" *
        *

        - * One of the name:value attribute pairs will always be the special attribute "__metadata__". The value + * One of the name:value attribute pairs will always be the special attribute "__metadata__". The value * is an object representing a version counter which is incremented every time the attributes change. *

        *

        * For example: *

        - * { "_id"       : ObjectId("52845534a40b66410f228f23"), 
        - *    "accessed" :  NumberLong("1384818548903"), 
        + * { "_id"       : ObjectId("52845534a40b66410f228f23"),
        + *    "accessed" :  NumberLong("1384818548903"),
          *    "maxIdle"  : 1,
        - *    "context"  : { "0_0_0_0:_testA" : { "A"            : "A", 
        - *                                     "__metadata__" : { "version" : NumberLong(2) } 
        + *    "context"  : { "0_0_0_0:_testA" : { "A"            : "A",
        + *                                     "__metadata__" : { "version" : NumberLong(2) }
          *                                   },
        - *                   "0_0_0_0:_testB" : { "B"            : "B", 
        - *                                     "__metadata__" : { "version" : NumberLong(1) } 
        - *                                   } 
        - *                 }, 
        + *                   "0_0_0_0:_testB" : { "B"            : "B",
        + *                                     "__metadata__" : { "version" : NumberLong(1) }
        + *                                   }
        + *                 },
          *    "created"  : NumberLong("1384818548903"),
          *    "expiry"   : NumberLong("1384818549903"),
        - *    "id"       : "w01ijx2vnalgv1sqrpjwuirprp7", 
        - *    "valid"    : true 
        + *    "id"       : "w01ijx2vnalgv1sqrpjwuirprp7",
        + *    "valid"    : true
          * }
          * 
        *

        * In MongoDB, the nesting level is indicated by "." separators for the key name. Thus to - * interact with a session attribute, the key is composed of: - * "context".unique_context_name.attribute_name - * Eg "context"."0_0_0_0:_testA"."A" - * - * + * interact with session fields, the key is composed of: + * "context".unique_context_name.field_name + * Eg "context"."0_0_0_0:_testA"."lastSaved" */ @ManagedObject public class MongoSessionDataStore extends NoSqlSessionDataStore { - - private final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session"); - - + + private static final Logger LOG = Log.getLogger("org.eclipse.jetty.server.session"); + /** * Special attribute for a session that is context-specific */ - public final static String __METADATA = "__metadata__"; + public static final String METADATA = "__metadata__"; /** * Name of nested document field containing 1 sub document per context for which the session id is in use */ - public final static String __CONTEXT = "context"; - + public static final String CONTEXT = "context"; + /** * Special attribute per session per context, incremented each time attributes are modified */ - public final static String __VERSION = __METADATA + ".version"; - - - public final static String __LASTSAVED = __METADATA + ".lastSaved"; - - - public final static String __LASTNODE = __METADATA + ".lastNode"; - + public static final String VERSION = METADATA + ".version"; + + public static final String LASTSAVED = METADATA + ".lastSaved"; + + public static final String LASTNODE = METADATA + ".lastNode"; + /** * Last access time of session */ - public final static String __ACCESSED = "accessed"; - - - public final static String __LAST_ACCESSED = "lastAccessed"; - + public static final String ACCESSED = "accessed"; + + public static final String LAST_ACCESSED = "lastAccessed"; + + public static final String ATTRIBUTES = "attributes"; + /** * Time this session will expire, based on last access time and maxIdle */ - public final static String __EXPIRY = "expiry"; - + public static final String EXPIRY = "expiry"; + /** * The max idle time of a session (smallest value across all contexts which has a session with the same id) */ - public final static String __MAX_IDLE = "maxIdle"; - + public static final String MAX_IDLE = "maxIdle"; + /** * Time of session creation */ - public final static String __CREATED = "created"; - + public static final String CREATED = "created"; + /** * Whether or not session is valid */ - public final static String __VALID = "valid"; - + public static final String VALID = "valid"; + /** * Session id */ - public final static String __ID = "id"; - - - + public static final String ID = "id"; + /** * Utility value of 1 for a session version for this context */ - private DBObject _version_1; - + private DBObject _version1; + /** * Access to MongoDB */ private DBCollection _dbSessions; - - - public void setDBCollection (DBCollection collection) + + public void setDBCollection(DBCollection collection) { _dbSessions = collection; } - - @ManagedAttribute(value="DBCollection", readonly=true) - public DBCollection getDBCollection () + + @ManagedAttribute(value = "DBCollection", readonly = true) + public DBCollection getDBCollection() { return _dbSessions; } - - - - /** - * @see org.eclipse.jetty.server.session.SessionDataStore#load(String) - */ + @Override - public SessionData load(String id) throws Exception + public SessionData doLoad(String id) throws Exception { - final AtomicReference reference = new AtomicReference<>(); - final AtomicReference exception = new AtomicReference<>(); - Runnable r = new Runnable() + DBObject sessionDocument = _dbSessions.findOne(new BasicDBObject(ID, id)); + + try { - @Override - public void run () + if (LOG.isDebugEnabled()) + LOG.debug("id={} loaded={}", id, sessionDocument); + + if (sessionDocument == null) + return null; + + Boolean valid = (Boolean)sessionDocument.get(VALID); + + if (LOG.isDebugEnabled()) + LOG.debug("id={} valid={}", id, valid); + if (valid == null || !valid) + return null; + + Object version = MongoUtils.getNestedValue(sessionDocument, getContextSubfield(VERSION)); + Long lastSaved = (Long)MongoUtils.getNestedValue(sessionDocument, getContextSubfield(LASTSAVED)); + String lastNode = (String)MongoUtils.getNestedValue(sessionDocument, getContextSubfield(LASTNODE)); + byte[] attributes = (byte[])MongoUtils.getNestedValue(sessionDocument, getContextSubfield(ATTRIBUTES)); + + Long created = (Long)sessionDocument.get(CREATED); + Long accessed = (Long)sessionDocument.get(ACCESSED); + Long lastAccessed = (Long)sessionDocument.get(LAST_ACCESSED); + Long maxInactive = (Long)sessionDocument.get(MAX_IDLE); + Long expiry = (Long)sessionDocument.get(EXPIRY); + + NoSqlSessionData data = null; + + // get the session for the context + DBObject sessionSubDocumentForContext = (DBObject)MongoUtils.getNestedValue(sessionDocument, getContextField()); + + if (LOG.isDebugEnabled()) + LOG.debug("attrs {}", sessionSubDocumentForContext); + + if (sessionSubDocumentForContext != null) { - try + if (LOG.isDebugEnabled()) + LOG.debug("Session {} present for context {}", id, _context); + + //only load a session if it exists for this context + data = (NoSqlSessionData)newSessionData(id, created, accessed, (lastAccessed == null ? accessed : lastAccessed), maxInactive); + data.setVersion(version); + data.setExpiry(expiry); + data.setContextPath(_context.getCanonicalContextPath()); + data.setVhost(_context.getVhost()); + data.setLastSaved(lastSaved); + data.setLastNode(lastNode); + + if (attributes == null) { - DBObject sessionDocument = _dbSessions.findOne(new BasicDBObject(__ID, id)); - - if (LOG.isDebugEnabled()) - LOG.debug("id={} loaded={}", id, sessionDocument); - - if (sessionDocument == null) - return; - - Boolean valid = (Boolean)sessionDocument.get(__VALID); - - if (LOG.isDebugEnabled()) - LOG.debug("id={} valid={}", id, valid); - if (valid == null || !valid) - return; - - Object version = MongoUtils.getNestedValue(sessionDocument, getContextSubfield(__VERSION)); - Long lastSaved = (Long)MongoUtils.getNestedValue(sessionDocument, getContextSubfield(__LASTSAVED)); - String lastNode = (String)MongoUtils.getNestedValue(sessionDocument, getContextSubfield(__LASTNODE)); - - Long created = (Long)sessionDocument.get(__CREATED); - Long accessed = (Long)sessionDocument.get(__ACCESSED); - Long lastAccessed = (Long)sessionDocument.get(__LAST_ACCESSED); - Long maxInactive = (Long)sessionDocument.get(__MAX_IDLE); - Long expiry = (Long)sessionDocument.get(__EXPIRY); - - NoSqlSessionData data = null; - - // get the session for the context - DBObject sessionSubDocumentForContext = (DBObject)MongoUtils.getNestedValue(sessionDocument,getContextField()); - - if (LOG.isDebugEnabled()) LOG.debug("attrs {}", sessionSubDocumentForContext); - - if (sessionSubDocumentForContext != null) + //legacy attribute storage format: the attributes are all fields in the document + Map map = new HashMap<>(); + for (String name : sessionSubDocumentForContext.keySet()) { - if (LOG.isDebugEnabled()) - LOG.debug("Session {} present for context {}", id, _context); - - //only load a session if it exists for this context - data = (NoSqlSessionData)newSessionData(id, created, accessed, (lastAccessed == null? accessed:lastAccessed), maxInactive); - data.setVersion(version); - data.setExpiry(expiry); - data.setContextPath(_context.getCanonicalContextPath()); - data.setVhost(_context.getVhost()); - data.setLastSaved(lastSaved); - data.setLastNode(lastNode); - - HashMap attributes = new HashMap<>(); - for (String name : sessionSubDocumentForContext.keySet()) - { - //skip special metadata attribute which is not one of the actual session attributes - if ( __METADATA.equals(name) ) - continue; - String attr = MongoUtils.decodeName(name); - Object value = MongoUtils.decodeValue(sessionSubDocumentForContext.get(name)); - attributes.put(attr,value); - } - - data.putAllAttributes(attributes); + //skip special metadata attribute which is not one of the actual session attributes + if (METADATA.equals(name)) + continue; + String attr = MongoUtils.decodeName(name); + Object value = MongoUtils.decodeValue(sessionSubDocumentForContext.get(name)); + map.put(attr, value); } - else - { - if (LOG.isDebugEnabled()) - LOG.debug("Session {} not present for context {}", id, _context); - } - - reference.set(data); + data.putAllAttributes(map); } - catch (Exception e) + else { - exception.set(new UnreadableSessionDataException(id, _context, e)); + //attributes have special serialized format + try (ByteArrayInputStream bais = new ByteArrayInputStream(attributes); + ClassLoadingObjectInputStream ois = new ClassLoadingObjectInputStream(bais)) + { + SessionData.deserializeAttributes(data, ois); + } } } - }; - - _context.run(r); - - if (exception.get() != null) - throw exception.get(); - - return reference.get(); + else + { + if (LOG.isDebugEnabled()) + LOG.debug("Session {} not present for context {}", id, _context); + } + + return data; + } + catch (Exception e) + { + throw (new UnreadableSessionDataException(id, _context, e)); + } } - /** - * @see org.eclipse.jetty.server.session.SessionDataStore#delete(String) - */ @Override public boolean delete(String id) throws Exception { if (LOG.isDebugEnabled()) - LOG.debug("Remove:session {} for context ",id, _context); + LOG.debug("Remove:session {} for context ", id, _context); /* * Check if the session exists and if it does remove the context * associated with this session */ - BasicDBObject mongoKey = new BasicDBObject(__ID, id); - - //DBObject sessionDocument = _dbSessions.findOne(mongoKey,_version_1); - DBObject sessionDocument = _dbSessions.findOne(new BasicDBObject(__ID, id)); + BasicDBObject mongoKey = new BasicDBObject(ID, id); + + //DBObject sessionDocument = _dbSessions.findOne(mongoKey,_version1); + DBObject sessionDocument = _dbSessions.findOne(new BasicDBObject(ID, id)); if (sessionDocument != null) { - DBObject c = (DBObject)MongoUtils.getNestedValue(sessionDocument, __CONTEXT); + DBObject c = (DBObject)MongoUtils.getNestedValue(sessionDocument, CONTEXT); if (c == null) { //delete whole doc @@ -315,104 +301,93 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore if (contexts.size() == 1 && contexts.iterator().next().equals(getCanonicalContextId())) { //delete whole doc - _dbSessions.remove(new BasicDBObject(__ID, id), WriteConcern.SAFE); + _dbSessions.remove(new BasicDBObject(ID, id), WriteConcern.SAFE); return true; } - + //just remove entry for my context BasicDBObject remove = new BasicDBObject(); BasicDBObject unsets = new BasicDBObject(); - unsets.put(getContextField(),1); - remove.put("$unset",unsets); - _dbSessions.update(mongoKey,remove,false,false,WriteConcern.SAFE); + unsets.put(getContextField(), 1); + remove.put("$unset", unsets); + _dbSessions.update(mongoKey, remove, false, false, WriteConcern.SAFE); return true; } else { return false; } - } - - - /** - * @see org.eclipse.jetty.server.session.SessionDataStore#exists(java.lang.String) - */ @Override public boolean exists(String id) throws Exception { DBObject fields = new BasicDBObject(); - fields.put(__EXPIRY, 1); - fields.put(__VALID, 1); - fields.put(getContextSubfield(__VERSION), 1); - - DBObject sessionDocument = _dbSessions.findOne(new BasicDBObject(__ID, id), fields); - + fields.put(EXPIRY, 1); + fields.put(VALID, 1); + fields.put(getContextSubfield(VERSION), 1); + + DBObject sessionDocument = _dbSessions.findOne(new BasicDBObject(ID, id), fields); + if (sessionDocument == null) return false; //doesn't exist - Boolean valid = (Boolean)sessionDocument.get(__VALID); + Boolean valid = (Boolean)sessionDocument.get(VALID); if (!valid) return false; //invalid - nb should not happen - - Long expiry = (Long)sessionDocument.get(__EXPIRY); - + + Long expiry = (Long)sessionDocument.get(EXPIRY); + //expired? if (expiry.longValue() > 0 && expiry.longValue() < System.currentTimeMillis()) return false; //it's expired - + //does it exist for this context? - Object version = MongoUtils.getNestedValue(sessionDocument, getContextSubfield(__VERSION)); - if (version == null) - return false; - - return true; + Object version = MongoUtils.getNestedValue(sessionDocument, getContextSubfield(VERSION)); + return version != null; } - - /** - * @see org.eclipse.jetty.server.session.SessionDataStore#getExpired(Set) - */ @Override public Set doGetExpired(Set candidates) { long now = System.currentTimeMillis(); long upperBound = now; Set expiredSessions = new HashSet<>(); - + //firstly ask mongo to verify if these candidate ids have expired - all of //these candidates will be for our node - BasicDBObject query = new BasicDBObject(); - query.append(__ID,new BasicDBObject("$in", candidates)); - query.append(__EXPIRY, new BasicDBObject("$gt", 0).append("$lt", upperBound)); + BasicDBObject query = new BasicDBObject(); + query.append(ID, new BasicDBObject("$in", candidates)); + query.append(EXPIRY, new BasicDBObject("$gt", 0).append("$lt", upperBound)); DBCursor verifiedExpiredSessions = null; - try + try { - verifiedExpiredSessions = _dbSessions.find(query, new BasicDBObject(__ID, 1)); - for ( DBObject session : verifiedExpiredSessions ) + verifiedExpiredSessions = _dbSessions.find(query, new BasicDBObject(ID, 1)); + for (DBObject session : verifiedExpiredSessions) { - String id = (String)session.get(__ID); - if (LOG.isDebugEnabled()) LOG.debug("{} Mongo confirmed expired session {}", _context,id); + String id = (String)session.get(ID); + if (LOG.isDebugEnabled()) + LOG.debug("{} Mongo confirmed expired session {}", _context, id); expiredSessions.add(id); - } + } } finally { - if (verifiedExpiredSessions != null) verifiedExpiredSessions.close(); + if (verifiedExpiredSessions != null) + verifiedExpiredSessions.close(); } //now ask mongo to find sessions last managed by any nodes that expired a while ago //if this is our first expiry check, make sure that we only grab really old sessions if (_lastExpiryCheckTime <= 0) - upperBound = (now - (3*(1000L * _gracePeriodSec))); + upperBound = (now - (3 * (1000L * _gracePeriodSec))); else - upperBound = _lastExpiryCheckTime - (1000L * _gracePeriodSec); - + upperBound = _lastExpiryCheckTime - (1000L * _gracePeriodSec); + query = new BasicDBObject(); - BasicDBObject gt = new BasicDBObject(__EXPIRY, new BasicDBObject("$gt", 0)); - BasicDBObject lt = new BasicDBObject (__EXPIRY, new BasicDBObject("$lt", upperBound)); + BasicDBObject gt = new BasicDBObject(EXPIRY, new BasicDBObject("$gt", 0)); + BasicDBObject lt = new BasicDBObject(EXPIRY, new BasicDBObject("$lt", upperBound)); BasicDBList list = new BasicDBList(); list.add(gt); list.add(lt); @@ -421,14 +396,15 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore DBCursor oldExpiredSessions = null; try { - BasicDBObject bo = new BasicDBObject(__ID, 1); - bo.append(__EXPIRY, 1); - + BasicDBObject bo = new BasicDBObject(ID, 1); + bo.append(EXPIRY, 1); + oldExpiredSessions = _dbSessions.find(query, bo); for (DBObject session : oldExpiredSessions) { - String id = (String)session.get(__ID); - if (LOG.isDebugEnabled()) LOG.debug("{} Mongo found old expired session {}", _context, id+" exp="+session.get(__EXPIRY)); + String id = (String)session.get(ID); + if (LOG.isDebugEnabled()) + LOG.debug("{} Mongo found old expired session {}", _context, id + " exp=" + session.get(EXPIRY)); expiredSessions.add(id); } } @@ -438,10 +414,9 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore oldExpiredSessions.close(); } - - //check through sessions that were candidates, but not found as expired. + //check through sessions that were candidates, but not found as expired. //they may no longer be persisted, in which case they are treated as expired. - for (String c:candidates) + for (String c : candidates) { if (!expiredSessions.contains(c)) { @@ -459,10 +434,7 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore return expiredSessions; } - /** - * @see org.eclipse.jetty.server.session.SessionDataStore#initialize(org.eclipse.jetty.server.session.SessionContext) - */ - public void initialize (SessionContext context) throws Exception + public void initialize(SessionContext context) throws Exception { if (isStarted()) throw new IllegalStateException("Context set after SessionDataStore started"); @@ -470,168 +442,137 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore ensureIndexes(); } - /** - * @see org.eclipse.jetty.server.session.AbstractSessionDataStore#doStore(String, SessionData, long) - */ @Override public void doStore(String id, SessionData data, long lastSaveTime) throws Exception - { + { // Form query for upsert - BasicDBObject key = new BasicDBObject(__ID, id); + BasicDBObject key = new BasicDBObject(ID, id); // Form updates BasicDBObject update = new BasicDBObject(); boolean upsert = false; BasicDBObject sets = new BasicDBObject(); - BasicDBObject unsets = new BasicDBObject(); - + Object version = ((NoSqlSessionData)data).getVersion(); - + // New session if (lastSaveTime <= 0) { upsert = true; version = new Long(1); - sets.put(__CREATED,data.getCreated()); - sets.put(__VALID,true); - sets.put(getContextSubfield(__VERSION),version); - sets.put(getContextSubfield(__LASTSAVED), data.getLastSaved()); - sets.put(getContextSubfield(__LASTNODE), data.getLastNode()); - sets.put(__MAX_IDLE, data.getMaxInactiveMs()); - sets.put(__EXPIRY, data.getExpiry()); + sets.put(CREATED, data.getCreated()); + sets.put(VALID, true); + sets.put(getContextSubfield(VERSION), version); + sets.put(getContextSubfield(LASTSAVED), data.getLastSaved()); + sets.put(getContextSubfield(LASTNODE), data.getLastNode()); + sets.put(MAX_IDLE, data.getMaxInactiveMs()); + sets.put(EXPIRY, data.getExpiry()); ((NoSqlSessionData)data).setVersion(version); } else { - sets.put(getContextSubfield(__LASTSAVED), data.getLastSaved()); - sets.put(getContextSubfield(__LASTNODE), data.getLastNode()); + sets.put(getContextSubfield(LASTSAVED), data.getLastSaved()); + sets.put(getContextSubfield(LASTNODE), data.getLastNode()); version = new Long(((Number)version).longValue() + 1); ((NoSqlSessionData)data).setVersion(version); - update.put("$inc",_version_1); + update.put("$inc", _version1); //if max idle time and/or expiry is smaller for this context, then choose that for the whole session doc BasicDBObject fields = new BasicDBObject(); - fields.append(__MAX_IDLE, true); - fields.append(__EXPIRY, true); + fields.append(MAX_IDLE, true); + fields.append(EXPIRY, true); DBObject o = _dbSessions.findOne(new BasicDBObject("id", id), fields); if (o != null) { - Long tmpLong = (Long)o.get(__MAX_IDLE); - long currentMaxIdle = (tmpLong == null? 0:tmpLong.longValue()); - tmpLong = (Long)o.get(__EXPIRY); - long currentExpiry = (tmpLong == null? 0 : tmpLong.longValue()); + Long tmpLong = (Long)o.get(MAX_IDLE); + long currentMaxIdle = (tmpLong == null ? 0 : tmpLong.longValue()); + tmpLong = (Long)o.get(EXPIRY); + long currentExpiry = (tmpLong == null ? 0 : tmpLong.longValue()); if (currentMaxIdle != data.getMaxInactiveMs()) - sets.put(__MAX_IDLE, data.getMaxInactiveMs()); + sets.put(MAX_IDLE, data.getMaxInactiveMs()); if (currentExpiry != data.getExpiry()) - sets.put(__EXPIRY, data.getExpiry()); + sets.put(EXPIRY, data.getExpiry()); } else LOG.warn("Session {} not found, can't update", id); } - sets.put(__ACCESSED, data.getAccessed()); - sets.put(__LAST_ACCESSED, data.getLastAccessed()); + sets.put(ACCESSED, data.getAccessed()); + sets.put(LAST_ACCESSED, data.getLastAccessed()); - Set names = ((NoSqlSessionData)data).takeDirtyAttributes(); - - if (lastSaveTime <= 0) - { - names.addAll(((NoSqlSessionData)data).getAllAttributeNames()); // note dirty may include removed names - } - - - for (String name : names) + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos)) { - Object value = data.getAttribute(name); - if (value == null) - unsets.put(getContextField() + "." + MongoUtils.encodeName(name),1); - else - sets.put(getContextField() + "." + MongoUtils.encodeName(name), MongoUtils.encodeName(value)); + SessionData.serializeAttributes(data, oos); + sets.put(getContextSubfield(ATTRIBUTES), baos.toByteArray()); } // Do the upsert if (!sets.isEmpty()) - update.put("$set",sets); - if (!unsets.isEmpty()) - update.put("$unset",unsets); + update.put("$set", sets); - WriteResult res = _dbSessions.update(key,update,upsert,false,WriteConcern.SAFE); + WriteResult res = _dbSessions.update(key, update, upsert, false, WriteConcern.SAFE); if (LOG.isDebugEnabled()) - LOG.debug("Save:db.sessions.update( {}, {},{} )", key, update, res); + LOG.debug("Save:db.sessions.update( {}, {},{} )", key, update, res); } protected void ensureIndexes() throws MongoException { - _version_1 = new BasicDBObject(getContextSubfield(__VERSION),1); + _version1 = new BasicDBObject(getContextSubfield(VERSION), 1); DBObject idKey = BasicDBObjectBuilder.start().add("id", 1).get(); _dbSessions.createIndex(idKey, - BasicDBObjectBuilder.start() - .add("name", "id_1") - .add("ns", _dbSessions.getFullName()) - .add("sparse", false) - .add("unique", true) - .get()); + BasicDBObjectBuilder.start() + .add("name", "id_1") + .add("ns", _dbSessions.getFullName()) + .add("sparse", false) + .add("unique", true) + .get()); DBObject versionKey = BasicDBObjectBuilder.start().add("id", 1).add("version", 1).get(); _dbSessions.createIndex(versionKey, BasicDBObjectBuilder.start() - .add("name", "id_1_version_1") - .add("ns", _dbSessions.getFullName()) - .add("sparse", false) - .add("unique", true) - .get()); - LOG.debug( "done ensure Mongodb indexes existing" ); + .add("name", "id_1_version_1") + .add("ns", _dbSessions.getFullName()) + .add("sparse", false) + .add("unique", true) + .get()); + LOG.debug("done ensure Mongodb indexes existing"); //TODO perhaps index on expiry time? } - - - /*------------------------------------------------------------ */ - private String getContextField () + private String getContextField() { - return __CONTEXT + "." + getCanonicalContextId(); + return CONTEXT + "." + getCanonicalContextId(); } - - - private String getCanonicalContextId () + + private String getCanonicalContextId() { return canonicalizeVHost(_context.getVhost()) + ":" + _context.getCanonicalContextPath(); } - - private String canonicalizeVHost (String vhost) + + private String canonicalizeVHost(String vhost) { if (vhost == null) return ""; - - return vhost.replace('.', '_'); - } - - - private String getContextSubfield (String attr) - { - return getContextField () +"."+ attr; - } - - /** - * @see org.eclipse.jetty.server.session.SessionDataStore#isPassivating() - */ - @ManagedAttribute(value="does store serialize sessions", readonly=true) + return StringUtil.replace(vhost, '.', '_'); + } + + private String getContextSubfield(String attr) + { + return getContextField() + "." + attr; + } + + @ManagedAttribute(value = "does store serialize sessions", readonly = true) @Override public boolean isPassivating() { return true; } - - /** - * @see org.eclipse.jetty.server.session.AbstractSessionDataStore#toString() - */ @Override public String toString() { - return String.format("%s[collection=%s]", super.toString(),getDBCollection()); + return String.format("%s[collection=%s]", super.toString(), getDBCollection()); } - - } diff --git a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStoreFactory.java b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStoreFactory.java index e8ca93542f1..201d481281a 100644 --- a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStoreFactory.java +++ b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStoreFactory.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,25 +16,19 @@ // ======================================================================== // - package org.eclipse.jetty.nosql.mongodb; import java.net.UnknownHostException; +import com.mongodb.Mongo; +import com.mongodb.MongoURI; import org.eclipse.jetty.server.session.AbstractSessionDataStoreFactory; +import org.eclipse.jetty.server.session.SessionDataStore; import org.eclipse.jetty.server.session.SessionHandler; import org.eclipse.jetty.util.StringUtil; -import org.eclipse.jetty.server.session.SessionDataStore; - - -import com.mongodb.Mongo; -import com.mongodb.MongoException; -import com.mongodb.MongoURI; /** * MongoSessionDataStoreFactory - * - * */ public class MongoSessionDataStoreFactory extends AbstractSessionDataStoreFactory { @@ -101,7 +95,7 @@ public class MongoSessionDataStoreFactory extends AbstractSessionDataStoreFactor } /** - * @param connectionString the connection string to set. This has priority over dbHost and port + * @param connectionString the connection string to set. This has priority over dbHost and port */ public void setConnectionString(String connectionString) { @@ -124,9 +118,8 @@ public class MongoSessionDataStoreFactory extends AbstractSessionDataStoreFactor _collectionName = collectionName; } - /** - * @throws Exception {@link UnknownHostException} if any issue while resolving MongoDB Host + * @throws Exception {@link UnknownHostException} if any issue while resolving MongoDB Host * @see org.eclipse.jetty.server.session.SessionDataStoreFactory#getSessionDataStore(org.eclipse.jetty.server.session.SessionHandler) */ @Override @@ -148,7 +141,4 @@ public class MongoSessionDataStoreFactory extends AbstractSessionDataStoreFactor store.setDBCollection(mongo.getDB(getDbName()).getCollection(getCollectionName())); return store; } - - - } diff --git a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoUtils.java b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoUtils.java index cea0c039bb5..94de6c5785c 100644 --- a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoUtils.java +++ b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoUtils.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,7 +16,6 @@ // ======================================================================== // - package org.eclipse.jetty.nosql.mongodb; import java.io.ByteArrayInputStream; @@ -27,20 +26,19 @@ import java.util.Date; import java.util.HashMap; import java.util.Map; -import org.eclipse.jetty.util.ClassLoadingObjectInputStream; - import com.mongodb.BasicDBObject; import com.mongodb.DBObject; +import org.eclipse.jetty.util.ClassLoadingObjectInputStream; +import org.eclipse.jetty.util.URIUtil; /** * MongoUtils * * Some utility methods for manipulating mongo data. This class facilitates testing. - * */ public class MongoUtils { - + public static Object decodeValue(final Object valueToDecode) throws IOException, ClassNotFoundException { if (valueToDecode == null || valueToDecode instanceof Number || valueToDecode instanceof String || valueToDecode instanceof Boolean || valueToDecode instanceof Date) @@ -60,7 +58,7 @@ public class MongoUtils for (String name : ((DBObject)valueToDecode).keySet()) { String attr = decodeName(name); - map.put(attr,decodeValue(((DBObject)valueToDecode).get(name))); + map.put(attr, decodeValue(((DBObject)valueToDecode).get(name))); } return map; } @@ -69,23 +67,17 @@ public class MongoUtils throw new IllegalStateException(valueToDecode.getClass().toString()); } } - - - + public static String decodeName(String name) { - return name.replace("%2E",".").replace("%25","%"); + return URIUtil.decodeSpecific(name, ".%"); } - - public static String encodeName(String name) { - return name.replace("%","%25").replace(".","%2E"); + return URIUtil.encodeSpecific(name, ".%"); } - - public static Object encodeName(Object value) throws IOException { if (value instanceof Number || value instanceof String || value instanceof Boolean || value instanceof Date) @@ -102,13 +94,13 @@ public class MongoUtils o = null; break; } - o.append(encodeName(entry.getKey().toString()),encodeName(entry.getValue())); + o.append(encodeName(entry.getKey().toString()), encodeName(entry.getValue())); } if (o != null) return o; } - + ByteArrayOutputStream bout = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(bout); out.reset(); @@ -116,15 +108,12 @@ public class MongoUtils out.flush(); return bout.toByteArray(); } - - /** * Dig through a given dbObject for the nested value - * + * * @param dbObject the mongo object to search * @param nestedKey the field key to find - * * @return the value of the field key */ public static Object getNestedValue(DBObject dbObject, String nestedKey) @@ -137,7 +126,7 @@ public class MongoUtils { temp = (DBObject)temp.get(keyChain[i]); - if ( temp == null ) + if (temp == null) { return null; } @@ -145,6 +134,4 @@ public class MongoUtils return temp.get(keyChain[keyChain.length - 1]); } - - } diff --git a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/package-info.java b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/package-info.java index 214f244e559..69443e75abe 100644 --- a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/package-info.java +++ b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/package-info.java b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/package-info.java index ec914f57410..d92cfa5d36d 100644 --- a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/package-info.java +++ b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 diff --git a/jetty-osgi/jetty-osgi-alpn/pom.xml b/jetty-osgi/jetty-osgi-alpn/pom.xml index 1fe2b2000b5..f9e2dd3028b 100644 --- a/jetty-osgi/jetty-osgi-alpn/pom.xml +++ b/jetty-osgi/jetty-osgi-alpn/pom.xml @@ -2,14 +2,14 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 jetty-osgi-alpn Jetty :: OSGi ALPN Fragment jar - org.eclipse.jetty.osgi.alpn.fragment + ${project.groupId}.alpn.fragment @@ -33,13 +33,13 @@ org.apache.felix maven-bundle-plugin - - ${bundle-symbolic-name};singleton:=true - Jetty OSGi ALPN Fragment - !javax.*;!org.eclipse.jetty.* - org.eclipse.jetty.alpn;version="${alpn.majorVersion}.${alpn.minorVersion}.${alpn.incrementalVersion}" - system.bundle;extension:=framework - + + ${bundle-symbolic-name};singleton:=true + Jetty OSGi ALPN Fragment + !javax.*;!org.eclipse.jetty.* + org.eclipse.jetty.alpn;version="${alpn.majorVersion}.${alpn.minorVersion}.${alpn.incrementalVersion}" + system.bundle;extension:=framework + diff --git a/jetty-osgi/jetty-osgi-boot-jsp/build.properties b/jetty-osgi/jetty-osgi-boot-jsp/build.properties deleted file mode 100644 index 6d10c98886e..00000000000 --- a/jetty-osgi/jetty-osgi-boot-jsp/build.properties +++ /dev/null @@ -1,5 +0,0 @@ -source.. = src/main/java/ -output.. = target/classes/ -bin.includes = META-INF/,\ - . -src.includes = META-INF/ diff --git a/jetty-osgi/jetty-osgi-boot-jsp/pom.xml b/jetty-osgi/jetty-osgi-boot-jsp/pom.xml index eb424f2d69d..91c7aa55980 100644 --- a/jetty-osgi/jetty-osgi-boot-jsp/pom.xml +++ b/jetty-osgi/jetty-osgi-boot-jsp/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 jetty-osgi-boot-jsp @@ -47,82 +47,20 @@ - org.apache.felix - maven-bundle-plugin - true - - - Jetty-OSGi-Jasper Integration - - org.eclipse.jetty.osgi.boot - !org.eclipse.jetty.osgi.boot.* - org.eclipse.jdt.*;resolution:=optional, - org.eclipse.jdt.core.compiler.*;resolution:=optional, - com.sun.el;resolution:=optional, - com.sun.el.lang;resolution:=optional, - com.sun.el.parser;resolution:=optional, - com.sun.el.util;resolution:=optional, - javax.el;version="[3.0,3.1)", - javax.servlet;version="[3.1,3.2)", - javax.servlet.resources;version="[3.1,3.2)", - javax.servlet.jsp.resources;version="[2.3,4)", - javax.servlet.jsp;version="[2.3,2.4)", - javax.servlet.jsp.el;version="[2.3,2.4)", - javax.servlet.jsp.tagext;version="[2.3,2.4)", - javax.servlet.jsp.jstl.core;version="1.2";resolution:=optional, - javax.servlet.jsp.jstl.fmt;version="1.2";resolution:=optional, - javax.servlet.jsp.jstl.sql;version="1.2";resolution:=optional, - javax.servlet.jsp.jstl.tlv;version="1.2";resolution:=optional, - org.apache.el;version="[8.0.23,9)";resolution:=optional, - org.apache.el.lang;version="[8.0.23,9)";resolution:=optional, - org.apache.el.stream;version="[8.0.23,9)";resolution:=optional, - org.apache.el.util;version="[8.0.23,9)";resolution:=optional, - org.apache.el.parser;version="[8.0.23,9)";resolution:=optional, - org.apache.jasper;version="[8.0.23,9)";resolution:=optional, - org.apache.jasper.compiler;version="[8.0.23,9)";resolution:=optional, - org.apache.jasper.compiler.tagplugin;version="[8.0.23,9)";resolution:=optional, - org.apache.jasper.runtime;version="[8.0.23,9)";resolution:=optional, - org.apache.jasper.security;version="[8.0.23,9)";resolution:=optional, - org.apache.jasper.servlet;version="[8.0.23,9)";resolution:=optional, - org.apache.jasper.tagplugins.jstl;version="[8.0.23,9)";resolution:=optional, - org.apache.jasper.util;version="[8.0.23,9)";resolution:=optional, - org.apache.jasper.xmlparser;version="[8.0.23,9)";resolution:=optional, - org.apache.taglibs.standard;version="1.2";resolution:=optional, - org.apache.taglibs.standard.extra.spath;version="1.2";resolution:=optional, - org.apache.taglibs.standard.functions;version="1.2";resolution:=optional, - org.apache.taglibs.standard.lang.jstl;version="1.2";resolution:=optional, - org.apache.taglibs.standard.lang.jstl.parser;version="1.2";resolution:=optional, - org.apache.taglibs.standard.lang.jstl.test;version="1.2";resolution:=optional, - org.apache.taglibs.standard.lang.jstl.test.beans;version="1.2";resolution:=optional, - org.apache.taglibs.standard.lang.support;version="1.2";resolution:=optional, - org.apache.taglibs.standard.resources;version="1.2";resolution:=optional, - org.apache.taglibs.standard.tag.common.core;version="1.2";resolution:=optional, - org.apache.taglibs.standard.tag.common.fmt;version="1.2";resolution:=optional, - org.apache.taglibs.standard.tag.common.sql;version="1.2";resolution:=optional, - org.apache.taglibs.standard.tag.common.xml;version="1.2";resolution:=optional, - org.apache.taglibs.standard.tag.el.core;version="1.2";resolution:=optional, - org.apache.taglibs.standard.tag.el.fmt;version="1.2";resolution:=optional, - org.apache.taglibs.standard.tag.el.sql;version="1.2";resolution:=optional, - org.apache.taglibs.standard.tag.el.xml;version="1.2";resolution:=optional, - org.apache.taglibs.standard.tag.rt.core;version="1.2";resolution:=optional, - org.apache.taglibs.standard.tag.rt.fmt;version="1.2";resolution:=optional, - org.apache.taglibs.standard.tag.rt.sql;version="1.2";resolution:=optional, - org.apache.taglibs.standard.tag.rt.xml;version="1.2";resolution:=optional, - org.apache.taglibs.standard.tei;version="1.2";resolution:=optional, - org.apache.taglibs.standard.tlv;version="1.2";resolution:=optional, - org.apache.tomcat;version="[8.0.23,9)";resolution:=optional, - org.eclipse.jetty.jsp;version="[$(version;===;${parsedVersion.osgiVersion}),$(version;==+;${parsedVersion.osgiVersion}))";resolution:=optional, - org.osgi.*, - org.xml.*;resolution:=optional, - org.xml.sax.*;resolution:=optional, - javax.xml.*;resolution:=optional, - org.w3c.dom;resolution:=optional, - org.w3c.dom.ls;resolution:=optional, - javax.xml.parser;resolution:=optional - - org.eclipse.jetty.jsp.*;version="[$(version;===;${parsedVersion.osgiVersion}),$(version;==+;${parsedVersion.osgiVersion}))",org.apache.jasper.*;version="8.0.23",org.apache.el.*;version="8.0.23" - - + org.apache.felix + maven-bundle-plugin + true + + + Jetty-OSGi-Jasper Integration + + org.eclipse.jetty.osgi.boot + !org.eclipse.jetty.osgi.boot.* + org.eclipse.jdt.*;resolution:=optional, org.eclipse.jdt.core.compiler.*;resolution:=optional, com.sun.el;resolution:=optional, com.sun.el.lang;resolution:=optional, com.sun.el.parser;resolution:=optional, com.sun.el.util;resolution:=optional, javax.el;version="[3.0,3.1)", javax.servlet;version="[3.1,3.2)", javax.servlet.resources;version="[3.1,3.2)", javax.servlet.jsp.resources;version="[2.3,4)", javax.servlet.jsp;version="[2.3,2.4)", javax.servlet.jsp.el;version="[2.3,2.4)", javax.servlet.jsp.tagext;version="[2.3,2.4)", javax.servlet.jsp.jstl.core;version="1.2";resolution:=optional, javax.servlet.jsp.jstl.fmt;version="1.2";resolution:=optional, javax.servlet.jsp.jstl.sql;version="1.2";resolution:=optional, javax.servlet.jsp.jstl.tlv;version="1.2";resolution:=optional, org.apache.el;version="[8.0.23,9)";resolution:=optional, org.apache.el.lang;version="[8.0.23,9)";resolution:=optional, org.apache.el.stream;version="[8.0.23,9)";resolution:=optional, org.apache.el.util;version="[8.0.23,9)";resolution:=optional, org.apache.el.parser;version="[8.0.23,9)";resolution:=optional, org.apache.jasper;version="[8.0.23,9)";resolution:=optional, org.apache.jasper.compiler;version="[8.0.23,9)";resolution:=optional, org.apache.jasper.compiler.tagplugin;version="[8.0.23,9)";resolution:=optional, org.apache.jasper.runtime;version="[8.0.23,9)";resolution:=optional, org.apache.jasper.security;version="[8.0.23,9)";resolution:=optional, org.apache.jasper.servlet;version="[8.0.23,9)";resolution:=optional, org.apache.jasper.tagplugins.jstl;version="[8.0.23,9)";resolution:=optional, org.apache.jasper.util;version="[8.0.23,9)";resolution:=optional, org.apache.jasper.xmlparser;version="[8.0.23,9)";resolution:=optional, org.apache.taglibs.standard;version="1.2";resolution:=optional, org.apache.taglibs.standard.extra.spath;version="1.2";resolution:=optional, org.apache.taglibs.standard.functions;version="1.2";resolution:=optional, org.apache.taglibs.standard.lang.jstl;version="1.2";resolution:=optional, org.apache.taglibs.standard.lang.jstl.parser;version="1.2";resolution:=optional, org.apache.taglibs.standard.lang.jstl.test;version="1.2";resolution:=optional, org.apache.taglibs.standard.lang.jstl.test.beans;version="1.2";resolution:=optional, org.apache.taglibs.standard.lang.support;version="1.2";resolution:=optional, org.apache.taglibs.standard.resources;version="1.2";resolution:=optional, org.apache.taglibs.standard.tag.common.core;version="1.2";resolution:=optional, org.apache.taglibs.standard.tag.common.fmt;version="1.2";resolution:=optional, org.apache.taglibs.standard.tag.common.sql;version="1.2";resolution:=optional, org.apache.taglibs.standard.tag.common.xml;version="1.2";resolution:=optional, org.apache.taglibs.standard.tag.el.core;version="1.2";resolution:=optional, org.apache.taglibs.standard.tag.el.fmt;version="1.2";resolution:=optional, org.apache.taglibs.standard.tag.el.sql;version="1.2";resolution:=optional, org.apache.taglibs.standard.tag.el.xml;version="1.2";resolution:=optional, org.apache.taglibs.standard.tag.rt.core;version="1.2";resolution:=optional, org.apache.taglibs.standard.tag.rt.fmt;version="1.2";resolution:=optional, org.apache.taglibs.standard.tag.rt.sql;version="1.2";resolution:=optional, org.apache.taglibs.standard.tag.rt.xml;version="1.2";resolution:=optional, org.apache.taglibs.standard.tei;version="1.2";resolution:=optional, org.apache.taglibs.standard.tlv;version="1.2";resolution:=optional, org.apache.tomcat;version="[8.0.23,9)";resolution:=optional, org.eclipse.jetty.jsp;version="[$(version;===;${parsedVersion.osgiVersion}),$(version;==+;${parsedVersion.osgiVersion}))";resolution:=optional, org.osgi.*, org.xml.*;resolution:=optional, org.xml.sax.*;resolution:=optional, javax.xml.*;resolution:=optional, org.w3c.dom;resolution:=optional, org.w3c.dom.ls;resolution:=optional, javax.xml.parser;resolution:=optional + + org.eclipse.jetty.jsp.*;version="[$(version;===;${parsedVersion.osgiVersion}),$(version;==+;${parsedVersion.osgiVersion}))",org.apache.jasper.*;version="8.0.23",org.apache.el.*;version="8.0.23" + + org.codehaus.mojo diff --git a/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/ContainerTldBundleDiscoverer.java b/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/ContainerTldBundleDiscoverer.java index fd34521803a..82dc490406f 100644 --- a/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/ContainerTldBundleDiscoverer.java +++ b/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/ContainerTldBundleDiscoverer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -26,7 +26,6 @@ import java.util.List; import java.util.Set; import java.util.StringTokenizer; import java.util.regex.Pattern; - import javax.servlet.jsp.JspFactory; import org.eclipse.jetty.deploy.DeploymentManager; @@ -39,39 +38,35 @@ import org.eclipse.jetty.util.log.Logger; import org.osgi.framework.Bundle; import org.osgi.framework.FrameworkUtil; - - /** * ContainerTldBundleDiscoverer - * + * * Finds bundles that are considered as on the container classpath that * contain tlds. - * + * * The System property org.eclipse.jetty.osgi.tldbundles is a comma * separated list of exact symbolic names of bundles that have container classpath * tlds. - * + * * The DeploymentManager context attribute "org.eclipse.jetty.server.webapp.containerIncludeBundlePattern" - * can be used to define a pattern of symbolic names of bundles that contain container + * can be used to define a pattern of symbolic names of bundles that contain container * classpath tlds. - * + * * The matching bundles are converted to URLs that are put onto a special classloader that acts as the * parent classloader for contexts deployed by the jetty Server instance (see ServerInstanceWrapper). - * - * It also discovers the bundle that contains the jstl taglib and adds it into the + * + * It also discovers the bundle that contains the jstl taglib and adds it into the * "org.eclipse.jetty.server.webapp.containerIncludeBundlePattern" (if it is not already there) so * that the WebInfOSGiConfiguration class will add the jstl taglib bundle into the list of container * resources. - * + * * Eg: * -Dorg.eclipse.jetty.osgi.tldbundles=org.springframework.web.servlet,com.opensymphony.module.sitemesh - * */ public class ContainerTldBundleDiscoverer implements TldBundleDiscoverer { private static final Logger LOG = Log.getLogger(ContainerTldBundleDiscoverer.class); - private static String DEFAULT_JSP_FACTORY_IMPL_CLASS = "org.apache.jasper.runtime.JspFactoryImpl"; /** @@ -82,16 +77,16 @@ public class ContainerTldBundleDiscoverer implements TldBundleDiscoverer private static String DEFAULT_JSTL_BUNDLE_CLASS = "org.apache.taglibs.standard.tag.rt.core.WhenTag"; private Bundle jstlBundle = null; - + /** * Check the System property "org.eclipse.jetty.osgi.tldbundles" for names of * bundles that contain tlds and convert to URLs. - * + * * @return The location of the jars that contain tld files as URLs. */ @Override public URL[] getUrlsForBundlesWithTlds(DeploymentManager deploymentManager, BundleFileLocatorHelper locatorHelper) throws Exception - { + { if (!isJspAvailable()) { return new URL[0]; @@ -103,21 +98,23 @@ public class ContainerTldBundleDiscoverer implements TldBundleDiscoverer Bundle[] bundles = FrameworkUtil.getBundle(ContainerTldBundleDiscoverer.class).getBundleContext().getBundles(); HashSet urls = new HashSet(); String tmp = System.getProperty(OSGiWebInfConfiguration.SYS_PROP_TLD_BUNDLES); //comma separated exact names - List sysNames = new ArrayList(); + List sysNames = new ArrayList(); if (tmp != null) { StringTokenizer tokenizer = new StringTokenizer(tmp, ", \n\r\t", false); while (tokenizer.hasMoreTokens()) + { sysNames.add(tokenizer.nextToken()); + } } - tmp = (String) deploymentManager.getContextAttribute(OSGiWebInfConfiguration.CONTAINER_BUNDLE_PATTERN); //bundle name patterns - - Pattern pattern = (tmp==null? null : Pattern.compile(tmp)); - + tmp = (String)deploymentManager.getContextAttribute(OSGiWebInfConfiguration.CONTAINER_BUNDLE_PATTERN); //bundle name patterns + + Pattern pattern = (tmp == null ? null : Pattern.compile(tmp)); + //check that the jstl bundle is not already included in the pattern, and include it if it is not because //subsequent classes such as OSGiWebInfConfiguration use this pattern to determine which jars are //considered to be on the container classpath - if (jstlBundle != null) + if (jstlBundle != null) { if (pattern == null) { @@ -126,27 +123,26 @@ public class ContainerTldBundleDiscoverer implements TldBundleDiscoverer } else if (!(pattern.matcher(jstlBundle.getSymbolicName()).matches())) { - String s = tmp+"|"+jstlBundle.getSymbolicName(); + String s = tmp + "|" + jstlBundle.getSymbolicName(); pattern = Pattern.compile(s); deploymentManager.setContextAttribute(OSGiWebInfConfiguration.CONTAINER_BUNDLE_PATTERN, s); } } - for (Bundle bundle : bundles) { if (sysNames.contains(bundle.getSymbolicName())) - convertBundleLocationToURL(locatorHelper, bundle, urls); + convertBundleLocationToURL(locatorHelper, bundle, urls); else if (pattern != null && pattern.matcher(bundle.getSymbolicName()).matches()) convertBundleLocationToURL(locatorHelper, bundle, urls); } return urls.toArray(new URL[urls.size()]); - } /** * Check that jsp is on the classpath + * * @return true if jsp is available in the environment */ public boolean isJspAvailable() @@ -162,15 +158,13 @@ public class ContainerTldBundleDiscoverer implements TldBundleDiscoverer } return true; } - - + /** - * - * Some versions of JspFactory do Class.forName, which probably won't work in an + * Some versions of JspFactory do Class.forName, which probably won't work in an * OSGi environment. */ - public void fixJspFactory () - { + public void fixJspFactory() + { try { Class servletContextClass = javax.servlet.ServletContext.class; @@ -178,11 +172,11 @@ public class ContainerTldBundleDiscoverer implements TldBundleDiscoverer JspFactory fact = JspFactory.getDefaultFactory(); if (fact == null) { // bug #299733 - // JspFactory does a simple - // Class.getForName("org.apache.jasper.runtime.JspFactoryImpl") - // however its bundles does not import the jasper package - // so it fails. let's help things out: - fact = (JspFactory) JettyBootstrapActivator.class.getClassLoader() + // JspFactory does a simple + // Class.getForName("org.apache.jasper.runtime.JspFactoryImpl") + // however its bundles does not import the jasper package + // so it fails. let's help things out: + fact = (JspFactory)JettyBootstrapActivator.class.getClassLoader() .loadClass(DEFAULT_JSP_FACTORY_IMPL_CLASS).getDeclaredConstructor().newInstance(); JspFactory.setDefaultFactory(fact); } @@ -192,17 +186,17 @@ public class ContainerTldBundleDiscoverer implements TldBundleDiscoverer LOG.warn("Unable to set the JspFactory: jsp support incomplete.", e); } } - - + /** * Find the bundle that contains a jstl implementation class, which assumes that * the jstl taglibs will be inside the same bundle. + * * @return Bundle contains the jstl implementation class */ - public Bundle findJstlBundle () + public Bundle findJstlBundle() { Class jstlClass = null; - + try { jstlClass = JSTLBundleDiscoverer.class.getClassLoader().loadClass(DEFAULT_JSTL_BUNDLE_CLASS); @@ -211,27 +205,22 @@ public class ContainerTldBundleDiscoverer implements TldBundleDiscoverer { LOG.info("jstl not on classpath", e); } - + if (jstlClass != null) //get the bundle containing jstl return FrameworkUtil.getBundle(jstlClass); - + return null; } - + /** * Resolves a bundle that contains tld files as a URL. The URLs are * used by jasper to discover the tld files. - * + * * Support only 2 types of packaging for the bundle: - the bundle is a jar * (recommended for runtime.) - the bundle is a folder and contain jars in * the root and/or in the lib folder (nice for PDE development situations) * Unsupported: the bundle is a jar that embeds more jars. - * - * @param locatorHelper - * @param bundle - * @param urls - * @throws Exception */ private void convertBundleLocationToURL(BundleFileLocatorHelper locatorHelper, Bundle bundle, Set urls) throws Exception { diff --git a/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/JSTLBundleDiscoverer.java b/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/JSTLBundleDiscoverer.java index 94a6977a543..b702de34a53 100644 --- a/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/JSTLBundleDiscoverer.java +++ b/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/JSTLBundleDiscoverer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -23,7 +23,6 @@ import java.net.URL; import java.util.ArrayList; import java.util.HashSet; import java.util.Set; - import javax.servlet.jsp.JspFactory; import org.eclipse.jetty.deploy.DeploymentManager; @@ -36,9 +35,8 @@ import org.osgi.framework.Bundle; import org.osgi.framework.FrameworkUtil; /** - * * JSTLBundleDiscoverer - * + * * Fix various shortcomings with the way jasper parses the tld files. Plugs the * JSTL tlds assuming that they are packaged with the bundle that contains the * JSTL classes. @@ -50,7 +48,6 @@ import org.osgi.framework.FrameworkUtil; public class JSTLBundleDiscoverer implements TldBundleDiscoverer { private static final Logger LOG = Log.getLogger(JSTLBundleDiscoverer.class); - /** * Default name of a class that belongs to the jstl bundle. From that class @@ -59,15 +56,13 @@ public class JSTLBundleDiscoverer implements TldBundleDiscoverer */ private static String DEFAULT_JSTL_BUNDLE_CLASS = "org.apache.taglibs.standard.tag.el.core.WhenTag"; - - /** * Default jsp factory implementation. Idally jasper is osgified and we can * use services. In the mean time we statically set the jsp factory * implementation. bug #299733 */ private static String DEFAULT_JSP_FACTORY_IMPL_CLASS = "org.apache.jasper.runtime.JspFactoryImpl"; - + private static final Set __tldBundleCache = new HashSet(); public JSTLBundleDiscoverer() @@ -89,15 +84,14 @@ public class JSTLBundleDiscoverer implements TldBundleDiscoverer JspFactory fact = JspFactory.getDefaultFactory(); if (fact == null) { // bug #299733 - // JspFactory does a simple - // Class.getForName("org.apache.jasper.runtime.JspFactoryImpl") - // however its bundles does not import the jasper package - // so it fails. let's help things out: - fact = (JspFactory) JettyBootstrapActivator.class.getClassLoader() + // JspFactory does a simple + // Class.getForName("org.apache.jasper.runtime.JspFactoryImpl") + // however its bundles does not import the jasper package + // so it fails. let's help things out: + fact = (JspFactory)JettyBootstrapActivator.class.getClassLoader() .loadClass(DEFAULT_JSP_FACTORY_IMPL_CLASS).getDeclaredConstructor().newInstance(); JspFactory.setDefaultFactory(fact); } - } catch (Exception e) { @@ -111,15 +105,15 @@ public class JSTLBundleDiscoverer implements TldBundleDiscoverer * such tag-libraries. Please note that it will work if and only if the * bundle is a jar (!) Currently we just hardcode the bundle that contains * the jstl implemenation. - * + * * A workaround when the tld cannot be parsed with this method is to copy * and paste it inside the WEB-INF of the webapplication where it is used. - * + * * Support only 2 types of packaging for the bundle: - the bundle is a jar * (recommended for runtime.) - the bundle is a folder and contain jars in * the root and/or in the lib folder (nice for PDE development situations) * Unsupported: the bundle is a jar that embeds more jars. - * + * * @return array of URLs * @throws Exception In case of errors during resolving TLDs files */ @@ -142,13 +136,13 @@ public class JSTLBundleDiscoverer implements TldBundleDiscoverer { LOG.info("jstl not on classpath", e); } - + if (jstlClass != null) { //get the bundle containing jstl Bundle tldBundle = FrameworkUtil.getBundle(jstlClass); File tldBundleLocation = locatorHelper.getBundleInstallLocation(tldBundle); - + if (tldBundleLocation != null && tldBundleLocation.isDirectory()) { // try to find the jar files inside this folder @@ -169,23 +163,21 @@ public class JSTLBundleDiscoverer implements TldBundleDiscoverer } } } - } else if (tldBundleLocation != null) { urls.add(tldBundleLocation.toURI().toURL()); - + String pattern = (String)deployer.getContextAttribute("org.eclipse.jetty.server.webapp.containerIncludeBundlePattern"); - pattern = (pattern==null?"":pattern); + pattern = (pattern == null ? "" : pattern); if (!pattern.contains(tldBundle.getSymbolicName())) { - pattern += "|"+tldBundle.getSymbolicName(); + pattern += "|" + tldBundle.getSymbolicName(); deployer.setContextAttribute("org.eclipse.jetty.server.webapp.containerIncludeBundlePattern", pattern); } } } - + return urls.toArray(new URL[urls.size()]); } - } diff --git a/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jsp/FragmentActivator.java b/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jsp/FragmentActivator.java index 385b2c6a7cf..5649086f424 100644 --- a/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jsp/FragmentActivator.java +++ b/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jsp/FragmentActivator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,7 +18,6 @@ package org.eclipse.jetty.osgi.boot.jsp; - import org.eclipse.jetty.osgi.boot.internal.serverfactory.ServerInstanceWrapper; import org.eclipse.jetty.osgi.boot.jasper.ContainerTldBundleDiscoverer; import org.osgi.framework.BundleActivator; @@ -26,16 +25,16 @@ import org.osgi.framework.BundleContext; /** * FragmentActivator - * + * * Sets up support for jsp and jstl. All relevant jsp jars must also be installed * into the osgi environment. - *

        + *

        * Note that as this is part of a bundle fragment, this activator is NOT * called by the OSGi environment. Instead, the org.eclipse.jetty.osgi.boot.utils.internal.PackageAdminTracker * simulates fragment activation and causes this class's start() method to * be called. *

        - *

        + *

        * The package of this class MUST match the Bundle-SymbolicName of this fragment * in order for the PackageAdminTracker to find it. *

        @@ -43,7 +42,7 @@ import org.osgi.framework.BundleContext; public class FragmentActivator implements BundleActivator { /** - * + * */ @Override public void start(BundleContext context) throws Exception @@ -51,11 +50,11 @@ public class FragmentActivator implements BundleActivator //set up some classes that will look for bundles with tlds that must be converted //to urls and treated as if they are on the Jetty container's classpath so that //jasper can deal with them - ServerInstanceWrapper.addContainerTldBundleDiscoverer(new ContainerTldBundleDiscoverer()); + ServerInstanceWrapper.addContainerTldBundleDiscoverer(new ContainerTldBundleDiscoverer()); } /** - * + * */ @Override public void stop(BundleContext context) throws Exception diff --git a/jetty-osgi/jetty-osgi-boot-warurl/build.properties b/jetty-osgi/jetty-osgi-boot-warurl/build.properties deleted file mode 100644 index 6d10c98886e..00000000000 --- a/jetty-osgi/jetty-osgi-boot-warurl/build.properties +++ /dev/null @@ -1,5 +0,0 @@ -source.. = src/main/java/ -output.. = target/classes/ -bin.includes = META-INF/,\ - . -src.includes = META-INF/ diff --git a/jetty-osgi/jetty-osgi-boot-warurl/pom.xml b/jetty-osgi/jetty-osgi-boot-warurl/pom.xml index 3421edc642b..c62f5c54bf4 100644 --- a/jetty-osgi/jetty-osgi-boot-warurl/pom.xml +++ b/jetty-osgi/jetty-osgi-boot-warurl/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT ../pom.xml 4.0.0 @@ -27,15 +27,15 @@ - org.apache.felix - maven-bundle-plugin - true - - - RFC66 War URL - org.eclipse.jetty.osgi.boot.warurl.WarUrlActivator - - + org.apache.felix + maven-bundle-plugin + true + + + RFC66 War URL + org.eclipse.jetty.osgi.boot.warurl.WarUrlActivator + + org.codehaus.mojo diff --git a/jetty-osgi/jetty-osgi-boot-warurl/src/main/java/org/eclipse/jetty/osgi/boot/warurl/WarUrlActivator.java b/jetty-osgi/jetty-osgi-boot-warurl/src/main/java/org/eclipse/jetty/osgi/boot/warurl/WarUrlActivator.java index 27c7269b7bf..9383ca9f60a 100644 --- a/jetty-osgi/jetty-osgi-boot-warurl/src/main/java/org/eclipse/jetty/osgi/boot/warurl/WarUrlActivator.java +++ b/jetty-osgi/jetty-osgi-boot-warurl/src/main/java/org/eclipse/jetty/osgi/boot/warurl/WarUrlActivator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -33,12 +33,12 @@ import org.osgi.service.url.URLStreamHandlerService; */ public class WarUrlActivator implements BundleActivator { - + private ServiceRegistration _reg; /** * Register the url stream handler factory. - * + * * @param context the {@link BundleContext} to use */ @SuppressWarnings("unchecked") @@ -46,11 +46,11 @@ public class WarUrlActivator implements BundleActivator public void start(BundleContext context) throws Exception { Dictionary props = new Hashtable(); - props.put(URLConstants.URL_HANDLER_PROTOCOL,new String[] {"war"}); + props.put(URLConstants.URL_HANDLER_PROTOCOL, new String[]{"war"}); context.registerService(URLStreamHandlerService.class.getName(), - new WarUrlStreamHandler(), props); + new WarUrlStreamHandler(), props); } - + /** * Remove the url stream handler. (probably not required, * as osgi might shutdown every registered service @@ -71,5 +71,4 @@ public class WarUrlActivator implements BundleActivator e.printStackTrace(); } } - } diff --git a/jetty-osgi/jetty-osgi-boot-warurl/src/main/java/org/eclipse/jetty/osgi/boot/warurl/WarUrlStreamHandler.java b/jetty-osgi/jetty-osgi-boot-warurl/src/main/java/org/eclipse/jetty/osgi/boot/warurl/WarUrlStreamHandler.java index f04d04f4c6e..88a591499d0 100644 --- a/jetty-osgi/jetty-osgi-boot-warurl/src/main/java/org/eclipse/jetty/osgi/boot/warurl/WarUrlStreamHandler.java +++ b/jetty-osgi/jetty-osgi-boot-warurl/src/main/java/org/eclipse/jetty/osgi/boot/warurl/WarUrlStreamHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -63,18 +63,18 @@ public class WarUrlStreamHandler extends AbstractURLStreamHandlerService } // if (actual.toString().startsWith("file:/") && ! actual.to) - URLConnection ori = (URLConnection) actual.openConnection(); + URLConnection ori = actual.openConnection(); ori.setDefaultUseCaches(Resource.getDefaultUseCaches()); JarURLConnection jarOri = null; try { if (ori instanceof JarURLConnection) { - jarOri = (JarURLConnection) ori; + jarOri = (JarURLConnection)ori; } else { - jarOri = (JarURLConnection) new URL("jar:" + actual.toString() + "!/").openConnection(); + jarOri = (JarURLConnection)new URL("jar:" + actual.toString() + "!/").openConnection(); jarOri.setDefaultUseCaches(Resource.getDefaultUseCaches()); } Manifest mf = WarBundleManifestGenerator.createBundleManifest(jarOri.getManifest(), url, jarOri.getJarFile()); @@ -83,22 +83,21 @@ public class WarUrlStreamHandler extends AbstractURLStreamHandlerService jarOri.getJarFile().close(); jarOri = null; } - catch (Throwable t) + catch (Throwable ignored) { } return new WarURLConnection(actual, mf); } finally { - if (jarOri != null) try - { - jarOri.getJarFile().close(); - } - catch (Throwable t) - { - } + if (jarOri != null) + try + { + jarOri.getJarFile().close(); + } + catch (Throwable ignored) + { + } } - } - } diff --git a/jetty-osgi/jetty-osgi-boot-warurl/src/main/java/org/eclipse/jetty/osgi/boot/warurl/internal/WarBundleManifestGenerator.java b/jetty-osgi/jetty-osgi-boot-warurl/src/main/java/org/eclipse/jetty/osgi/boot/warurl/internal/WarBundleManifestGenerator.java index f533a8aa3a4..ae60728b1ff 100644 --- a/jetty-osgi/jetty-osgi-boot-warurl/src/main/java/org/eclipse/jetty/osgi/boot/warurl/internal/WarBundleManifestGenerator.java +++ b/jetty-osgi/jetty-osgi-boot-warurl/src/main/java/org/eclipse/jetty/osgi/boot/warurl/internal/WarBundleManifestGenerator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -35,27 +35,28 @@ import org.osgi.framework.Constants; public class WarBundleManifestGenerator { - /** missing version in the url and in the manifest - * use this one. */ + /** + * missing version in the url and in the manifest + * use this one. + */ private static final String MISSING_VERSION = "0.0.1.unknown"; private static final String MISSING_MANIFEST_VERSION = "2"; - + public static Manifest createBundleManifest(Manifest originalManifest, URL url, JarFile jarFile) { Manifest res = new Manifest(); res.getMainAttributes().putAll( - createBundleManifest(originalManifest.getMainAttributes(), - url.toString(), jarFile)); + createBundleManifest(originalManifest.getMainAttributes(), + url.toString(), jarFile)); return res; } - - + private static Attributes createBundleManifest(Attributes originalManifest, String url, JarFile jarFile) { HashMap res = new HashMap(); for (Entry entries : originalManifest.entrySet()) { - res.put(entries.getKey().toString(),String.valueOf(entries.getValue())); + res.put(entries.getKey().toString(), String.valueOf(entries.getValue())); } MultiMap params = parseQueryString(url); //follow RFC66 documentation: @@ -67,13 +68,13 @@ public class WarBundleManifestGenerator } else { - String versionInManifest = (String) res.get(Constants.BUNDLE_VERSION); + String versionInManifest = res.get(Constants.BUNDLE_VERSION); if (versionInManifest == null) { res.put(Constants.BUNDLE_VERSION, MISSING_VERSION); } } - + //#2 Bundle_ManifestVersion String manversion = params.getString(Constants.BUNDLE_MANIFESTVERSION); if (manversion != null) @@ -83,20 +84,20 @@ public class WarBundleManifestGenerator else { int manv = 2; - try { - String versionInManifest = (String) res.get(Constants.BUNDLE_MANIFESTVERSION); + try + { + String versionInManifest = res.get(Constants.BUNDLE_MANIFESTVERSION); if (versionInManifest != null) { manv = Integer.parseInt(versionInManifest.trim()); } } - catch (NumberFormatException nfe) + catch (NumberFormatException ignored) { - } - res.put(Constants.BUNDLE_MANIFESTVERSION, String.valueOf( manv < 2 ? 2 : manv )); + res.put(Constants.BUNDLE_MANIFESTVERSION, String.valueOf(manv < 2 ? 2 : manv)); } - + //#3 Bundle-SymbolicName String symbname = params.getString(Constants.BUNDLE_SYMBOLICNAME); if (symbname != null) @@ -105,7 +106,7 @@ public class WarBundleManifestGenerator } else { - symbname = (String) res.get(Constants.BUNDLE_SYMBOLICNAME); + symbname = res.get(Constants.BUNDLE_SYMBOLICNAME); if (symbname == null) { //derive the symbolic name from the url. @@ -119,12 +120,12 @@ public class WarBundleManifestGenerator beforeQueryString = url.length(); } } - symbname = url.substring(lastSlash+1, beforeQueryString); + symbname = url.substring(lastSlash + 1, beforeQueryString); //todo: something better probably. res.put(Constants.BUNDLE_SYMBOLICNAME, symbname); } } - + //#4 Bundle-Classpath String extraBundleClasspath = params.getString(Constants.BUNDLE_CLASSPATH); String alreadyBundleClasspath = res.get(Constants.BUNDLE_CLASSPATH); @@ -153,40 +154,40 @@ public class WarBundleManifestGenerator } alreadyBundleClasspath = bundleClasspath.toString(); } - + //if there is already a manifest and it specifies the Bundle-Classpath. //for now let's trust that one. //please note that the draft of the spec implies that we should be parsing the existing //header and merge it with the missing stuff so this does not follow the spec yet. - + res.put(Constants.BUNDLE_CLASSPATH, - alreadyBundleClasspath + (extraBundleClasspath == null ? "" : "," + extraBundleClasspath )); - + alreadyBundleClasspath + (extraBundleClasspath == null ? "" : "," + extraBundleClasspath)); + //#5 Import-Package String extraImportPackage = params.getString(Constants.IMPORT_PACKAGE); String alreadyImportPackage = res.get(Constants.IMPORT_PACKAGE); if (alreadyImportPackage == null) - {//The spec does not specify that the jsp imports are optional - //kind of nice to have them optional so we can run simple wars in - //simple environments. + { + //The spec does not specify that the jsp imports are optional + //kind of nice to have them optional so we can run simple wars in + //simple environments. alreadyImportPackage = "javax.servlet; version=\"2.5\"," + - "javax.servlet.http;version=\"2.5\"," + - "javax.el;version=\"1.0\"" + - "javax.jsp;version=\"2.1\";resolution:=optional," + - "javax.jsp.tagext;version=\"2.1\";resolution:=optional"; - + "javax.servlet.http;version=\"2.5\"," + + "javax.el;version=\"1.0\"" + + "javax.jsp;version=\"2.1\";resolution:=optional," + + "javax.jsp.tagext;version=\"2.1\";resolution:=optional"; } if (extraImportPackage != null) { //if there is already a manifest and it specifies the Bundle-Classpath. //for now let's trust that one. //please note that the draft of the spec implies that we should be parsing the existing //header and merge it with the missing stuff so this does not follow the spec yet. - + res.put(Constants.IMPORT_PACKAGE, - (alreadyImportPackage == null ? "" : alreadyImportPackage + ",") + + (alreadyImportPackage == null ? "" : alreadyImportPackage + ",") + extraImportPackage); } - + //#6 Export-Package String extraExportPackage = params.getString(Constants.EXPORT_PACKAGE); String alreadyExportPackage = res.get(Constants.EXPORT_PACKAGE); @@ -196,10 +197,10 @@ public class WarBundleManifestGenerator //please note that the draft of the spec implies that we should be parsing the existing //header and merge it with the missing stuff so this does not follow the spec yet. res.put(Constants.EXPORT_PACKAGE, - (alreadyExportPackage == null ? "" : alreadyExportPackage + ",") + + (alreadyExportPackage == null ? "" : alreadyExportPackage + ",") + extraImportPackage); } - + //#7 Web-ContextPath String webContextPath = params.getString("Web-ContextPath"); if (webContextPath != null) @@ -214,7 +215,7 @@ public class WarBundleManifestGenerator //we choose to use the symbolic name as the default context path. if (symbname.endsWith(".war")) { - webContextPath = "/" + symbname.substring(0, symbname.length()-".war".length()); + webContextPath = "/" + symbname.substring(0, symbname.length() - ".war".length()); } else { @@ -223,7 +224,7 @@ public class WarBundleManifestGenerator res.put("Web-ContextPath", webContextPath); } } - + //#8 Web-JSPExtractLocation String jspExtractLocation = params.getString("Web-JSPExtractLocation"); if (jspExtractLocation != null) @@ -235,14 +236,13 @@ public class WarBundleManifestGenerator //nothing to do. } Attributes newAttrs = new Attributes(); - for (Entry e : res.entrySet()) + for (Entry e : res.entrySet()) { - newAttrs.putValue(e.getKey(),e.getValue()); + newAttrs.putValue(e.getKey(), e.getValue()); } return newAttrs; } - - + /** * @return The key values pairs that are in the query string of this url. */ @@ -259,11 +259,11 @@ public class WarBundleManifestGenerator { poundIndex = url.length(); } - UrlEncoded.decodeUtf8To(url, questionMarkIndex+1, - poundIndex - questionMarkIndex - 1, res); + UrlEncoded.decodeUtf8To(url, questionMarkIndex + 1, + poundIndex - questionMarkIndex - 1, res); return res; } - + private static List getJarsInWebInfLib(JarFile jarFile) { List res = new ArrayList(); @@ -278,6 +278,4 @@ public class WarBundleManifestGenerator } return res; } - - } diff --git a/jetty-osgi/jetty-osgi-boot-warurl/src/main/java/org/eclipse/jetty/osgi/boot/warurl/internal/WarURLConnection.java b/jetty-osgi/jetty-osgi-boot-warurl/src/main/java/org/eclipse/jetty/osgi/boot/warurl/internal/WarURLConnection.java index c675bcab340..f9502a4251e 100644 --- a/jetty-osgi/jetty-osgi-boot-warurl/src/main/java/org/eclipse/jetty/osgi/boot/warurl/internal/WarURLConnection.java +++ b/jetty-osgi/jetty-osgi-boot-warurl/src/main/java/org/eclipse/jetty/osgi/boot/warurl/internal/WarURLConnection.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -50,13 +50,14 @@ public class WarURLConnection extends URLConnection /** * Use PipedOuputStream and PipedInputStream to do the transformation without making * a new temporary file ust to replace the manifest. + * * @param newmanifest The new manifest * @param rawIn The file input stream or equivalent. not the jar input stream. - * @throws IOException if an I/O error occurs. * @return InputStream of the replaced manifest file + * @throws IOException if an I/O error occurs. */ public static InputStream substitueManifest(final Manifest newmanifest, - final InputStream rawIn) throws IOException + final InputStream rawIn) throws IOException { final PipedOutputStream pOut = new PipedOutputStream(); PipedInputStream pIn = new PipedInputStream(pOut); @@ -81,18 +82,21 @@ public class WarURLConnection extends URLConnection dest.putNextEntry(next); if (next.getSize() > 0) { - IO.copy(jin,dest,next.getSize()); + IO.copy(jin, dest, next.getSize()); } next = jin.getNextJarEntry(); } } - catch (IOException ioe) { + catch (IOException ioe) + { ioe.printStackTrace(); } finally { - if (dest != null) IO.close(dest); - if (jin != null) IO.close(jin); + if (dest != null) + IO.close(dest); + if (jin != null) + IO.close(jin); IO.close(pOut); } } @@ -101,10 +105,10 @@ public class WarURLConnection extends URLConnection th.start(); return pIn; } - + private Manifest _mf; private URLConnection _conn; - + /** * @param url The file url (for example) * @param mf The manifest to use as a replacement to the jar file inside @@ -118,12 +122,12 @@ public class WarURLConnection extends URLConnection _conn.setDefaultUseCaches(Resource.getDefaultUseCaches()); _mf = mf; } + @Override public void connect() throws IOException { _conn.connect(); } - @Override public InputStream getInputStream() throws IOException @@ -134,7 +138,7 @@ public class WarURLConnection extends URLConnection @Override public void addRequestProperty(String key, String value) { - _conn.addRequestProperty(key,value); + _conn.addRequestProperty(key, value); } @Override @@ -228,15 +232,15 @@ public class WarURLConnection extends URLConnection } @Override - public long getHeaderFieldDate(String name, long Default) + public long getHeaderFieldDate(String name, long defaultVal) { - return _conn.getHeaderFieldDate(name,Default); + return _conn.getHeaderFieldDate(name, defaultVal); } @Override - public int getHeaderFieldInt(String name, int Default) + public int getHeaderFieldInt(String name, int defaultVal) { - return _conn.getHeaderFieldInt(name,Default); + return _conn.getHeaderFieldInt(name, defaultVal); } @Override @@ -350,7 +354,7 @@ public class WarURLConnection extends URLConnection @Override public void setRequestProperty(String key, String value) { - _conn.setRequestProperty(key,value); + _conn.setRequestProperty(key, value); } @Override @@ -358,7 +362,4 @@ public class WarURLConnection extends URLConnection { _conn.setUseCaches(usecaches); } - - - } diff --git a/jetty-osgi/jetty-osgi-boot/build.properties b/jetty-osgi/jetty-osgi-boot/build.properties deleted file mode 100644 index ba1366d0903..00000000000 --- a/jetty-osgi/jetty-osgi-boot/build.properties +++ /dev/null @@ -1,8 +0,0 @@ -source.. = src/main/java/ -output.. = target/classes/ -bin.includes = META-INF/,\ - .,\ - jettyhome/ -bin.excludes = jettyhome/logs/*.log,\ - jettyhome/lib/* -src.includes = jettyhome/ diff --git a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-deployer.xml b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-deployer.xml index 19b3a5db090..d00c7995453 100644 --- a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-deployer.xml +++ b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-deployer.xml @@ -1,5 +1,4 @@ - - + diff --git a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-http.xml b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-http.xml index 319ae6cbef7..412e644a2e2 100644 --- a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-http.xml +++ b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-http.xml @@ -1,15 +1,10 @@ - - + - - - - - + - + diff --git a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty.xml b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty.xml index f47a40a2bc4..fe4fc1d1ab3 100644 --- a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty.xml +++ b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty.xml @@ -40,7 +40,7 @@
        - + + + + + + + + + + + + + + + + + + + - true - 1000 - false - false - + + + + diff --git a/jetty-osgi/jetty-osgi-boot/pom.xml b/jetty-osgi/jetty-osgi-boot/pom.xml index 18457863a7c..c436089a844 100644 --- a/jetty-osgi/jetty-osgi-boot/pom.xml +++ b/jetty-osgi/jetty-osgi-boot/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 jetty-osgi-boot @@ -13,10 +13,10 @@ ${project.groupId}.boot - - org.eclipse.jetty - jetty-annotations - + + org.eclipse.jetty + jetty-annotations + org.eclipse.jetty jetty-webapp @@ -39,74 +39,52 @@ - - - - maven-antrun-plugin - - - process-resources - - - - - - - - - - - - run - - - - - - org.apache.felix - maven-bundle-plugin - true - - - org.eclipse.jetty.osgi.boot;singleton:=true - org.eclipse.jetty.osgi.boot.JettyBootstrapActivator - org.eclipse.jetty.*;version="[$(version;===;${parsedVersion.osgiVersion}),$(version;==+;${parsedVersion.osgiVersion}))" - javax.mail;version="1.4.0";resolution:=optional, - javax.mail.event;version="1.4.0";resolution:=optional, - javax.mail.internet;version="1.4.0";resolution:=optional, - javax.mail.search;version="1.4.0";resolution:=optional, - javax.mail.util;version="1.4.0";resolution:=optional, - javax.servlet;version="[3.1,3.2)", - javax.servlet.http;version="[3.1,3.2)", - javax.transaction;version="1.1.0";resolution:=optional, - javax.transaction.xa;version="1.1.0";resolution:=optional, - org.objectweb.asm;version=4;resolution:=optional, - org.osgi.framework, - org.osgi.service.cm;version="1.2.0", - org.osgi.service.packageadmin, - org.osgi.service.startlevel;version="1.0.0", - org.osgi.service.url;version="1.0.0", - org.osgi.util.tracker;version="1.3.0", - org.slf4j;resolution:=optional, - org.slf4j.spi;resolution:=optional, - org.slf4j.helpers;resolution:=optional, - org.xml.sax, - org.xml.sax.helpers, - org.eclipse.jetty.annotations;resolution:=optional, - * - - <_nouses>true - - - - - org.codehaus.mojo - findbugs-maven-plugin - - org.eclipse.jetty.osgi.boot.* - - - - + + + + maven-antrun-plugin + + + process-resources + + + + + + + + + + + + run + + + + + + org.apache.felix + maven-bundle-plugin + true + + + org.eclipse.jetty.osgi.boot;singleton:=true + org.eclipse.jetty.osgi.boot.JettyBootstrapActivator + org.eclipse.jetty.*;version="[$(version;===;${parsedVersion.osgiVersion}),$(version;==+;${parsedVersion.osgiVersion}))" + javax.mail;version="1.4.0";resolution:=optional, javax.mail.event;version="1.4.0";resolution:=optional, javax.mail.internet;version="1.4.0";resolution:=optional, javax.mail.search;version="1.4.0";resolution:=optional, javax.mail.util;version="1.4.0";resolution:=optional, javax.servlet;version="[3.1,3.2)", javax.servlet.http;version="[3.1,3.2)", javax.transaction;version="1.1.0";resolution:=optional, javax.transaction.xa;version="1.1.0";resolution:=optional, org.objectweb.asm;version="5";resolution:=optional, org.osgi.framework, org.osgi.service.cm;version="1.2.0", org.osgi.service.packageadmin, org.osgi.service.startlevel;version="1.0.0", org.osgi.service.url;version="1.0.0", org.osgi.util.tracker;version="1.3.0", org.slf4j;resolution:=optional, org.slf4j.spi;resolution:=optional, org.slf4j.helpers;resolution:=optional, org.xml.sax, org.xml.sax.helpers, org.eclipse.jetty.annotations;resolution:=optional, * + + <_nouses>true + + + + + org.codehaus.mojo + findbugs-maven-plugin + + org.eclipse.jetty.osgi.boot.* + + + +
        diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationConfiguration.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationConfiguration.java index a649a79d14b..13b44ef5461 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationConfiguration.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationConfiguration.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,10 +19,8 @@ package org.eclipse.jetty.osgi.annotations; import java.io.IOException; -import java.net.MalformedURLException; import java.util.HashSet; import java.util.Set; - import javax.servlet.ServletContainerInitializer; import org.eclipse.jetty.annotations.AnnotationParser.Handler; @@ -40,16 +38,16 @@ import org.osgi.framework.Constants; /** * Extend the AnnotationConfiguration to support OSGi: * Look for annotations inside WEB-INF/lib and also in the fragments and required bundles. - * Discover them using a scanner adapted to OSGi instead of the jarscanner. + * Discover them using a scanner adapted to OSGi instead of the jarscanner. */ public class AnnotationConfiguration extends org.eclipse.jetty.annotations.AnnotationConfiguration { private static final Logger LOG = Log.getLogger(org.eclipse.jetty.annotations.AnnotationConfiguration.class); - + public class BundleParserTask extends ParserTask { - - public BundleParserTask (AnnotationParser parser, Sethandlers, Resource resource) + + public BundleParserTask(AnnotationParser parser, Set handlers, Resource resource) { super(parser, handlers, resource); } @@ -63,19 +61,18 @@ public class AnnotationConfiguration extends org.eclipse.jetty.annotations.Annot Bundle bundle = osgiAnnotationParser.getBundle(_resource); if (_stat != null) _stat.start(); - osgiAnnotationParser.parse(_handlers, bundle); + osgiAnnotationParser.parse(_handlers, bundle); if (_stat != null) _stat.end(); } return null; } } - - + public AnnotationConfiguration() { } - + /** * This parser scans the bundles using the OSGi APIs instead of assuming a jar. */ @@ -84,14 +81,14 @@ public class AnnotationConfiguration extends org.eclipse.jetty.annotations.Annot { return new AnnotationParser(javaTargetVersion); } - + @Override - public Resource getJarFor(ServletContainerInitializer service) throws MalformedURLException, IOException + public Resource getJarFor(ServletContainerInitializer service) throws IOException { Resource resource = super.getJarFor(service); // TODO This is not correct, but implemented like this to be bug for bug compatible // with previous implementation that could only handle actual jars and not bundles. - if (resource!=null && !resource.toString().endsWith(".jar")) + if (resource != null && !resource.toString().endsWith(".jar")) return null; return resource; } @@ -107,15 +104,15 @@ public class AnnotationConfiguration extends org.eclipse.jetty.annotations.Annot * */ @Override - public void parseWebInfLib (WebAppContext context, org.eclipse.jetty.annotations.AnnotationParser parser) - throws Exception + public void parseWebInfLib(WebAppContext context, org.eclipse.jetty.annotations.AnnotationParser parser) + throws Exception { AnnotationParser oparser = (AnnotationParser)parser; if (_webInfLibStats == null) _webInfLibStats = new CounterStatistic(); - - Bundle webbundle = (Bundle) context.getAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE); + + Bundle webbundle = (Bundle)context.getAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE); @SuppressWarnings("unchecked") Set fragAndRequiredBundles = (Set)context.getAttribute(OSGiWebInfConfiguration.FRAGMENT_AND_REQUIRED_BUNDLES); if (fragAndRequiredBundles != null) @@ -126,28 +123,28 @@ public class AnnotationConfiguration extends org.eclipse.jetty.annotations.Annot //skip bundles that have been uninstalled since we discovered them if (bundle.getState() == Bundle.UNINSTALLED) continue; - + Resource bundleRes = oparser.indexBundle(bundle); if (!context.getMetaData().getWebInfJars().contains(bundleRes)) { context.getMetaData().addWebInfJar(bundleRes); } - + if (bundle.getHeaders().get(Constants.FRAGMENT_HOST) != null) { //a fragment indeed: - parseFragmentBundle(context,oparser,webbundle,bundle); + parseFragmentBundle(context, oparser, webbundle, bundle); _webInfLibStats.increment(); } } } //scan ourselves oparser.indexBundle(webbundle); - parseWebBundle(context,oparser,webbundle); + parseWebBundle(context, oparser, webbundle); _webInfLibStats.increment(); - + //scan the WEB-INF/lib - super.parseWebInfLib(context,parser); + super.parseWebInfLib(context, parser); if (fragAndRequiredBundles != null) { //scan the required bundles @@ -156,19 +153,20 @@ public class AnnotationConfiguration extends org.eclipse.jetty.annotations.Annot //skip bundles that have been uninstalled since we discovered them if (requiredBundle.getState() == Bundle.UNINSTALLED) continue; - + if (requiredBundle.getHeaders().get(Constants.FRAGMENT_HOST) == null) { //a bundle indeed: - parseRequiredBundle(context,oparser,webbundle,requiredBundle); + parseRequiredBundle(context, oparser, webbundle, requiredBundle); _webInfLibStats.increment(); } } } } - + /** * Scan a fragment bundle for servlet annotations + * * @param context The webapp context * @param parser The parser * @param webbundle The current webbundle @@ -176,35 +174,33 @@ public class AnnotationConfiguration extends org.eclipse.jetty.annotations.Annot * @throws Exception if unable to parse fragment bundle */ protected void parseFragmentBundle(WebAppContext context, AnnotationParser parser, - Bundle webbundle, Bundle fragmentBundle) throws Exception + Bundle webbundle, Bundle fragmentBundle) throws Exception { - parseBundle(context,parser,webbundle,fragmentBundle); + parseBundle(context, parser, webbundle, fragmentBundle); } - + /** * Scan a bundle required by the webbundle for servlet annotations + * * @param context The webapp context * @param parser The parser * @param webbundle The current webbundle * @throws Exception if unable to parse the web bundle */ protected void parseWebBundle(WebAppContext context, AnnotationParser parser, Bundle webbundle) - throws Exception + throws Exception { - parseBundle(context,parser,webbundle,webbundle); + parseBundle(context, parser, webbundle, webbundle); } - - - - - /** + + /** * @see org.eclipse.jetty.annotations.AnnotationConfiguration#parseWebInfClasses(org.eclipse.jetty.webapp.WebAppContext, org.eclipse.jetty.annotations.AnnotationParser) */ @Override public void parseWebInfClasses(WebAppContext context, org.eclipse.jetty.annotations.AnnotationParser parser) - throws Exception + throws Exception { - Bundle webbundle = (Bundle) context.getAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE); + Bundle webbundle = (Bundle)context.getAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE); String bundleClasspath = (String)webbundle.getHeaders().get(Constants.BUNDLE_CLASSPATH); //only scan WEB-INF/classes if we didn't already scan it with parseWebBundle if (StringUtil.isBlank(bundleClasspath) || !bundleClasspath.contains("WEB-INF/classes")) @@ -213,6 +209,7 @@ public class AnnotationConfiguration extends org.eclipse.jetty.annotations.Annot /** * Scan a bundle required by the webbundle for servlet annotations + * * @param context The webapp context * @param parser The parser * @param webbundle The current webbundle @@ -220,16 +217,16 @@ public class AnnotationConfiguration extends org.eclipse.jetty.annotations.Annot * @throws Exception if unable to parse the required bundle */ protected void parseRequiredBundle(WebAppContext context, AnnotationParser parser, - Bundle webbundle, Bundle requiredBundle) throws Exception + Bundle webbundle, Bundle requiredBundle) throws Exception { - parseBundle(context,parser,webbundle,requiredBundle); + parseBundle(context, parser, webbundle, requiredBundle); } - + protected void parseBundle(WebAppContext context, AnnotationParser parser, Bundle webbundle, Bundle bundle) throws Exception - { + { - Resource bundleRes = parser.getResource(bundle); + Resource bundleRes = parser.getResource(bundle); Set handlers = new HashSet<>(); handlers.addAll(_discoverableAnnotationHandlers); if (_classInheritanceHandler != null) @@ -244,5 +241,4 @@ public class AnnotationConfiguration extends org.eclipse.jetty.annotations.Annot task.setStatistic(new TimeStatistic()); } } - } diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationParser.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationParser.java index ef85bd9e23a..c457149301c 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationParser.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationParser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -30,31 +30,32 @@ import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelperFactory; +import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.resource.Resource; import org.objectweb.asm.Opcodes; import org.osgi.framework.Bundle; import org.osgi.framework.Constants; /** - * + * */ public class AnnotationParser extends org.eclipse.jetty.annotations.AnnotationParser { private Set _alreadyParsed = ConcurrentHashMap.newKeySet(); - - private ConcurrentHashMap _uriToBundle = new ConcurrentHashMap<>(); - private ConcurrentHashMap _bundleToResource = new ConcurrentHashMap<>(); + + private ConcurrentHashMap _uriToBundle = new ConcurrentHashMap<>(); + private ConcurrentHashMap _bundleToResource = new ConcurrentHashMap<>(); private ConcurrentHashMap _resourceToBundle = new ConcurrentHashMap<>(); - private ConcurrentHashMap _bundleToUri = new ConcurrentHashMap<>(); - + private ConcurrentHashMap _bundleToUri = new ConcurrentHashMap<>(); + public AnnotationParser(int javaPlatform) { - super(javaPlatform, Opcodes.ASM5); + super(javaPlatform, Opcodes.ASM7); } - + /** * Keep track of a jetty URI Resource and its associated OSGi bundle. - * + * * @param bundle the bundle to index * @return the resource for the bundle * @throws Exception if unable to create the resource reference @@ -64,32 +65,34 @@ public class AnnotationParser extends org.eclipse.jetty.annotations.AnnotationPa File bundleFile = BundleFileLocatorHelperFactory.getFactory().getHelper().getBundleInstallLocation(bundle); Resource resource = Resource.newResource(bundleFile.toURI()); URI uri = resource.getURI(); - _uriToBundle.putIfAbsent(uri,bundle); - _bundleToUri.putIfAbsent(bundle,uri); - _bundleToResource.putIfAbsent(bundle,resource); - _resourceToBundle.putIfAbsent(resource,bundle); + _uriToBundle.putIfAbsent(uri, bundle); + _bundleToUri.putIfAbsent(bundle, uri); + _bundleToResource.putIfAbsent(bundle, resource); + _resourceToBundle.putIfAbsent(resource, bundle); return resource; } + protected URI getURI(Bundle bundle) { return _bundleToUri.get(bundle); } + protected Resource getResource(Bundle bundle) { return _bundleToResource.get(bundle); } - protected Bundle getBundle (Resource resource) + + protected Bundle getBundle(Resource resource) { return _resourceToBundle.get(resource); } - - + /** - * + * */ @Override - public void parse (Set handlers, URI[] uris) - throws Exception + public void parse(Set handlers, URI[] uris) + throws Exception { for (URI uri : uris) { @@ -102,7 +105,7 @@ public class AnnotationParser extends org.eclipse.jetty.annotations.AnnotationPa } //a jar in WEB-INF/lib or the WEB-INF/classes //use the behavior of the super class for a standard jar. - super.parse(handlers, new URI[] {uri}); + super.parse(handlers, new URI[]{uri}); } else { @@ -110,16 +113,16 @@ public class AnnotationParser extends org.eclipse.jetty.annotations.AnnotationPa } } } - + protected void parse(Set handlers, Bundle bundle) - throws Exception + throws Exception { URI uri = _bundleToUri.get(bundle); if (!_alreadyParsed.add(uri)) { return; } - + String bundleClasspath = (String)bundle.getHeaders().get(Constants.BUNDLE_CLASSPATH); if (bundleClasspath == null) { @@ -127,20 +130,20 @@ public class AnnotationParser extends org.eclipse.jetty.annotations.AnnotationPa } //order the paths first by the number of tokens in the path second alphabetically. TreeSet paths = new TreeSet<>( - new Comparator() + new Comparator() + { + @Override + public int compare(String o1, String o2) { - @Override - public int compare(String o1, String o2) + int paths1 = new StringTokenizer(o1, "/", false).countTokens(); + int paths2 = new StringTokenizer(o2, "/", false).countTokens(); + if (paths1 == paths2) { - int paths1 = new StringTokenizer(o1,"/",false).countTokens(); - int paths2 = new StringTokenizer(o2,"/",false).countTokens(); - if (paths1 == paths2) - { - return o1.compareTo(o2); - } - return paths2 - paths1; + return o1.compareTo(o2); } - }); + return paths2 - paths1; + } + }); boolean hasDotPath = false; StringTokenizer tokenizer = new StringTokenizer(bundleClasspath, ",;", false); while (tokenizer.hasMoreTokens()) @@ -156,7 +159,7 @@ public class AnnotationParser extends org.eclipse.jetty.annotations.AnnotationPa } else if (!token.endsWith(".jar") && !token.endsWith("/")) { - paths.add(token+"/"); + paths.add(token + "/"); } else { @@ -178,14 +181,14 @@ public class AnnotationParser extends org.eclipse.jetty.annotations.AnnotationPa } } @SuppressWarnings("rawtypes") - Enumeration classes = bundle.findEntries("/","*.class",true); + Enumeration classes = bundle.findEntries("/", "*.class", true); if (classes == null) { return; } while (classes.hasMoreElements()) { - URL classUrl = (URL) classes.nextElement(); + URL classUrl = (URL)classes.nextElement(); String path = classUrl.getPath(); //remove the longest path possible: String name = null; @@ -209,7 +212,7 @@ public class AnnotationParser extends org.eclipse.jetty.annotations.AnnotationPa continue; } //transform into a classname to pass to the resolver - String shortName = name.replace('/', '.').substring(0,name.length()-6); + String shortName = StringUtil.replace(name, '/', '.').substring(0, name.length() - 6); addParsedClass(shortName, getResource(bundle)); try (InputStream classInputStream = classUrl.openStream()) diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractContextProvider.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractContextProvider.java index ef045288ff1..1d9d977fb11 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractContextProvider.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractContextProvider.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -37,76 +37,66 @@ import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.xml.XmlConfiguration; import org.osgi.framework.Bundle; - - - /** * AbstractContextProvider * - * Base class for DeploymentManager Providers that can deploy ContextHandlers into + * Base class for DeploymentManager Providers that can deploy ContextHandlers into * Jetty that have been discovered via OSGI either as bundles or services. - * */ public abstract class AbstractContextProvider extends AbstractLifeCycle implements AppProvider { private static final Logger LOG = Log.getLogger(AbstractContextProvider.class); - - private DeploymentManager _deploymentManager; - + + private DeploymentManager _deploymentManager; + private ServerInstanceWrapper _serverWrapper; - - - - - /* ------------------------------------------------------------ */ + /** * OSGiApp - * - * */ public class OSGiApp extends AbstractOSGiApp { private String _contextFile; private ContextHandler _contextHandler; private boolean _configured = false; - + public OSGiApp(DeploymentManager manager, AppProvider provider, String originId, Bundle bundle, String contextFile) { super(manager, provider, bundle, originId); _contextFile = contextFile; } - + public OSGiApp(DeploymentManager manager, AppProvider provider, Bundle bundle, Dictionary properties, String contextFile, String originId) { super(manager, provider, bundle, properties, originId); _contextFile = contextFile; } - - public String getContextFile () + + public String getContextFile() { return _contextFile; } - + public void setHandler(ContextHandler h) { _contextHandler = h; } - + public ContextHandler createContextHandler() - throws Exception + throws Exception { configureContextHandler(); return _contextHandler; } public void configureContextHandler() - throws Exception + throws Exception { if (_configured) return; _configured = true; - + //Override for bundle root may have been set String bundleOverrideLocation = (String)_properties.get(OSGiWebappConstants.JETTY_BUNDLE_INSTALL_LOCATION_OVERRIDE); if (bundleOverrideLocation == null) @@ -114,17 +104,17 @@ public abstract class AbstractContextProvider extends AbstractLifeCycle implemen //Location on filesystem of bundle or the bundle override location File bundleLocation = BundleFileLocatorHelperFactory.getFactory().getHelper().getBundleInstallLocation(_bundle); - File root = (bundleOverrideLocation==null?bundleLocation:new File(bundleOverrideLocation)); + File root = (bundleOverrideLocation == null ? bundleLocation : new File(bundleOverrideLocation)); Resource rootResource = Resource.newResource(BundleFileLocatorHelperFactory.getFactory().getHelper().getLocalURL(root.toURI().toURL())); - + //try and make sure the rootResource is useable - if its a jar then make it a jar file url - if (rootResource.exists()&& !rootResource.isDirectory() && !rootResource.toString().startsWith("jar:")) + if (rootResource.exists() && !rootResource.isDirectory() && !rootResource.toString().startsWith("jar:")) { - Resource jarResource = JarResource.newJarResource(rootResource); - if (jarResource.exists() && jarResource.isDirectory()) - rootResource = jarResource; + Resource jarResource = JarResource.newJarResource(rootResource); + if (jarResource.exists() && jarResource.isDirectory()) + rootResource = jarResource; } - + //Set the base resource of the ContextHandler, if not already set, can also be overridden by the context xml file if (_contextHandler != null && _contextHandler.getBaseResource() == null) { @@ -139,39 +129,39 @@ public abstract class AbstractContextProvider extends AbstractLifeCycle implemen throw new IllegalStateException("No context file or ContextHandler"); if (_contextFile != null) - { + { //apply the contextFile, creating the ContextHandler, the DeploymentManager will register it in the ContextHandlerCollection Resource res = null; - + String jettyHome = (String)getServerInstanceWrapper().getServer().getAttribute(OSGiServerConstants.JETTY_HOME); if (jettyHome == null) - jettyHome = System.getProperty(OSGiServerConstants.JETTY_HOME); - + jettyHome = System.getProperty(OSGiServerConstants.JETTY_HOME); + res = findFile(_contextFile, jettyHome, bundleOverrideLocation, _bundle); //apply the context xml file, either to an existing ContextHandler, or letting the //it create the ContextHandler as necessary if (res != null) - { + { ClassLoader cl = Thread.currentThread().getContextClassLoader(); LOG.debug("Context classloader = " + cl); try { Thread.currentThread().setContextClassLoader(classLoader); - - XmlConfiguration xmlConfiguration = new XmlConfiguration(res.getInputStream()); + + XmlConfiguration xmlConfiguration = new XmlConfiguration(res); HashMap properties = new HashMap(); //put the server instance in properties.put("Server", getServerInstanceWrapper().getServer()); //put in the location of the bundle root properties.put(OSGiWebappConstants.JETTY_BUNDLE_ROOT, rootResource.toString()); - + // insert the bundle's location as a property. xmlConfiguration.getProperties().putAll(properties); if (_contextHandler == null) - _contextHandler = (ContextHandler) xmlConfiguration.configure(); + _contextHandler = (ContextHandler)xmlConfiguration.configure(); else xmlConfiguration.configure(_contextHandler); } @@ -184,53 +174,45 @@ public abstract class AbstractContextProvider extends AbstractLifeCycle implemen //Set up the class loader we created _contextHandler.setClassLoader(classLoader); - - + //If a bundle/service property specifies context path, let it override the context xml String contextPath = (String)_properties.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH); if (contextPath == null) contextPath = (String)_properties.get(OSGiWebappConstants.SERVICE_PROP_CONTEXT_PATH); if (contextPath != null) - _contextHandler.setContextPath(contextPath); - + _contextHandler.setContextPath(contextPath); + //osgi Enterprise Spec r4 p.427 _contextHandler.setAttribute(OSGiWebappConstants.OSGI_BUNDLECONTEXT, _bundle.getBundleContext()); - + //make sure we protect also the osgi dirs specified by OSGi Enterprise spec String[] targets = _contextHandler.getProtectedTargets(); - int length = (targets==null?0:targets.length); - + int length = (targets == null ? 0 : targets.length); + String[] updatedTargets = null; if (targets != null) { - updatedTargets = new String[length+OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS.length]; + updatedTargets = new String[length + OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS.length]; System.arraycopy(targets, 0, updatedTargets, 0, length); - } else updatedTargets = new String[OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS.length]; System.arraycopy(OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS, 0, updatedTargets, length, OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS.length); _contextHandler.setProtectedTargets(updatedTargets); - } - } - - /* ------------------------------------------------------------ */ + public AbstractContextProvider(ServerInstanceWrapper wrapper) { _serverWrapper = wrapper; } - - - /* ------------------------------------------------------------ */ + public ServerInstanceWrapper getServerInstanceWrapper() { return _serverWrapper; } - - /* ------------------------------------------------------------ */ - /** + + /** * @see org.eclipse.jetty.deploy.AppProvider#createContextHandler(org.eclipse.jetty.deploy.App) */ @Override @@ -239,21 +221,19 @@ public abstract class AbstractContextProvider extends AbstractLifeCycle implemen if (app == null) return null; if (!(app instanceof OSGiApp)) - throw new IllegalStateException(app+" is not a BundleApp"); - + throw new IllegalStateException(app + " is not a BundleApp"); + //Create a ContextHandler suitable to deploy in OSGi - ContextHandler h = ((OSGiApp)app).createContextHandler(); + ContextHandler h = ((OSGiApp)app).createContextHandler(); return h; } - - /* ------------------------------------------------------------ */ + @Override public void setDeploymentManager(DeploymentManager deploymentManager) { _deploymentManager = deploymentManager; } - - /* ------------------------------------------------------------ */ + public DeploymentManager getDeploymentManager() { return _deploymentManager; diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractOSGiApp.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractOSGiApp.java index 68cd5c4b5bd..1db95bb2df3 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractOSGiApp.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractOSGiApp.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -34,74 +34,63 @@ import org.osgi.framework.Bundle; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.ServiceRegistration; - - /** * AbstractOSGiApp * * Base class representing info about a webapp/ContextHandler that is deployed into Jetty. - * */ public abstract class AbstractOSGiApp extends App -{ +{ private static final Logger LOG = Log.getLogger(AbstractOSGiApp.class); - + protected Bundle _bundle; - protected Dictionary _properties; + protected Dictionary _properties; protected ServiceRegistration _registration; - /* ------------------------------------------------------------ */ public AbstractOSGiApp(DeploymentManager manager, AppProvider provider, Bundle bundle, String originId) { - this (manager, provider, bundle, bundle.getHeaders(), originId); + this(manager, provider, bundle, bundle.getHeaders(), originId); } - /* ------------------------------------------------------------ */ - public AbstractOSGiApp(DeploymentManager manager, AppProvider provider, Bundle bundle, Dictionary properties, String originId) + + public AbstractOSGiApp(DeploymentManager manager, AppProvider provider, Bundle bundle, Dictionary properties, String originId) { super(manager, provider, originId); _properties = properties; _bundle = bundle; } - - /* ------------------------------------------------------------ */ + public String getBundleSymbolicName() { return _bundle.getSymbolicName(); } - - /* ------------------------------------------------------------ */ + public String getBundleVersionAsString() { - if (_bundle.getVersion() == null) - return null; - return _bundle.getVersion().toString(); + if (_bundle.getVersion() == null) + return null; + return _bundle.getVersion().toString(); } - - /* ------------------------------------------------------------ */ + public Bundle getBundle() { return _bundle; } - - /* ------------------------------------------------------------ */ - public void setRegistration (ServiceRegistration registration) + + public void setRegistration(ServiceRegistration registration) { _registration = registration; } - - /* ------------------------------------------------------------ */ - public ServiceRegistration getRegistration () + + public ServiceRegistration getRegistration() { return _registration; } - - - /* ------------------------------------------------------------ */ + public void registerAsOSGiService() throws Exception { if (_registration == null) { - Dictionary properties = new Hashtable(); + Dictionary properties = new Hashtable(); properties.put(OSGiWebappConstants.WATERMARK, OSGiWebappConstants.WATERMARK); if (getBundleSymbolicName() != null) properties.put(OSGiWebappConstants.OSGI_WEB_SYMBOLICNAME, getBundleSymbolicName()); @@ -113,7 +102,6 @@ public abstract class AbstractOSGiApp extends App } } - /* ------------------------------------------------------------ */ protected void deregisterAsOSGiService() throws Exception { if (_registration == null) @@ -123,39 +111,39 @@ public abstract class AbstractOSGiApp extends App _registration = null; } - protected Resource getFileAsResource (String dir, String file) + protected Resource getFileAsResource(String dir, String file) { Resource r = null; try { - File asFile = new File (dir, file); + File asFile = new File(dir, file); if (asFile.exists()) r = Resource.newResource(asFile); } catch (Exception e) { r = null; - } + } return r; } - - protected Resource getFileAsResource (String file) + + protected Resource getFileAsResource(String file) { Resource r = null; try { - File asFile = new File (file); + File asFile = new File(file); if (asFile.exists()) r = Resource.newResource(asFile); } catch (Exception e) { r = null; - } + } return r; } - - protected Resource findFile (String fileName, String jettyHome, String bundleOverrideLocation, Bundle containingBundle) + + protected Resource findFile(String fileName, String jettyHome, String bundleOverrideLocation, Bundle containingBundle) { Resource res = null; @@ -171,29 +159,28 @@ public abstract class AbstractOSGiApp extends App if (jettyHome.startsWith("\"") || jettyHome.startsWith("'")) jettyHome = jettyHome.substring(1); if (jettyHome.endsWith("\"") || (jettyHome.endsWith("'"))) - jettyHome = jettyHome.substring(0,jettyHome.length()-1); + jettyHome = jettyHome.substring(0, jettyHome.length() - 1); - res = getFileAsResource(jettyHome, fileName); + res = getFileAsResource(jettyHome, fileName); } if (res != null) return res; - //try to find it relative to an override location that has been specified if (bundleOverrideLocation != null) - { - try(Resource location=Resource.newResource(bundleOverrideLocation)) + { + try (Resource location = Resource.newResource(bundleOverrideLocation)) { - res=location.addPath(fileName); + res = location.addPath(fileName); } catch (Exception e) { LOG.warn(e); } - } + } if (res != null) return res; - + //try to find it relative to the bundle in which it is being deployed if (containingBundle != null) { @@ -207,7 +194,7 @@ public abstract class AbstractOSGiApp extends App if (entry != null) res = Resource.newResource(entry); } - + return res; } } diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractWebAppProvider.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractWebAppProvider.java index 2ac88bee6d0..9c557616b13 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractWebAppProvider.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractWebAppProvider.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -55,11 +55,10 @@ import org.osgi.service.packageadmin.PackageAdmin; public abstract class AbstractWebAppProvider extends AbstractLifeCycle implements AppProvider { private static final Logger LOG = Log.getLogger(AbstractWebAppProvider.class); - - /* ------------------------------------------------------------ */ + /** * Check if we should be enabling annotation processing - * + * * @return true if the jetty-annotations.jar is present, false otherwise */ private static boolean annotationsAvailable() @@ -67,7 +66,7 @@ public abstract class AbstractWebAppProvider extends AbstractLifeCycle implement boolean result = false; try { - Loader.loadClass(AbstractWebAppProvider.class,"org.eclipse.jetty.annotations.AnnotationConfiguration"); + Loader.loadClass(AbstractWebAppProvider.class, "org.eclipse.jetty.annotations.AnnotationConfiguration"); result = true; LOG.debug("Annotation support detected"); } @@ -79,11 +78,10 @@ public abstract class AbstractWebAppProvider extends AbstractLifeCycle implement return result; } - - /* ------------------------------------------------------------ */ + /** * Check if jndi is support is present. - * + * * @return true if the jetty-jndi.jar is present, false otherwise */ private static boolean jndiAvailable() @@ -101,7 +99,6 @@ public abstract class AbstractWebAppProvider extends AbstractLifeCycle implement return false; } } - private boolean _parentLoaderPriority; @@ -110,16 +107,13 @@ public abstract class AbstractWebAppProvider extends AbstractLifeCycle implement private boolean _extractWars = true; //See WebAppContext.extractWars private String _tldBundles; - + private DeploymentManager _deploymentManager; - + private String[] _configurationClasses; - + private ServerInstanceWrapper _serverWrapper; - - - - /* ------------------------------------------------------------ */ + /** * OSGiApp * @@ -135,13 +129,13 @@ public abstract class AbstractWebAppProvider extends AbstractLifeCycle implement { super(manager, provider, bundle, originId); } - + public OSGiApp(DeploymentManager manager, AppProvider provider, Bundle bundle, Dictionary properties, String originId) { super(manager, provider, bundle, properties, originId); } - - public void setWebAppContext (WebAppContext webApp) + + public void setWebAppContext(WebAppContext webApp) { _webApp = webApp; } @@ -166,31 +160,28 @@ public abstract class AbstractWebAppProvider extends AbstractLifeCycle implement { this._webAppPath = path; } - - + public ContextHandler createContextHandler() - throws Exception + throws Exception { if (_webApp != null) { configureWebApp(); return _webApp; } - + createWebApp(); return _webApp; } - - - - protected void createWebApp () - throws Exception + + protected void createWebApp() + throws Exception { _webApp = newWebApp(); configureWebApp(); } - - protected WebAppContext newWebApp () + + protected WebAppContext newWebApp() { WebAppContext webApp = new WebAppContext(); webApp.setAttribute(OSGiWebappConstants.WATERMARK, OSGiWebappConstants.WATERMARK); @@ -200,7 +191,7 @@ public abstract class AbstractWebAppProvider extends AbstractLifeCycle implement String[] updatedTargets = null; if (targets != null) { - updatedTargets = new String[targets.length+OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS.length]; + updatedTargets = new String[targets.length + OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS.length]; System.arraycopy(targets, 0, updatedTargets, 0, targets.length); } else @@ -208,40 +199,39 @@ public abstract class AbstractWebAppProvider extends AbstractLifeCycle implement System.arraycopy(OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS, 0, updatedTargets, targets.length, OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS.length); webApp.setProtectedTargets(updatedTargets); - return webApp; + return webApp; } - - public void configureWebApp() - throws Exception - { + public void configureWebApp() + throws Exception + { //TODO turn this around and let any context.xml file get applied first, and have the properties override _webApp.setContextPath(_contextPath); - + //osgi Enterprise Spec r4 p.427 _webApp.setAttribute(OSGiWebappConstants.OSGI_BUNDLECONTEXT, _bundle.getBundleContext()); String overrideBundleInstallLocation = (String)_properties.get(OSGiWebappConstants.JETTY_BUNDLE_INSTALL_LOCATION_OVERRIDE); - File bundleInstallLocation = - (overrideBundleInstallLocation == null - ? BundleFileLocatorHelperFactory.getFactory().getHelper().getBundleInstallLocation(_bundle) - : new File(overrideBundleInstallLocation)); - + File bundleInstallLocation = + (overrideBundleInstallLocation == null + ? BundleFileLocatorHelperFactory.getFactory().getHelper().getBundleInstallLocation(_bundle) + : new File(overrideBundleInstallLocation)); + if (LOG.isDebugEnabled()) { LOG.debug("Bundle location is {}, install location: {}", _bundle.getLocation(), bundleInstallLocation); } - + URL url = null; Resource rootResource = Resource.newResource(BundleFileLocatorHelperFactory.getFactory().getHelper().getLocalURL(bundleInstallLocation.toURI().toURL())); //try and make sure the rootResource is useable - if its a jar then make it a jar file url - if (rootResource.exists()&& !rootResource.isDirectory() && !rootResource.toString().startsWith("jar:")) + if (rootResource.exists() && !rootResource.isDirectory() && !rootResource.toString().startsWith("jar:")) { - Resource jarResource = JarResource.newJarResource(rootResource); - if (jarResource.exists() && jarResource.isDirectory()) - rootResource = jarResource; + Resource jarResource = JarResource.newJarResource(rootResource); + if (jarResource.exists() && jarResource.isDirectory()) + rootResource = jarResource; } - + //if the path wasn't set or it was ., then it is the root of the bundle's installed location if (_webAppPath == null || _webAppPath.length() == 0 || ".".equals(_webAppPath)) { @@ -277,10 +267,10 @@ public abstract class AbstractWebAppProvider extends AbstractLifeCycle implement } if (url == null) - { - throw new IllegalArgumentException("Unable to locate " + _webAppPath - + " in " - + (bundleInstallLocation != null ? bundleInstallLocation.getAbsolutePath() : "unlocated bundle '" + _bundle.getSymbolicName()+ "'")); + { + throw new IllegalArgumentException(String.format("Unable to locate %s in %s", + _webAppPath, + (bundleInstallLocation != null ? bundleInstallLocation.getAbsolutePath() : "missing bundle '" + _bundle.getSymbolicName() + "'"))); } //Sets the location of the war file @@ -292,7 +282,6 @@ public abstract class AbstractWebAppProvider extends AbstractLifeCycle implement _webApp.setExtractWAR(isExtract()); _webApp.setConfigurationClasses(getConfigurationClasses()); - if (getDefaultsDescriptor() != null) _webApp.setDefaultsDescriptor(getDefaultsDescriptor()); @@ -306,7 +295,7 @@ public abstract class AbstractWebAppProvider extends AbstractLifeCycle implement tmp = (String)_properties.get(OSGiWebappConstants.JETTY_WEB_XML_PATH); if (tmp != null && tmp.trim().length() != 0) { - File webXml = getFile (tmp, bundleInstallLocation); + File webXml = getFile(tmp, bundleInstallLocation); if (webXml != null && webXml.exists()) _webApp.setDescriptor(webXml.getAbsolutePath()); } @@ -315,13 +304,13 @@ public abstract class AbstractWebAppProvider extends AbstractLifeCycle implement tmp = (String)_properties.get(OSGiWebappConstants.JETTY_DEFAULT_WEB_XML_PATH); if (tmp != null) { - File defaultWebXml = getFile (tmp, bundleInstallLocation); + File defaultWebXml = getFile(tmp, bundleInstallLocation); if (defaultWebXml != null) { if (defaultWebXml.exists()) _webApp.setDefaultsDescriptor(defaultWebXml.getAbsolutePath()); else - LOG.warn(defaultWebXml.getAbsolutePath()+" does not exist"); + LOG.warn(defaultWebXml.getAbsolutePath() + " does not exist"); } } @@ -331,7 +320,6 @@ public abstract class AbstractWebAppProvider extends AbstractLifeCycle implement String requireTldBundles = (String)_properties.get(OSGiWebappConstants.REQUIRE_TLD_BUNDLE); String pathsToTldBundles = getPathsToRequiredBundles(requireTldBundles); - // make sure we provide access to all the jetty bundles by going // through this bundle. OSGiWebappClassLoader webAppLoader = new OSGiWebappClassLoader(_serverWrapper.getParentClassLoaderForWebapps(), _webApp, _bundle); @@ -340,7 +328,6 @@ public abstract class AbstractWebAppProvider extends AbstractLifeCycle implement webAppLoader.addClassPath(pathsToTldBundles); _webApp.setClassLoader(webAppLoader); - // apply any META-INF/context.xml file that is found to configure // the webapp first applyMetaInfContextXml(rootResource, overrideBundleInstallLocation); @@ -364,58 +351,59 @@ public abstract class AbstractWebAppProvider extends AbstractLifeCycle implement _webApp.setAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE, _bundle); } - protected String getPathsToRequiredBundles (String requireTldBundles) - throws Exception + protected String getPathsToRequiredBundles(String requireTldBundles) + throws Exception { - if (requireTldBundles == null) return null; + if (requireTldBundles == null) + return null; ServiceReference ref = _bundle.getBundleContext().getServiceReference(org.osgi.service.packageadmin.PackageAdmin.class.getName()); PackageAdmin packageAdmin = (ref == null) ? null : (PackageAdmin)_bundle.getBundleContext().getService(ref); if (packageAdmin == null) throw new IllegalStateException("Unable to get PackageAdmin reference to locate required Tld bundles"); - StringBuilder paths = new StringBuilder(); + StringBuilder paths = new StringBuilder(); String[] symbNames = requireTldBundles.split("[, ]"); for (String symbName : symbNames) { Bundle[] bs = packageAdmin.getBundles(symbName, null); - if (bs == null || bs.length == 0) - { - throw new IllegalArgumentException("Unable to locate the bundle '" + symbName - + "' specified by " - + OSGiWebappConstants.REQUIRE_TLD_BUNDLE - + " in manifest of " - + (_bundle == null ? "unknown" : _bundle.getSymbolicName())); + if (bs == null || bs.length == 0) + { + throw new IllegalArgumentException("Unable to locate the bundle '" + symbName + + "' specified by " + OSGiWebappConstants.REQUIRE_TLD_BUNDLE + " in manifest of " + + (_bundle == null ? "unknown" : _bundle.getSymbolicName())); } File f = BundleFileLocatorHelperFactory.getFactory().getHelper().getBundleInstallLocation(bs[0]); - if (paths.length() > 0) paths.append(", "); + if (paths.length() > 0) + paths.append(", "); paths.append(f.toURI().toURL().toString()); LOG.debug("getPathsToRequiredBundles: bundle path=" + bs[0].getLocation() + " uri=" + f.toURI()); } return paths.toString(); } - - + protected void applyMetaInfContextXml(Resource rootResource, String overrideBundleInstallLocation) - throws Exception + throws Exception { - if (_bundle == null) return; - if (_webApp == null) return; + if (_bundle == null) + return; + if (_webApp == null) + return; ClassLoader cl = Thread.currentThread().getContextClassLoader(); LOG.debug("Context classloader = " + cl); try { - + Thread.currentThread().setContextClassLoader(_webApp.getClassLoader()); //TODO replace this with getting the InputStream so we don't cache in URL //Try looking for a context xml file in META-INF with a specific name URL contextXmlUrl = _bundle.getEntry("/META-INF/jetty-webapp-context.xml"); - + if (contextXmlUrl == null) { //Didn't find specially named file, try looking for a property that names a context xml file to use @@ -430,7 +418,7 @@ public abstract class AbstractWebAppProvider extends AbstractLifeCycle implement String filename = filenames[0]; //should only be 1 filename in this usage String jettyHome = (String)getServerInstanceWrapper().getServer().getAttribute(OSGiServerConstants.JETTY_HOME); if (jettyHome == null) - jettyHome = System.getProperty(OSGiServerConstants.JETTY_HOME); + jettyHome = System.getProperty(OSGiServerConstants.JETTY_HOME); Resource res = findFile(filename, jettyHome, overrideBundleInstallLocation, _bundle); if (res != null) contextXmlUrl = res.getURL(); @@ -438,17 +426,17 @@ public abstract class AbstractWebAppProvider extends AbstractLifeCycle implement } } } - if (contextXmlUrl == null) + if (contextXmlUrl == null) return; // Apply it just as the standard jetty ContextProvider would do LOG.info("Applying " + contextXmlUrl + " to " + _webApp); XmlConfiguration xmlConfiguration = new XmlConfiguration(contextXmlUrl); - WebAppClassLoader.runWithServerClassAccess(()-> + WebAppClassLoader.runWithServerClassAccess(() -> { - HashMap properties = new HashMap<>(); - xmlConfiguration.getIdMap().put("Server",getDeploymentManager().getServer()); + HashMap properties = new HashMap<>(); + xmlConfiguration.getIdMap().put("Server", getDeploymentManager().getServer()); properties.put(OSGiWebappConstants.JETTY_BUNDLE_ROOT, rootResource.toString()); properties.put(OSGiServerConstants.JETTY_HOME, (String)getDeploymentManager().getServer().getAttribute(OSGiServerConstants.JETTY_HOME)); xmlConfiguration.getProperties().putAll(properties); @@ -461,8 +449,8 @@ public abstract class AbstractWebAppProvider extends AbstractLifeCycle implement Thread.currentThread().setContextClassLoader(cl); } } - - private File getFile (String file, File bundleInstall) + + private File getFile(String file, File bundleInstall) { if (file == null) return null; @@ -473,29 +461,26 @@ public abstract class AbstractWebAppProvider extends AbstractLifeCycle implement { //relative location //try inside the bundle first - File f = new File (bundleInstall, file); - if (f.exists()) return f; + File f = new File(bundleInstall, file); + if (f.exists()) + return f; String jettyHome = (String)getDeploymentManager().getServer().getAttribute(OSGiServerConstants.JETTY_HOME); if (jettyHome != null) return new File(jettyHome, file); } - + return null; } } - - /* ------------------------------------------------------------ */ - public AbstractWebAppProvider (ServerInstanceWrapper wrapper) + + public AbstractWebAppProvider(ServerInstanceWrapper wrapper) { _serverWrapper = wrapper; } - - - - /* ------------------------------------------------------------ */ + /** * Get the parentLoaderPriority. - * + * * @return the parentLoaderPriority */ public boolean isParentLoaderPriority() @@ -503,10 +488,9 @@ public abstract class AbstractWebAppProvider extends AbstractLifeCycle implement return _parentLoaderPriority; } - /* ------------------------------------------------------------ */ /** * Set the parentLoaderPriority. - * + * * @param parentLoaderPriority the parentLoaderPriority to set */ public void setParentLoaderPriority(boolean parentLoaderPriority) @@ -514,10 +498,9 @@ public abstract class AbstractWebAppProvider extends AbstractLifeCycle implement _parentLoaderPriority = parentLoaderPriority; } - /* ------------------------------------------------------------ */ /** * Get the defaultsDescriptor. - * + * * @return the defaultsDescriptor */ public String getDefaultsDescriptor() @@ -525,63 +508,52 @@ public abstract class AbstractWebAppProvider extends AbstractLifeCycle implement return _defaultsDescriptor; } - /* ------------------------------------------------------------ */ /** * Set the defaultsDescriptor. - * + * * @param defaultsDescriptor the defaultsDescriptor to set */ public void setDefaultsDescriptor(String defaultsDescriptor) { _defaultsDescriptor = defaultsDescriptor; } - - - /* ------------------------------------------------------------ */ + public boolean isExtract() { return _extractWars; } - - - /* ------------------------------------------------------------ */ + public void setExtract(boolean extract) { _extractWars = extract; } - - - /* ------------------------------------------------------------ */ + /** * @param tldBundles Comma separated list of bundles that contain tld jars - * that should be setup on the jetty instances created here. + * that should be setup on the jetty instances created here. */ public void setTldBundles(String tldBundles) { _tldBundles = tldBundles; } - - - /* ------------------------------------------------------------ */ + /** * @return The list of bundles that contain tld jars that should be setup on - * the jetty instances created here. + * the jetty instances created here. */ public String getTldBundles() { return _tldBundles; } - - /* ------------------------------------------------------------ */ + /** * @param configurations The configuration class names. */ public void setConfigurationClasses(String[] configurations) { - _configurationClasses = configurations == null ? null : (String[]) configurations.clone(); + _configurationClasses = configurations == null ? null : configurations.clone(); } - /* ------------------------------------------------------------ */ public String[] getConfigurationClasses() { if (_configurationClasses != null) @@ -591,25 +563,23 @@ public abstract class AbstractWebAppProvider extends AbstractLifeCycle implement //add before JettyWebXmlConfiguration if (annotationsAvailable() && !defaults.contains("org.eclipse.jetty.osgi.annotations.AnnotationConfiguration")) - defaults.addBefore("org.eclipse.jetty.webapp.JettyWebXmlConfiguration", - "org.eclipse.jetty.osgi.annotations.AnnotationConfiguration"); + defaults.addBefore("org.eclipse.jetty.webapp.JettyWebXmlConfiguration", + "org.eclipse.jetty.osgi.annotations.AnnotationConfiguration"); //add in EnvConfiguration and PlusConfiguration just after FragmentConfiguration if (jndiAvailable()) { if (!defaults.contains("org.eclipse.jetty.plus.webapp.EnvConfiguration")) defaults.addAfter("org.eclipse.jetty.webapp.FragmentConfiguration", - "org.eclipse.jetty.plus.webapp.EnvConfiguration"); + "org.eclipse.jetty.plus.webapp.EnvConfiguration"); if (!defaults.contains("org.eclipse.jetty.plus.webapp.PlusConfiguration")) defaults.addAfter("org.eclipse.jetty.plus.webapp.EnvConfiguration", "org.eclipse.jetty.plus.webapp.PlusConfiguration"); } - String[] asArray = new String[defaults.size()]; - return defaults.toArray(asArray); + String[] asArray = new String[defaults.size()]; + return defaults.toArray(asArray); } - - /* ------------------------------------------------------------ */ public void setServerInstanceWrapper(ServerInstanceWrapper wrapper) { _serverWrapper = wrapper; @@ -620,14 +590,12 @@ public abstract class AbstractWebAppProvider extends AbstractLifeCycle implement return _serverWrapper; } - /* ------------------------------------------------------------ */ public DeploymentManager getDeploymentManager() { return _deploymentManager; } - /* ------------------------------------------------------------ */ - /** + /** * @see org.eclipse.jetty.deploy.AppProvider#setDeploymentManager(org.eclipse.jetty.deploy.DeploymentManager) */ @Override @@ -635,27 +603,22 @@ public abstract class AbstractWebAppProvider extends AbstractLifeCycle implement { _deploymentManager = deploymentManager; } - - - /* ------------------------------------------------------------ */ + @Override public ContextHandler createContextHandler(App app) throws Exception { if (app == null) return null; if (!(app instanceof OSGiApp)) - throw new IllegalStateException(app+" is not a BundleApp"); + throw new IllegalStateException(app + " is not a BundleApp"); //Create a WebAppContext suitable to deploy in OSGi ContextHandler ch = ((OSGiApp)app).createContextHandler(); return ch; } - - /* ------------------------------------------------------------ */ public static String getOriginId(Bundle contributor, String path) { return contributor.getSymbolicName() + "-" + contributor.getVersion().toString() + (path.startsWith("/") ? path : "/" + path); } - } diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleContextProvider.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleContextProvider.java index f35c8e237aa..d506c82aeb8 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleContextProvider.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleContextProvider.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -43,29 +43,28 @@ import org.osgi.util.tracker.BundleTracker; * Handles deploying OSGi bundles that define a context xml file for configuring them. */ public class BundleContextProvider extends AbstractContextProvider implements BundleProvider -{ +{ private static final Logger LOG = Log.getLogger(AbstractContextProvider.class); private Map _appMap = new HashMap(); - + private Map> _bundleMap = new HashMap>(); - + private ServiceRegistration _serviceRegForBundles; - + private BundleTracker _tracker; - - + public class ContextBundleTracker extends BundleTracker { protected String _managedServerName; - - public ContextBundleTracker (BundleContext bundleContext, String managedServerName) + + public ContextBundleTracker(BundleContext bundleContext, String managedServerName) { - super (bundleContext, Bundle.ACTIVE | Bundle.STOPPING,null); + super(bundleContext, Bundle.ACTIVE | Bundle.STOPPING, null); _managedServerName = managedServerName; } - /** + /** * @see org.osgi.util.tracker.BundleTracker#addingBundle(org.osgi.framework.Bundle, org.osgi.framework.BundleEvent) */ @Override @@ -74,10 +73,10 @@ public class BundleContextProvider extends AbstractContextProvider implements Bu try { String serverName = (String)bundle.getHeaders().get(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME); - if ((StringUtil.isBlank(serverName) && _managedServerName.equals(OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME)) - || (!StringUtil.isBlank(serverName) && (serverName.equals(_managedServerName)))) + if ((StringUtil.isBlank(serverName) && _managedServerName.equals(OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME)) || + (!StringUtil.isBlank(serverName) && (serverName.equals(_managedServerName)))) { - if (bundleAdded (bundle)) + if (bundleAdded(bundle)) return bundle; } } @@ -88,9 +87,7 @@ public class BundleContextProvider extends AbstractContextProvider implements Bu return null; } - - - /** + /** * @see org.osgi.util.tracker.BundleTracker#removedBundle(org.osgi.framework.Bundle, org.osgi.framework.BundleEvent, java.lang.Object) */ @Override @@ -105,37 +102,32 @@ public class BundleContextProvider extends AbstractContextProvider implements Bu LOG.warn(e); } } - } - - /* ------------------------------------------------------------ */ + public BundleContextProvider(ServerInstanceWrapper wrapper) { super(wrapper); } - - - /* ------------------------------------------------------------ */ + @Override protected void doStart() throws Exception { //Track bundles that are ContextHandlers that should be deployed _tracker = new ContextBundleTracker(FrameworkUtil.getBundle(this.getClass()).getBundleContext(), getServerInstanceWrapper().getManagedServerName()); _tracker.open(); - + //register as an osgi service for deploying contexts defined in a bundle, advertising the name of the jetty Server instance we are related to - Dictionary properties = new Hashtable(); + Dictionary properties = new Hashtable(); properties.put(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME, getServerInstanceWrapper().getManagedServerName()); _serviceRegForBundles = FrameworkUtil.getBundle(this.getClass()).getBundleContext().registerService(BundleProvider.class.getName(), this, properties); super.doStart(); } - /* ------------------------------------------------------------ */ @Override protected void doStop() throws Exception { _tracker.close(); - + //unregister ourselves if (_serviceRegForBundles != null) { @@ -150,31 +142,27 @@ public class BundleContextProvider extends AbstractContextProvider implements Bu } } - - - - /* ------------------------------------------------------------ */ @Override - public boolean bundleAdded (Bundle bundle) throws Exception + public boolean bundleAdded(Bundle bundle) throws Exception { if (bundle == null) return false; //If the bundle defines a Web-ContextPath then its probably a webapp and the BundleWebAppProvider should deploy it - if ((String)bundle.getHeaders().get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH) != null) + if (bundle.getHeaders().get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH) != null) { - if (LOG.isDebugEnabled()) LOG.debug("BundleContextProvider ignoring bundle {} with {} set", bundle.getSymbolicName(), OSGiWebappConstants.RFC66_WEB_CONTEXTPATH); + if (LOG.isDebugEnabled()) + LOG.debug("BundleContextProvider ignoring bundle {} with {} set", bundle.getSymbolicName(), OSGiWebappConstants.RFC66_WEB_CONTEXTPATH); return false; } - - String contextFiles = (String)bundle.getHeaders().get(OSGiWebappConstants.JETTY_CONTEXT_FILE_PATH); + + String contextFiles = (String)bundle.getHeaders().get(OSGiWebappConstants.JETTY_CONTEXT_FILE_PATH); if (contextFiles == null) contextFiles = (String)bundle.getHeaders().get(OSGiWebappConstants.SERVICE_PROP_CONTEXT_FILE_PATH); - + if (contextFiles == null) return false; - - + boolean added = false; //bundle defines JETTY_CONTEXT_FILE_PATH header, //a comma separated list of context xml files that each define a ContextHandler @@ -182,9 +170,9 @@ public class BundleContextProvider extends AbstractContextProvider implements Bu String[] tmp = contextFiles.split("[,;]"); for (String contextFile : tmp) { - String originId = bundle.getSymbolicName() + "-" + bundle.getVersion().toString() + "-"+contextFile; + String originId = bundle.getSymbolicName() + "-" + bundle.getVersion().toString() + "-" + contextFile; OSGiApp app = new OSGiApp(getDeploymentManager(), this, originId, bundle, contextFile); - _appMap.put(originId,app); + _appMap.put(originId, app); List apps = _bundleMap.get(bundle); if (apps == null) { @@ -198,23 +186,21 @@ public class BundleContextProvider extends AbstractContextProvider implements Bu return added; //true if even 1 context from this bundle was added } - - - /* ------------------------------------------------------------ */ - /** + + /** * Bundle has been removed. If it was a context we deployed, undeploy it. - * + * * @param bundle the bundle * @return true if this was a context we had deployed, false otherwise */ @Override - public boolean bundleRemoved (Bundle bundle) throws Exception + public boolean bundleRemoved(Bundle bundle) throws Exception { List apps = _bundleMap.remove(bundle); boolean removed = false; if (apps != null) { - for (App app:apps) + for (App app : apps) { _appMap.remove(app.getOriginId()); getDeploymentManager().removeApp(app); @@ -223,6 +209,4 @@ public class BundleContextProvider extends AbstractContextProvider implements Bu } return removed; //true if even 1 context was removed associated with this bundle } - - } diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleProvider.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleProvider.java index 0539040f647..f793b069eba 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleProvider.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleProvider.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -27,7 +27,7 @@ import org.osgi.framework.Bundle; */ public interface BundleProvider { - public boolean bundleAdded (Bundle bundle) throws Exception; - - public boolean bundleRemoved (Bundle bundle) throws Exception; + boolean bundleAdded(Bundle bundle) throws Exception; + + boolean bundleRemoved(Bundle bundle) throws Exception; } diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleWebAppProvider.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleWebAppProvider.java index 04591fc68d7..dd6c086fd53 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleWebAppProvider.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleWebAppProvider.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -42,30 +42,29 @@ import org.osgi.util.tracker.BundleTracker; * A Jetty Provider that knows how to deploy a WebApp contained inside a Bundle. */ public class BundleWebAppProvider extends AbstractWebAppProvider implements BundleProvider -{ +{ private static final Logger LOG = Log.getLogger(AbstractWebAppProvider.class); - + /** * Map of Bundle to App. Used when a Bundle contains a webapp. */ private Map _bundleMap = new HashMap<>(); - + private ServiceRegistration _serviceRegForBundles; - + private WebAppTracker _webappTracker; - - + public class WebAppTracker extends BundleTracker { protected String _managedServerName; - - public WebAppTracker (BundleContext bundleContext, String managedServerName) + + public WebAppTracker(BundleContext bundleContext, String managedServerName) { - super (bundleContext, Bundle.ACTIVE | Bundle.STOPPING,null); + super(bundleContext, Bundle.ACTIVE | Bundle.STOPPING, null); _managedServerName = managedServerName; } - /** + /** * @see org.osgi.util.tracker.BundleTracker#addingBundle(org.osgi.framework.Bundle, org.osgi.framework.BundleEvent) */ @Override @@ -74,10 +73,10 @@ public class BundleWebAppProvider extends AbstractWebAppProvider implements Bund try { String serverName = (String)bundle.getHeaders().get(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME); - if ((StringUtil.isBlank(serverName) && _managedServerName.equals(OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME)) - || (!StringUtil.isBlank(serverName) && (serverName.equals(_managedServerName)))) + if ((StringUtil.isBlank(serverName) && _managedServerName.equals(OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME)) || + (!StringUtil.isBlank(serverName) && (serverName.equals(_managedServerName)))) { - if (bundleAdded (bundle)) + if (bundleAdded(bundle)) return bundle; } } @@ -88,9 +87,7 @@ public class BundleWebAppProvider extends AbstractWebAppProvider implements Bund return null; } - - - /** + /** * @see org.osgi.util.tracker.BundleTracker#removedBundle(org.osgi.framework.Bundle, org.osgi.framework.BundleEvent, java.lang.Object) */ @Override @@ -105,18 +102,14 @@ public class BundleWebAppProvider extends AbstractWebAppProvider implements Bund LOG.warn(e); } } - - } - /* ------------------------------------------------------------ */ - public BundleWebAppProvider (ServerInstanceWrapper wrapper) + public BundleWebAppProvider(ServerInstanceWrapper wrapper) { super(wrapper); } - - /* ------------------------------------------------------------ */ - /** + + /** * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart() */ @Override @@ -125,21 +118,20 @@ public class BundleWebAppProvider extends AbstractWebAppProvider implements Bund _webappTracker = new WebAppTracker(FrameworkUtil.getBundle(this.getClass()).getBundleContext(), getServerInstanceWrapper().getManagedServerName()); _webappTracker.open(); //register as an osgi service for deploying bundles, advertising the name of the jetty Server instance we are related to - Dictionary properties = new Hashtable<>(); + Dictionary properties = new Hashtable<>(); properties.put(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME, getServerInstanceWrapper().getManagedServerName()); _serviceRegForBundles = FrameworkUtil.getBundle(this.getClass()).getBundleContext().registerService(BundleProvider.class.getName(), this, properties); super.doStart(); } - /* ------------------------------------------------------------ */ - /** + /** * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStop() */ @Override protected void doStop() throws Exception { _webappTracker.close(); - + //unregister ourselves if (_serviceRegForBundles != null) { @@ -152,22 +144,17 @@ public class BundleWebAppProvider extends AbstractWebAppProvider implements Bund LOG.warn(e); } } - + super.doStop(); } - - - - - - /* ------------------------------------------------------------ */ /** - * A bundle has been added that could be a webapp + * A bundle has been added that could be a webapp + * * @param bundle the bundle */ @Override - public boolean bundleAdded (Bundle bundle) throws Exception + public boolean bundleAdded(Bundle bundle) throws Exception { if (bundle == null) return false; @@ -175,10 +162,10 @@ public class BundleWebAppProvider extends AbstractWebAppProvider implements Bund ClassLoader cl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(getServerInstanceWrapper().getParentClassLoaderForWebapps()); String contextPath = null; - try + try { @SuppressWarnings("unchecked") - Dictionary headers = bundle.getHeaders(); + Dictionary headers = bundle.getHeaders(); //does the bundle have a OSGiWebappConstants.JETTY_WAR_FOLDER_PATH String resourcePath = Util.getManifestHeaderValue(OSGiWebappConstants.JETTY_WAR_FOLDER_PATH, OSGiWebappConstants.JETTY_WAR_RESOURCE_PATH, headers); @@ -187,7 +174,7 @@ public class BundleWebAppProvider extends AbstractWebAppProvider implements Bund String base = resourcePath; contextPath = getContextPath(bundle); String originId = getOriginId(bundle, base); - + //TODO : we don't know whether an app is actually deployed, as deploymentManager swallows all //exceptions inside the impl of addApp. Need to send the Event and also register as a service //only if the deployment succeeded @@ -199,19 +186,18 @@ public class BundleWebAppProvider extends AbstractWebAppProvider implements Bund return true; } - //does the bundle have a WEB-INF/web.xml if (bundle.getEntry("/WEB-INF/web.xml") != null) { String base = "."; contextPath = getContextPath(bundle); String originId = getOriginId(bundle, base); - + OSGiApp app = new OSGiApp(getDeploymentManager(), this, bundle, originId); app.setContextPath(contextPath); app.setWebAppPath(base); _bundleMap.put(bundle, app); - getDeploymentManager().addApp(app); + getDeploymentManager().addApp(app); return true; } @@ -221,13 +207,13 @@ public class BundleWebAppProvider extends AbstractWebAppProvider implements Bund //Could be a static webapp with no web.xml String base = "."; contextPath = headers.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH); - String originId = getOriginId(bundle,base); - + String originId = getOriginId(bundle, base); + OSGiApp app = new OSGiApp(getDeploymentManager(), this, bundle, originId); app.setContextPath(contextPath); app.setWebAppPath(base); _bundleMap.put(bundle, app); - getDeploymentManager().addApp(app); + getDeploymentManager().addApp(app); return true; } @@ -235,7 +221,7 @@ public class BundleWebAppProvider extends AbstractWebAppProvider implements Bund } catch (Exception e) { - + throw e; } finally @@ -244,35 +230,28 @@ public class BundleWebAppProvider extends AbstractWebAppProvider implements Bund } } - - /* ------------------------------------------------------------ */ - /** + /** * Bundle has been removed. If it was a webapp we deployed, undeploy it. - * + * * @param bundle the bundle * @return true if this was a webapp we had deployed, false otherwise */ @Override - public boolean bundleRemoved (Bundle bundle) throws Exception + public boolean bundleRemoved(Bundle bundle) throws Exception { App app = _bundleMap.remove(bundle); if (app != null) { - getDeploymentManager().removeApp(app); + getDeploymentManager().removeApp(app); return true; } return false; } - - - - - /* ------------------------------------------------------------ */ private static String getContextPath(Bundle bundle) { Dictionary headers = bundle.getHeaders(); - String contextPath = (String) headers.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH); + String contextPath = (String)headers.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH); if (contextPath == null) { // extract from the last token of the bundle's location: @@ -280,7 +259,7 @@ public class BundleWebAppProvider extends AbstractWebAppProvider implements Bund // the location will often reflect the version. // maybe this is relevant when the file is a war) String location = bundle.getLocation(); - String toks[] = location.replace('\\', '/').split("/"); + String[] toks = StringUtil.replace(location, '\\', '/').split("/"); contextPath = toks[toks.length - 1]; // remove .jar, .war etc: int lastDot = contextPath.lastIndexOf('.'); @@ -289,10 +268,7 @@ public class BundleWebAppProvider extends AbstractWebAppProvider implements Bund } if (!contextPath.startsWith("/")) contextPath = "/" + contextPath; - + return contextPath; } - - - } diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/JettyBootstrapActivator.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/JettyBootstrapActivator.java index d09d6301252..63140b189b3 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/JettyBootstrapActivator.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/JettyBootstrapActivator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -42,7 +42,7 @@ import org.osgi.util.tracker.ServiceTracker; public class JettyBootstrapActivator implements BundleActivator { private static final Logger LOG = Log.getLogger(JettyBootstrapActivator.class); - + private static JettyBootstrapActivator INSTANCE = null; public static JettyBootstrapActivator getInstance() @@ -51,30 +51,27 @@ public class JettyBootstrapActivator implements BundleActivator } private ServiceRegistration _registeredServer; - + private PackageAdminServiceTracker _packageAdminServiceTracker; private ServiceTracker _jettyServerServiceTracker; - - - - /* ------------------------------------------------------------ */ + /** * Setup a new jetty Server, registers it as a service. Setup the Service * tracker for the jetty ContextHandlers that are in charge of deploying the * webapps. Setup the BundleListener that supports the extender pattern for * the jetty ContextHandler. - * + * * @param context the bundle context */ @Override public void start(final BundleContext context) throws Exception { ServiceReference[] references = context.getAllServiceReferences("org.eclipse.jetty.http.HttpFieldPreEncoder", null); - - if (references == null || references.length==0) + + if (references == null || references.length == 0) LOG.warn("OSGi support for java.util.ServiceLoader may not be present. You may experience runtime errors."); - + INSTANCE = this; // track other bundles and fragments attached to this bundle that we @@ -84,19 +81,15 @@ public class JettyBootstrapActivator implements BundleActivator // track jetty Server instances that we should support as deployment targets _jettyServerServiceTracker = new ServiceTracker(context, context.createFilter("(objectclass=" + Server.class.getName() + ")"), new JettyServerServiceTracker()); _jettyServerServiceTracker.open(); - + // Create a default jetty instance right now. DefaultJettyAtJettyHomeHelper.startJettyAtJettyHome(context); } - - - /* ------------------------------------------------------------ */ /** * Stop the activator. - * - * @see - * org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) + * + * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) */ @Override public void stop(BundleContext context) throws Exception diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiDeployer.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiDeployer.java index 06f636ec675..ac6161d7302 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiDeployer.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiDeployer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -24,27 +24,22 @@ import org.eclipse.jetty.deploy.graph.Node; import org.eclipse.jetty.osgi.boot.internal.serverfactory.ServerInstanceWrapper; import org.eclipse.jetty.osgi.boot.utils.EventSender; - /** * OSGiDeployer * - * Extension of standard Jetty deployer that emits OSGi EventAdmin + * Extension of standard Jetty deployer that emits OSGi EventAdmin * events whenever a webapp is deployed into OSGi via Jetty. - * */ public class OSGiDeployer extends StandardDeployer { - + private ServerInstanceWrapper _server; - /* ------------------------------------------------------------ */ - public OSGiDeployer (ServerInstanceWrapper server) + public OSGiDeployer(ServerInstanceWrapper server) { - _server = server; + _server = server; } - - - /* ------------------------------------------------------------ */ + @Override public void processBinding(Node node, App app) throws Exception { @@ -52,36 +47,34 @@ public class OSGiDeployer extends StandardDeployer //OSGi Enterprise Spec only wants an event sent if its a webapp bundle (ie not a ContextHandler) if (!(app instanceof AbstractOSGiApp)) { - doProcessBinding(node,app); + doProcessBinding(node, app); } else { EventSender.getInstance().send(EventSender.DEPLOYING_EVENT, ((AbstractOSGiApp)app).getBundle(), app.getContextPath()); try { - doProcessBinding(node,app); + doProcessBinding(node, app); ((AbstractOSGiApp)app).registerAsOSGiService(); EventSender.getInstance().send(EventSender.DEPLOYED_EVENT, ((AbstractOSGiApp)app).getBundle(), app.getContextPath()); } catch (Exception e) { - EventSender.getInstance().send(EventSender.FAILED_EVENT, ((AbstractOSGiApp)app).getBundle(), app.getContextPath()); + EventSender.getInstance().send(EventSender.FAILED_EVENT, ((AbstractOSGiApp)app).getBundle(), app.getContextPath()); throw e; } } } - - - /* ------------------------------------------------------------ */ - protected void doProcessBinding (Node node, App app) throws Exception + + protected void doProcessBinding(Node node, App app) throws Exception { ClassLoader old = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(_server.getParentClassLoaderForWebapps()); try { - super.processBinding(node,app); + super.processBinding(node, app); } - finally + finally { Thread.currentThread().setContextClassLoader(old); } diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiServerConstants.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiServerConstants.java index 616ae707000..3795396fd8a 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiServerConstants.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiServerConstants.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,7 +20,7 @@ package org.eclipse.jetty.osgi.boot; /** * OSGiServerConstants - * + * * Name of the properties that configure a jetty Server OSGi service. */ public class OSGiServerConstants @@ -62,7 +62,7 @@ public class OSGiServerConstants * PID of the jetty servers's ManagedFactory */ public static final String MANAGED_JETTY_SERVER_FACTORY_PID = "org.eclipse.jetty.osgi.boot.managedserverfactory"; - + /** * The associated value of that configuration parameter is the name under which this * instance of the jetty server is tracked. @@ -75,12 +75,12 @@ public class OSGiServerConstants * Usually the first one to be created. */ public static final String MANAGED_JETTY_SERVER_DEFAULT_NAME = "defaultJettyServer"; - + /** * List of URLs to the jetty.xml files that configure th server. */ public static final String MANAGED_JETTY_XML_CONFIG_URLS = "jetty.etc.config.urls"; - + /** * List of URLs to the folders where the legacy J2EE shared libraries are stored aka lib/ext, lib/jsp etc. */ diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiUndeployer.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiUndeployer.java index 364a25d0a23..90fc0daf06a 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiUndeployer.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiUndeployer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -24,29 +24,21 @@ import org.eclipse.jetty.deploy.graph.Node; import org.eclipse.jetty.osgi.boot.internal.serverfactory.ServerInstanceWrapper; import org.eclipse.jetty.osgi.boot.utils.EventSender; - - - /** * OSGiUndeployer * * Extension of the Jetty Undeployer which emits OSGi EventAdmin events * whenever a webapp is undeployed from Jetty. - * */ public class OSGiUndeployer extends StandardUndeployer { private ServerInstanceWrapper _server; - - /* ------------------------------------------------------------ */ - public OSGiUndeployer (ServerInstanceWrapper server) + public OSGiUndeployer(ServerInstanceWrapper server) { _server = server; } - - - /* ------------------------------------------------------------ */ + @Override public void processBinding(Node node, App app) throws Exception { @@ -55,9 +47,9 @@ public class OSGiUndeployer extends StandardUndeployer Thread.currentThread().setContextClassLoader(_server.getParentClassLoaderForWebapps()); try { - super.processBinding(node,app); + super.processBinding(node, app); } - finally + finally { Thread.currentThread().setContextClassLoader(old); } diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiWebInfConfiguration.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiWebInfConfiguration.java index 44301b47f5b..cc1c73a8e5a 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiWebInfConfiguration.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiWebInfConfiguration.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -35,6 +35,7 @@ import java.util.regex.Pattern; import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelperFactory; import org.eclipse.jetty.osgi.boot.utils.Util; import org.eclipse.jetty.osgi.boot.utils.internal.PackageAdminServiceTracker; +import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.resource.Resource; @@ -44,17 +45,15 @@ import org.eclipse.jetty.webapp.WebInfConfiguration; import org.osgi.framework.Bundle; import org.osgi.framework.FrameworkUtil; - - /** * OSGiWebInfConfiguration * - * Handle adding resources found in bundle fragments, and add them into the + * Handle adding resources found in bundle fragments, and add them into the */ public class OSGiWebInfConfiguration extends WebInfConfiguration { private static final Logger LOG = Log.getLogger(WebInfConfiguration.class); - + /** * Comma separated list of symbolic names of bundles that contain tlds that should be considered * as on the container classpath @@ -66,48 +65,48 @@ public class OSGiWebInfConfiguration extends WebInfConfiguration public static final String CONTAINER_BUNDLE_PATTERN = "org.eclipse.jetty.server.webapp.containerIncludeBundlePattern"; public static final String FRAGMENT_AND_REQUIRED_BUNDLES = "org.eclipse.jetty.osgi.fragmentAndRequiredBundles"; public static final String FRAGMENT_AND_REQUIRED_RESOURCES = "org.eclipse.jetty.osgi.fragmentAndRequiredResources"; - - - /* ------------------------------------------------------------ */ - /** + + /** * Check to see if there have been any bundle symbolic names added of bundles that should be * regarded as being on the container classpath, and scanned for fragments, tlds etc etc. * This can be defined in: *
          - *
        1. SystemProperty SYS_PROP_TLD_BUNDLES
        2. - *
        3. DeployerManager.setContextAttribute CONTAINER_BUNDLE_PATTERN
        4. - *
        - * - * We also allow individual bundles to specify particular bundles that might include TLDs via the Require-Tlds - * MANIFEST.MF header. - * + *
      5. SystemProperty SYS_PROP_TLD_BUNDLES
      6. + *
      7. DeployerManager.setContextAttribute CONTAINER_BUNDLE_PATTERN
      8. + * + * + * We also allow individual bundles to specify particular bundles that might include TLDs via the Require-Tlds + * MANIFEST.MF header. + * * @see org.eclipse.jetty.webapp.WebInfConfiguration#preConfigure(org.eclipse.jetty.webapp.WebAppContext) */ @Override public void preConfigure(final WebAppContext context) throws Exception { super.preConfigure(context); - + //Check to see if there have been any bundle symbolic names added of bundles that should be //regarded as being on the container classpath, and scanned for fragments, tlds etc etc. //This can be defined in: // 1. SystemProperty SYS_PROP_TLD_BUNDLES // 2. DeployerManager.setContextAttribute CONTAINER_BUNDLE_PATTERN String tmp = (String)context.getAttribute(CONTAINER_BUNDLE_PATTERN); - Pattern pattern = (tmp==null?null:Pattern.compile(tmp)); + Pattern pattern = (tmp == null ? null : Pattern.compile(tmp)); List names = new ArrayList<>(); tmp = System.getProperty(SYS_PROP_TLD_BUNDLES); if (tmp != null) { StringTokenizer tokenizer = new StringTokenizer(tmp, ", \n\r\t", false); while (tokenizer.hasMoreTokens()) + { names.add(tokenizer.nextToken()); + } } HashSet matchingResources = new HashSet<>(); - if ( !names.isEmpty() || pattern != null) + if (!names.isEmpty() || pattern != null) { Bundle[] bundles = FrameworkUtil.getBundle(OSGiWebInfConfiguration.class).getBundleContext().getBundles(); - + for (Bundle bundle : bundles) { LOG.debug("Checking bundle {}:{}", bundle.getBundleId(), bundle.getSymbolicName()); @@ -119,7 +118,7 @@ public class OSGiWebInfConfiguration extends WebInfConfiguration //get the file location of the jar and put it into the list of container jars that will be scanned for stuff (including tlds) matchingResources.addAll(getBundleAsResource(bundle)); } - } + } if (names != null) { //if there is an explicit bundle name, then check if it matches @@ -127,38 +126,36 @@ public class OSGiWebInfConfiguration extends WebInfConfiguration matchingResources.addAll(getBundleAsResource(bundle)); } } - } - for (Resource r:matchingResources) + } + for (Resource r : matchingResources) { context.getMetaData().addContainerResource(r); } } - + @Override public void postConfigure(WebAppContext context) throws Exception { - context.setAttribute(FRAGMENT_AND_REQUIRED_BUNDLES, null); + context.setAttribute(FRAGMENT_AND_REQUIRED_BUNDLES, null); context.setAttribute(FRAGMENT_AND_REQUIRED_RESOURCES, null); super.postConfigure(context); } - - /* ------------------------------------------------------------ */ - /** + + /** * Consider the fragment bundles associated with the bundle of the webapp being deployed. - * - * + * * @see org.eclipse.jetty.webapp.WebInfConfiguration#findJars(org.eclipse.jetty.webapp.WebAppContext) */ @Override - protected List findJars (WebAppContext context) - throws Exception + protected List findJars(WebAppContext context) + throws Exception { List mergedResources = new ArrayList<>(); //get jars from WEB-INF/lib if there are any List webInfJars = super.findJars(context); if (webInfJars != null) mergedResources.addAll(webInfJars); - + //add fragment jars and any Required-Bundles as if in WEB-INF/lib of the associated webapp Bundle[] bundles = PackageAdminServiceTracker.INSTANCE.getFragmentsAndRequiredBundles((Bundle)context.getAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE)); if (bundles != null && bundles.length > 0) @@ -170,7 +167,7 @@ public class OSGiWebInfConfiguration extends WebInfConfiguration fragsAndReqsBundles = new HashSet<>(); context.setAttribute(FRAGMENT_AND_REQUIRED_BUNDLES, fragsAndReqsBundles); } - + @SuppressWarnings("unchecked") Set fragsAndReqsResources = (Set)context.getAttribute(FRAGMENT_AND_REQUIRED_RESOURCES); if (fragsAndReqsResources == null) @@ -178,13 +175,13 @@ public class OSGiWebInfConfiguration extends WebInfConfiguration fragsAndReqsResources = new HashSet<>(); context.setAttribute(FRAGMENT_AND_REQUIRED_RESOURCES, fragsAndReqsResources); } - + for (Bundle b : bundles) { //skip bundles that are not installed if (b.getState() == Bundle.UNINSTALLED) continue; - + //add to context attribute storing associated fragments and required bundles fragsAndReqsBundles.add(b); File f = BundleFileLocatorHelperFactory.getFactory().getHelper().getBundleInstallLocation(b); @@ -194,16 +191,15 @@ public class OSGiWebInfConfiguration extends WebInfConfiguration mergedResources.add(r); } } - + return mergedResources; } - - /* ------------------------------------------------------------ */ - /** + + /** * Allow fragments to supply some resources that are added to the baseResource of the webapp. - * + * * The resources can be either prepended or appended to the baseResource. - * + * * @see org.eclipse.jetty.webapp.WebInfConfiguration#configure(org.eclipse.jetty.webapp.WebAppContext) */ @Override @@ -211,7 +207,7 @@ public class OSGiWebInfConfiguration extends WebInfConfiguration { TreeMap prependedResourcesPath = new TreeMap<>(); TreeMap appendedResourcesPath = new TreeMap<>(); - + Bundle bundle = (Bundle)context.getAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE); if (bundle != null) { @@ -234,7 +230,7 @@ public class OSGiWebInfConfiguration extends WebInfConfiguration // looked up. for (Bundle frag : fragments) { - String path = Util.getManifestHeaderValue(OSGiWebappConstants.JETTY_WAR_FRAGMENT_FOLDER_PATH,OSGiWebappConstants.JETTY_WAR_FRAGMENT_RESOURCE_PATH,frag.getHeaders()); + String path = Util.getManifestHeaderValue(OSGiWebappConstants.JETTY_WAR_FRAGMENT_FOLDER_PATH, OSGiWebappConstants.JETTY_WAR_FRAGMENT_RESOURCE_PATH, frag.getHeaders()); convertFragmentPathToResource(path, frag, appendedResourcesPath); path = Util.getManifestHeaderValue(OSGiWebappConstants.JETTY_WAR_PATCH_FRAGMENT_FOLDER_PATH, OSGiWebappConstants.JETTY_WAR_PREPEND_FRAGMENT_RESOURCE_PATH, frag.getHeaders()); convertFragmentPathToResource(path, frag, prependedResourcesPath); @@ -249,32 +245,30 @@ public class OSGiWebInfConfiguration extends WebInfConfiguration resources.addAll(resourceDirs); //Then append the values from JETTY_WAR_FRAGMENT_FOLDER_PATH resources.addAll(appendedResourcesPath.values()); - + context.setAttribute(WebInfConfiguration.RESOURCE_DIRS, resources); } } } - + super.configure(context); // place the prepended resources at the beginning of the contexts's resource base if (!prependedResourcesPath.isEmpty()) { - Resource[] resources = new Resource[1+prependedResourcesPath.size()]; + Resource[] resources = new Resource[1 + prependedResourcesPath.size()]; System.arraycopy(prependedResourcesPath.values().toArray(new Resource[prependedResourcesPath.size()]), 0, resources, 0, prependedResourcesPath.size()); - resources[resources.length-1] = context.getBaseResource(); + resources[resources.length - 1] = context.getBaseResource(); context.setBaseResource(new ResourceCollection(resources)); } } - - /* ------------------------------------------------------------ */ /** - * Resolves the bundle. Usually that would be a single URL per bundle. But we do some more work if there are jars - * embedded in the bundle. - */ - private List getBundleAsResource(Bundle bundle) - throws Exception + * Resolves the bundle. Usually that would be a single URL per bundle. But we do some more work if there are jars + * embedded in the bundle. + */ + private List getBundleAsResource(Bundle bundle) + throws Exception { List resources = new ArrayList<>(); @@ -304,42 +298,33 @@ public class OSGiWebInfConfiguration extends WebInfConfiguration { resources.add(Resource.newResource(file)); } - + return resources; } - /** * Convert a path inside a fragment into a Resource - * @param resourcePath - * @param fragment - * @param resourceMap - * @throws Exception */ - private void convertFragmentPathToResource (String resourcePath, Bundle fragment, Map resourceMap ) - throws Exception + private void convertFragmentPathToResource(String resourcePath, Bundle fragment, Map resourceMap) + throws Exception { if (resourcePath == null) return; URL url = fragment.getEntry(resourcePath); - if (url == null) - { - throw new IllegalArgumentException("Unable to locate " + resourcePath - + " inside " - + " the fragment '" - + fragment.getSymbolicName() - + "'"); + if (url == null) + { + throw new IllegalArgumentException("Unable to locate " + resourcePath + " inside the fragment '" + fragment.getSymbolicName() + "'"); } url = BundleFileLocatorHelperFactory.getFactory().getHelper().getLocalURL(url); URI uri; try { - uri = url.toURI(); + uri = url.toURI(); } catch (URISyntaxException e) { - uri = new URI(url.toString().replaceAll(" ", "%20")); + uri = new URI(URIUtil.encodeSpaces(url.toString())); } String key = resourcePath.startsWith("/") ? resourcePath.substring(1) : resourcePath; resourceMap.put(key + ";" + fragment.getSymbolicName(), Resource.newResource(uri)); diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiWebappConstants.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiWebappConstants.java index 8a2ff37a7e0..0bdaf31a18f 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiWebappConstants.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiWebappConstants.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,29 +20,36 @@ package org.eclipse.jetty.osgi.boot; /** * OSGiWebappConstants - * - * + * + * * Constants (MANIFEST headers, service properties etc) associated with deploying * webapps into OSGi via Jetty. - * */ public class OSGiWebappConstants { - /** service property osgi.web.symbolicname. See OSGi r4 */ + /** + * service property osgi.web.symbolicname. See OSGi r4 + */ public static final String OSGI_WEB_SYMBOLICNAME = "osgi.web.symbolicname"; - - /** service property osgi.web.symbolicname. See OSGi r4 */ + + /** + * service property osgi.web.symbolicname. See OSGi r4 + */ public static final String OSGI_WEB_VERSION = "osgi.web.version"; - - /** service property osgi.web.contextpath. See OSGi r4 */ + + /** + * service property osgi.web.contextpath. See OSGi r4 + */ public static final String OSGI_WEB_CONTEXTPATH = "osgi.web.contextpath"; - - /** See OSGi r4 p.427 */ + + /** + * See OSGi r4 p.427 + */ public static final String OSGI_BUNDLECONTEXT = "osgi-bundlecontext"; - - - /** url scheme to deploy war file as bundled webapp */ + /** + * url scheme to deploy war file as bundled webapp + */ public static final String RFC66_WAR_URL_SCHEME = "war"; /** @@ -56,93 +63,109 @@ public class OSGiWebappConstants */ public static final String RFC66_JSP_EXTRACT_LOCATION = "Jsp-ExtractLocation"; - /** Name of the servlet context attribute that points to the bundle context. */ + /** + * Name of the servlet context attribute that points to the bundle context. + */ public static final String RFC66_OSGI_BUNDLE_CONTEXT = "osgi-bundlecontext"; - /** Name of the servlet context attribute that points to the bundle object. - * We can't always rely on the bundle-context as there might be no such thing. */ + /** + * Name of the servlet context attribute that points to the bundle object. + * We can't always rely on the bundle-context as there might be no such thing. + */ public static final String JETTY_OSGI_BUNDLE = "osgi-bundle"; - /** List of relative pathes within the bundle to the jetty context files. */ + /** + * List of relative pathes within the bundle to the jetty context files. + */ public static final String JETTY_CONTEXT_FILE_PATH = "Jetty-ContextFilePath"; - /** path within the bundle to the folder that contains the basic resources. */ + /** + * path within the bundle to the folder that contains the basic resources. + */ @Deprecated public static final String JETTY_WAR_FOLDER_PATH = "Jetty-WarFolderPath"; public static final String JETTY_WAR_RESOURCE_PATH = "Jetty-WarResourcePath"; - /** path within a fragment hosted by a web-bundle to a folder that contains basic resources. - * the path is appended to the lookup path where jetty locates static resources */ + /** + * path within a fragment hosted by a web-bundle to a folder that contains basic resources. + * the path is appended to the lookup path where jetty locates static resources + */ @Deprecated public static final String JETTY_WAR_FRAGMENT_FOLDER_PATH = "Jetty-WarFragmentFolderPath"; public static final String JETTY_WAR_FRAGMENT_RESOURCE_PATH = "Jetty-WarFragmentResourcePath"; - - /** path within a fragment hosted by a web-bundle to a folder that contains basic resources. + /** + * path within a fragment hosted by a web-bundle to a folder that contains basic resources. * The path is prefixed to the lookup path where jetty locates static resources: - * this will override static resources with the same name in the web-bundle. */ + * this will override static resources with the same name in the web-bundle. + */ @Deprecated public static final String JETTY_WAR_PATCH_FRAGMENT_FOLDER_PATH = "Jetty-WarPatchFragmentFolderPath"; public static final String JETTY_WAR_PREPEND_FRAGMENT_RESOURCE_PATH = "Jetty-WarPrependFragmentResourcePath"; - - /** installation path of webapp bundle - * + /** + * installation path of webapp bundle */ public static final String JETTY_BUNDLE_ROOT = "bundle.root"; - /** - * web app context path + /** + * web app context path + * * @deprecated see RFC66_WEB_CONTEXTPATH */ public static final String SERVICE_PROP_CONTEXT_PATH = "contextPath"; - - /** - * Path to the web application base folder + /** + * Path to the web application base folder + * * @deprecated see JETTY_WAR_FOLDER_PATH */ public static final String SERVICE_PROP_WAR = "war"; - /** + /** * Extra classpath - * @deprecated see JETTY_EXTRA_CLASSPATH + * + * @deprecated see JETTY_EXTRA_CLASSPATH */ public static final String SERVICE_PROP_EXTRA_CLASSPATH = "extraClasspath"; - + public static final String JETTY_EXTRA_CLASSPATH = "Jetty-extraClasspath"; - /** - * jetty context file path + /** + * jetty context file path + * * @deprecated see JETTY_CONTEXT_FILE_PATH */ public static final String SERVICE_PROP_CONTEXT_FILE_PATH = "contextFilePath"; - /** - * web.xml file path + /** + * web.xml file path + * * @deprecated see JETTY_WEB_XML_PATH */ public static final String SERVICE_PROP_WEB_XML_PATH = "webXmlFilePath"; - + public static final String JETTY_WEB_XML_PATH = "Jetty-WebXmlFilePath"; - /** - * defaultweb.xml file path + /** + * defaultweb.xml file path + * * @deprecated see JETTY_DEFAULT_WEB_XML_PATH */ public static final String SERVICE_PROP_DEFAULT_WEB_XML_PATH = "defaultWebXmlFilePath"; - + public static final String JETTY_DEFAULT_WEB_XML_PATH = "Jetty-defaultWebXmlFilePath"; /** * path to the base folder that overrides the computed bundle installation * location if not null useful to install webapps or jetty context files * that are in fact not embedded in a bundle + * * @deprecated see JETTY_BUNDLE_INSTALL_LOCATION_OVERRIDE */ public static final String SERVICE_PROP_BUNDLE_INSTALL_LOCATION_OVERRIDE = "thisBundleInstall"; - + public static final String JETTY_BUNDLE_INSTALL_LOCATION_OVERRIDE = "Jetty-bundleInstall"; - + /** * Comma separated list of bundles that contain tld file used by the webapp. */ @@ -152,14 +175,11 @@ public class OSGiWebappConstants * Both the name of the manifest header and the name of the service property. */ public static final String SERVICE_PROP_REQUIRE_TLD_BUNDLE = REQUIRE_TLD_BUNDLE; - + public static final String WATERMARK = "o.e.j.o.b.watermark"; - + /** * Set of extra dirs that must not be served by osgi webapps */ public static final String[] DEFAULT_PROTECTED_OSGI_TARGETS = {"/osgi-inf", "/osgi-opts"}; - - - } diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/ServiceContextProvider.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/ServiceContextProvider.java index b870188db6c..8697d21d9e5 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/ServiceContextProvider.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/ServiceContextProvider.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -44,55 +44,50 @@ import org.osgi.util.tracker.ServiceTracker; * ServiceContextProvider * * Jetty DeploymentManager Provider that is able to deploy ContextHandlers discovered via OSGi as services. - * - * */ public class ServiceContextProvider extends AbstractContextProvider implements ServiceProvider -{ +{ private static final Logger LOG = Log.getLogger(AbstractContextProvider.class); - + private Map _serviceMap = new HashMap<>(); - + private ServiceRegistration _serviceRegForServices; - + ServiceTracker _tracker; - - + /** * ContextTracker - * - * */ public class ContextTracker extends ServiceTracker { - - public ContextTracker (BundleContext bundleContext, Filter filter) + + public ContextTracker(BundleContext bundleContext, Filter filter) { super(bundleContext, filter, null); } - /** + /** * @see org.osgi.util.tracker.ServiceTracker#addingService(org.osgi.framework.ServiceReference) */ @Override public Object addingService(ServiceReference reference) { ContextHandler h = (ContextHandler)context.getService(reference); - serviceAdded (reference, h); + serviceAdded(reference, h); return h; } - /** + /** * @see org.osgi.util.tracker.ServiceTracker#modifiedService(org.osgi.framework.ServiceReference, java.lang.Object) */ @Override public void modifiedService(ServiceReference reference, Object service) { - removedService(reference,service); + removedService(reference, service); addingService(reference); } - /** + /** * @see org.osgi.util.tracker.ServiceTracker#removedService(org.osgi.framework.ServiceReference, java.lang.Object) */ @Override @@ -102,13 +97,9 @@ public class ServiceContextProvider extends AbstractContextProvider implements S serviceRemoved(reference, (ContextHandler)service); } } - - - + /** * ServiceApp - * - * */ public class ServiceApp extends OSGiApp { @@ -134,30 +125,25 @@ public class ServiceContextProvider extends AbstractContextProvider implements S //not applicable for apps that are already services } } - - - - /* ------------------------------------------------------------ */ + public ServiceContextProvider(ServerInstanceWrapper wrapper) { super(wrapper); } - - - /* ------------------------------------------------------------ */ + @Override - public boolean serviceAdded (ServiceReference serviceRef, ContextHandler context) + public boolean serviceAdded(ServiceReference serviceRef, ContextHandler context) { if (context == null || serviceRef == null) return false; - + if (context instanceof org.eclipse.jetty.webapp.WebAppContext) return false; //the ServiceWebAppProvider will deploy it - + String watermark = (String)serviceRef.getProperty(OSGiWebappConstants.WATERMARK); if (watermark != null && !"".equals(watermark)) return false; //this service represents a contexthandler that has already been registered as a service by another of our deployers - + ClassLoader cl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(getServerInstanceWrapper().getParentClassLoaderForWebapps()); try @@ -165,18 +151,20 @@ public class ServiceContextProvider extends AbstractContextProvider implements S //See if there is a context file to apply to this pre-made context String contextFile = (String)serviceRef.getProperty(OSGiWebappConstants.JETTY_CONTEXT_FILE_PATH); if (contextFile == null) - contextFile = (String)serviceRef.getProperty(OSGiWebappConstants.SERVICE_PROP_CONTEXT_FILE_PATH); - + contextFile = (String)serviceRef.getProperty(OSGiWebappConstants.SERVICE_PROP_CONTEXT_FILE_PATH); + String[] keys = serviceRef.getPropertyKeys(); - Dictionary properties = new Hashtable<>(); + Dictionary properties = new Hashtable<>(); if (keys != null) { - for (String key:keys) + for (String key : keys) + { properties.put(key, serviceRef.getProperty(key)); + } } - Bundle bundle = serviceRef.getBundle(); - String originId = bundle.getSymbolicName() + "-" + bundle.getVersion().toString() + "-"+(contextFile!=null?contextFile:serviceRef.getProperty(Constants.SERVICE_ID)); - ServiceApp app = new ServiceApp(getDeploymentManager(), this, bundle, properties, contextFile, originId); + Bundle bundle = serviceRef.getBundle(); + String originId = bundle.getSymbolicName() + "-" + bundle.getVersion().toString() + "-" + (contextFile != null ? contextFile : serviceRef.getProperty(Constants.SERVICE_ID)); + ServiceApp app = new ServiceApp(getDeploymentManager(), this, bundle, properties, contextFile, originId); app.setHandler(context); //set the pre=made ContextHandler instance _serviceMap.put(serviceRef, app); getDeploymentManager().addApp(app); @@ -184,23 +172,21 @@ public class ServiceContextProvider extends AbstractContextProvider implements S } finally { - Thread.currentThread().setContextClassLoader(cl); + Thread.currentThread().setContextClassLoader(cl); } } - - - /* ------------------------------------------------------------ */ + @Override - public boolean serviceRemoved (ServiceReference serviceRef, ContextHandler context) + public boolean serviceRemoved(ServiceReference serviceRef, ContextHandler context) { if (context == null || serviceRef == null) return false; - + String watermark = (String)serviceRef.getProperty(OSGiWebappConstants.WATERMARK); if (watermark != null && !"".equals(watermark)) return false; //this service represents a contexthandler that will be deregistered as a service by another of our deployers - + App app = _serviceMap.remove(serviceRef); if (app != null) { @@ -210,10 +196,7 @@ public class ServiceContextProvider extends AbstractContextProvider implements S return false; } - - - - /* ------------------------------------------------------------ */ + @Override protected void doStart() throws Exception { @@ -221,27 +204,25 @@ public class ServiceContextProvider extends AbstractContextProvider implements S BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext(); //Start a tracker to find webapps that are osgi services that are targeted to my server name - _tracker = new ContextTracker (bundleContext, - Util.createFilter(bundleContext, ContextHandler.class.getName(), getServerInstanceWrapper().getManagedServerName())); + _tracker = new ContextTracker(bundleContext, + Util.createFilter(bundleContext, ContextHandler.class.getName(), getServerInstanceWrapper().getManagedServerName())); _tracker.open(); - //register as an osgi service for deploying contexts defined in a bundle, advertising the name of the jetty Server instance we are related to - Dictionary properties = new Hashtable<>(); + Dictionary properties = new Hashtable<>(); properties.put(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME, getServerInstanceWrapper().getManagedServerName()); - + //register as an osgi service for deploying contexts, advertising the name of the jetty Server instance we are related to _serviceRegForServices = FrameworkUtil.getBundle(this.getClass()).getBundleContext().registerService(ServiceProvider.class.getName(), this, properties); super.doStart(); } - - /* ------------------------------------------------------------ */ + @Override protected void doStop() throws Exception { if (_tracker != null) _tracker.close(); - + //unregister ourselves if (_serviceRegForServices != null) { diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/ServiceProvider.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/ServiceProvider.java index 0bbb382c3d6..afe677608ab 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/ServiceProvider.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/ServiceProvider.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -28,7 +28,7 @@ import org.osgi.framework.ServiceReference; */ public interface ServiceProvider { - public boolean serviceAdded (ServiceReference ref, ContextHandler handler) throws Exception; - - public boolean serviceRemoved (ServiceReference ref, ContextHandler handler) throws Exception; + boolean serviceAdded(ServiceReference ref, ContextHandler handler) throws Exception; + + boolean serviceRemoved(ServiceReference ref, ContextHandler handler) throws Exception; } diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/ServiceWebAppProvider.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/ServiceWebAppProvider.java index abb95eb9216..e1a14637882 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/ServiceWebAppProvider.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/ServiceWebAppProvider.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -46,23 +46,20 @@ import org.osgi.util.tracker.ServiceTracker; * Jetty Provider that knows how to deploy a WebApp that has been registered as an OSGi service. */ public class ServiceWebAppProvider extends AbstractWebAppProvider implements ServiceProvider -{ +{ private static final Logger LOG = Log.getLogger(AbstractWebAppProvider.class); - + /** * Map of ServiceRef to App. Used when it is an osgi service that is a WebAppContext. */ private Map _serviceMap = new HashMap<>(); - + private ServiceRegistration _serviceRegForServices; - + private ServiceTracker webappTracker; - /** * WebAppTracker - * - * */ public class WebAppTracker extends ServiceTracker { @@ -70,33 +67,33 @@ public class ServiceWebAppProvider extends AbstractWebAppProvider implements Ser * @param bundleContext the osgi context * @param filter the osgi filter for the tracker */ - public WebAppTracker (BundleContext bundleContext, Filter filter) + public WebAppTracker(BundleContext bundleContext, Filter filter) { super(bundleContext, filter, null); } - /** + /** * @see org.osgi.util.tracker.ServiceTracker#addingService(org.osgi.framework.ServiceReference) */ @Override public Object addingService(ServiceReference reference) { WebAppContext wac = (WebAppContext)context.getService(reference); - serviceAdded (reference, wac); + serviceAdded(reference, wac); return wac; } - /** + /** * @see org.osgi.util.tracker.ServiceTracker#modifiedService(org.osgi.framework.ServiceReference, java.lang.Object) */ @Override public void modifiedService(ServiceReference reference, Object service) { - removedService(reference,service); + removedService(reference, service); addingService(reference); } - /** + /** * @see org.osgi.util.tracker.ServiceTracker#removedService(org.osgi.framework.ServiceReference, java.lang.Object) */ @Override @@ -106,17 +103,14 @@ public class ServiceWebAppProvider extends AbstractWebAppProvider implements Ser context.ungetService(reference); } } - - + /** * ServiceApp - * - * */ public class ServiceApp extends OSGiApp { - public ServiceApp(DeploymentManager manager, AppProvider provider, Bundle bundle, Dictionary properties, String originId) + public ServiceApp(DeploymentManager manager, AppProvider provider, Bundle bundle, Dictionary properties, String originId) { super(manager, provider, bundle, properties, originId); } @@ -138,52 +132,46 @@ public class ServiceWebAppProvider extends AbstractWebAppProvider implements Ser //not applicable for apps that are already services } } - - - - /* ------------------------------------------------------------ */ - public ServiceWebAppProvider (ServerInstanceWrapper wrapper) + + public ServiceWebAppProvider(ServerInstanceWrapper wrapper) { super(wrapper); } - - - /* ------------------------------------------------------------ */ + /** * A webapp that was deployed as an osgi service has been added, * and we want to deploy it. - * + * * @param context the webapp */ @Override - public boolean serviceAdded (ServiceReference serviceRef, ContextHandler context) - { + public boolean serviceAdded(ServiceReference serviceRef, ContextHandler context) + { if (context == null || !(context instanceof WebAppContext)) return false; - + String watermark = (String)serviceRef.getProperty(OSGiWebappConstants.WATERMARK); if (watermark != null && !"".equals(watermark)) return false; //this service represents a webapp that has already been registered as a service by another of our deployers - - + WebAppContext webApp = (WebAppContext)context; - Dictionary properties = new Hashtable<>(); - + Dictionary properties = new Hashtable<>(); + String contextPath = (String)serviceRef.getProperty(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH); if (contextPath == null) contextPath = (String)serviceRef.getProperty(OSGiWebappConstants.SERVICE_PROP_CONTEXT_PATH); if (contextPath == null) return false; //No context path - + String base = (String)serviceRef.getProperty(OSGiWebappConstants.JETTY_WAR_FOLDER_PATH); if (base == null) base = (String)serviceRef.getProperty(OSGiWebappConstants.JETTY_WAR_RESOURCE_PATH); if (base == null) base = (String)serviceRef.getProperty(OSGiWebappConstants.SERVICE_PROP_WAR); - - if (base == null) - return false; //No webapp base - + + if (base == null) + return false; //No webapp base + String webdefaultXml = (String)serviceRef.getProperty(OSGiWebappConstants.JETTY_DEFAULT_WEB_XML_PATH); if (webdefaultXml == null) webdefaultXml = (String)serviceRef.getProperty(OSGiWebappConstants.SERVICE_PROP_DEFAULT_WEB_XML_PATH); @@ -208,7 +196,7 @@ public class ServiceWebAppProvider extends AbstractWebAppProvider implements Ser if (bundleInstallOverride != null) properties.put(OSGiWebappConstants.JETTY_BUNDLE_INSTALL_LOCATION_OVERRIDE, bundleInstallOverride); - String requiredTlds = (String)serviceRef.getProperty(OSGiWebappConstants.REQUIRE_TLD_BUNDLE); + String requiredTlds = (String)serviceRef.getProperty(OSGiWebappConstants.REQUIRE_TLD_BUNDLE); if (requiredTlds == null) requiredTlds = (String)serviceRef.getProperty(OSGiWebappConstants.SERVICE_PROP_REQUIRE_TLD_BUNDLE); if (requiredTlds != null) @@ -229,26 +217,23 @@ public class ServiceWebAppProvider extends AbstractWebAppProvider implements Ser } finally { - Thread.currentThread().setContextClassLoader(cl); + Thread.currentThread().setContextClassLoader(cl); } } - - - - /* ------------------------------------------------------------ */ + /** * @param context the webapp */ @Override - public boolean serviceRemoved (ServiceReference serviceRef, ContextHandler context) + public boolean serviceRemoved(ServiceReference serviceRef, ContextHandler context) { if (context == null || !(context instanceof WebAppContext)) return false; - + String watermark = (String)serviceRef.getProperty(OSGiWebappConstants.WATERMARK); if (watermark != null && !"".equals(watermark)) return false; //this service represents a contexthandler that will be deregistered as a service by another of our deployers - + App app = _serviceMap.remove(serviceRef); if (app != null) { @@ -257,10 +242,8 @@ public class ServiceWebAppProvider extends AbstractWebAppProvider implements Ser } return false; } - - - /* ------------------------------------------------------------ */ - /** + + /** * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart() */ @Override @@ -269,28 +252,27 @@ public class ServiceWebAppProvider extends AbstractWebAppProvider implements Ser BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext(); //Start a tracker to find webapps that are osgi services that are targeted to my server name - webappTracker = new WebAppTracker (bundleContext, - Util.createFilter(bundleContext, WebAppContext.class.getName(), getServerInstanceWrapper().getManagedServerName())); + webappTracker = new WebAppTracker(bundleContext, + Util.createFilter(bundleContext, WebAppContext.class.getName(), getServerInstanceWrapper().getManagedServerName())); webappTracker.open(); - + //register as an osgi service for deploying bundles, advertising the name of the jetty Server instance we are related to - Dictionary properties = new Hashtable<>(); + Dictionary properties = new Hashtable<>(); properties.put(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME, getServerInstanceWrapper().getManagedServerName()); - + //register as an osgi service for deploying contexts (discovered as osgi services), advertising the name of the jetty Server instance we are related to _serviceRegForServices = FrameworkUtil.getBundle(this.getClass()).getBundleContext().registerService(ServiceProvider.class.getName(), this, properties); super.doStart(); } - /* ------------------------------------------------------------ */ - /** + /** * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStop() */ @Override protected void doStop() throws Exception { webappTracker.close(); - + //unregister ourselves if (_serviceRegForServices != null) { @@ -305,5 +287,4 @@ public class ServiceWebAppProvider extends AbstractWebAppProvider implements Ser } super.doStop(); } - } diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/DefaultJettyAtJettyHomeHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/DefaultJettyAtJettyHomeHelper.java index 2988ccbb146..6f4a95aafef 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/DefaultJettyAtJettyHomeHelper.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/DefaultJettyAtJettyHomeHelper.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -46,9 +46,9 @@ import org.osgi.framework.BundleContext; * Creates a default instance of Jetty, based on the values of the * System properties "jetty.home" or "jetty.home.bundle", one of which * must be specified in order to create the default instance. - *

        + *

        * Called by the {@link JettyBootstrapActivator} during the starting of the - * bundle. + * bundle. */ public class DefaultJettyAtJettyHomeHelper { @@ -63,15 +63,12 @@ public class DefaultJettyAtJettyHomeHelper * Set of config files to apply to a jetty Server instance if none are supplied by SYS_PROP_JETTY_ETC_FILES */ public static final String DEFAULT_JETTY_ETC_FILES = "etc/jetty.xml,etc/jetty-http.xml,etc/jetty-deployer.xml"; - + /** * Default location within bundle of a jetty home dir. */ public static final String DEFAULT_JETTYHOME = "/jettyhome"; - - - - /* ------------------------------------------------------------ */ + /** * Called by the JettyBootStrapActivator. If the system property jetty.home * is defined and points to a folder, creates a corresponding jetty @@ -91,6 +88,7 @@ public class DefaultJettyAtJettyHomeHelper * jetty.ssl.port are passed to the configuration files that might use them * as part of their properties. *

        + * * @param bundleContext the bundle context * @return the configured server * @throws Exception if unable to create / configure / or start the server @@ -101,7 +99,7 @@ public class DefaultJettyAtJettyHomeHelper String jettyHomeBundleSysProp = System.getProperty(OSGiServerConstants.JETTY_HOME_BUNDLE); File jettyHomeDir = null; Bundle jettyHomeBundle = null; - + Dictionary properties = new Hashtable<>(); if (jettyHomeSysProp != null) { @@ -109,17 +107,17 @@ public class DefaultJettyAtJettyHomeHelper // bug 329621 if (jettyHomeSysProp.startsWith("\"") && jettyHomeSysProp.endsWith("\"") || (jettyHomeSysProp.startsWith("'") && jettyHomeSysProp.endsWith("'"))) jettyHomeSysProp = jettyHomeSysProp.substring(1, jettyHomeSysProp.length() - 1); - + if (jettyHomeBundleSysProp != null) LOG.warn("Both jetty.home and jetty.home.bundle property defined: jetty.home.bundle ignored."); - + jettyHomeDir = new File(jettyHomeSysProp); if (!jettyHomeDir.exists() || !jettyHomeDir.isDirectory()) { LOG.warn("Unable to locate the jetty.home folder " + jettyHomeSysProp); return null; } - + //set jetty.home Util.setProperty(properties, OSGiServerConstants.JETTY_HOME, jettyHomeDir.getAbsolutePath()); } @@ -130,7 +128,7 @@ public class DefaultJettyAtJettyHomeHelper { if (b.getState() == Bundle.UNINSTALLED) continue; - + if (b.getSymbolicName().equals(jettyHomeBundleSysProp)) { jettyHomeBundle = b; @@ -143,31 +141,29 @@ public class DefaultJettyAtJettyHomeHelper return null; } } - + if (jettyHomeDir == null && jettyHomeBundle == null) { LOG.warn("No default jetty created."); return null; } - - - + //configure the server here rather than letting the JettyServerServiceTracker do it, because we want to be able to //configure the ThreadPool, which can only be done via the constructor, ie from within the xml configuration processing List configURLs = jettyHomeDir != null ? getJettyConfigurationURLs(jettyHomeDir) : getJettyConfigurationURLs(jettyHomeBundle, properties); - LOG.info("Configuring the default jetty server with {}",configURLs); - String home=(String)properties.get(OSGiServerConstants.JETTY_HOME); - String base=(String)properties.get(OSGiServerConstants.JETTY_BASE); - if (base==null) - base=home; - LOG.info("JETTY.HOME="+home); - LOG.info("JETTY.BASE="+base); + LOG.info("Configuring the default jetty server with {}", configURLs); + String home = (String)properties.get(OSGiServerConstants.JETTY_HOME); + String base = (String)properties.get(OSGiServerConstants.JETTY_BASE); + if (base == null) + base = home; + LOG.info("JETTY.HOME=" + home); + LOG.info("JETTY.BASE=" + base); ClassLoader contextCl = Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader(JettyBootstrapActivator.class.getClassLoader()); - + // these properties usually are the ones passed to this type of // configuration. properties.put(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME, OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME); @@ -177,7 +173,7 @@ public class DefaultJettyAtJettyHomeHelper Util.setProperty(properties, OSGiServerConstants.JETTY_HOME, home); Util.setProperty(properties, OSGiServerConstants.JETTY_BASE, base); Server server = ServerInstanceWrapper.configure(null, configURLs, properties); - + //Register the default Server instance as an OSGi service. //The JettyServerServiceTracker will notice it and set it up to deploy bundles as wars etc bundleContext.registerService(Server.class.getName(), server, properties); @@ -195,22 +191,14 @@ public class DefaultJettyAtJettyHomeHelper } } - - - - /* ------------------------------------------------------------ */ /** * Minimum setup for the location of the configuration files given a * jettyhome folder. Reads the system property jetty.etc.config.urls and * look for the corresponding jetty configuration files that will be used to * setup the jetty server. - * - * @param jettyhome - * @return - * @throws MalformedURLException */ - private static List getJettyConfigurationURLs(File jettyhome) - throws MalformedURLException + private static List getJettyConfigurationURLs(File jettyhome) + throws MalformedURLException { List configURLs = new ArrayList<>(); String jettyetc = System.getProperty(JETTY_ETC_FILES, DEFAULT_JETTY_ETC_FILES); @@ -219,29 +207,25 @@ public class DefaultJettyAtJettyHomeHelper { String next = tokenizer.nextToken().trim(); //etc files can either be relative to jetty.home or absolute disk locations - if (!next.startsWith("/") && (next.indexOf(':') == -1)) + if (!next.startsWith("/") && (next.indexOf(':') == -1)) configURLs.add(new File(jettyhome, next).toURI().toURL()); - else + else configURLs.add(new URL(next)); } return configURLs; } - /* ------------------------------------------------------------ */ /** * Minimum setup for the location of the configuration files given a * configuration embedded inside a bundle. Reads the system property * jetty.etc.config.urls and look for the corresponding jetty configuration * files that will be used to setup the jetty server. - * - * @param jettyhome - * @return */ private static List getJettyConfigurationURLs(Bundle configurationBundle, Dictionary properties) - throws Exception + throws Exception { List configURLs = new ArrayList<>(); - String files = System.getProperty(JETTY_ETC_FILES, DEFAULT_JETTY_ETC_FILES); + String files = System.getProperty(JETTY_ETC_FILES, DEFAULT_JETTY_ETC_FILES); StringTokenizer tokenizer = new StringTokenizer(files, ";,", false); while (tokenizer.hasMoreTokens()) @@ -261,10 +245,10 @@ public class DefaultJettyAtJettyHomeHelper if ((enUrls == null || !enUrls.hasMoreElements())) { home = DEFAULT_JETTYHOME; - String tmp = DEFAULT_JETTYHOME+(DEFAULT_JETTYHOME.endsWith("/")?"":"/")+etcFile; - enUrls = BundleFileLocatorHelperFactory.getFactory().getHelper().findEntries(configurationBundle, tmp); - LOG.info("Configuring jetty from bundle: {} with {}", configurationBundle.getSymbolicName(),tmp); - } + String tmp = DEFAULT_JETTYHOME + (DEFAULT_JETTYHOME.endsWith("/") ? "" : "/") + etcFile; + enUrls = BundleFileLocatorHelperFactory.getFactory().getHelper().findEntries(configurationBundle, tmp); + LOG.info("Configuring jetty from bundle: {} with {}", configurationBundle.getSymbolicName(), tmp); + } //lazily ensure jetty.home value is set based on location of etc files if (properties.get(OSGiServerConstants.JETTY_HOME) == null) @@ -273,27 +257,26 @@ public class DefaultJettyAtJettyHomeHelper if (res != null) properties.put(OSGiServerConstants.JETTY_HOME, res.toString()); } - + if (enUrls == null || !enUrls.hasMoreElements()) - throw new IllegalStateException ("Unable to locate a jetty configuration file for " + etcFile); + throw new IllegalStateException("Unable to locate a jetty configuration file for " + etcFile); URL url = BundleFileLocatorHelperFactory.getFactory().getHelper().getFileURL(enUrls.nextElement()); configURLs.add(url); - } } return configURLs; } - - /* ------------------------------------------------------------ */ + /** * Get a resource representing a directory inside a bundle. If the dir is null, * return a resource representing the installation location of the bundle. + * * @param bundle the bundle * @param dir the directory * @return the resource found */ - public static Resource findDir (Bundle bundle, String dir) + public static Resource findDir(Bundle bundle, String dir) { if (bundle == null) return null; @@ -305,21 +288,20 @@ public class DefaultJettyAtJettyHomeHelper u = BundleFileLocatorHelperFactory.getFactory().getHelper().getLocalURL(u); Resource res = Resource.newResource(u); String s = res.toString(); - + //check if it is an unarchived bundle if (s.endsWith(".jar") && s.startsWith("file:")) res = JarResource.newJarResource(res); - + //if looking for a directory if (dir != null) res = res.addPath(dir); - + return res; - } catch (Exception e) { - LOG.warn("Bad bundle location" , e); + LOG.warn("Bad bundle location", e); return null; } } diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/JettyServerServiceTracker.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/JettyServerServiceTracker.java index 5656c10baf6..03daafe65b9 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/JettyServerServiceTracker.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/JettyServerServiceTracker.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,7 +20,6 @@ package org.eclipse.jetty.osgi.boot.internal.serverfactory; import java.util.Dictionary; import java.util.Hashtable; -import java.util.Properties; import org.eclipse.jetty.osgi.boot.OSGiServerConstants; import org.eclipse.jetty.server.Server; @@ -32,29 +31,31 @@ import org.osgi.util.tracker.ServiceTrackerCustomizer; /** * JettyServerServiceTracker - * - * Tracks instances of Jetty Servers, and configures them so that they can deploy + * + * Tracks instances of Jetty Servers, and configures them so that they can deploy * webapps or ContextHandlers discovered from the OSGi environment. - * */ public class JettyServerServiceTracker implements ServiceTrackerCustomizer { private static Logger LOG = Log.getLogger(JettyServerServiceTracker.class.getName()); - - /** + /** * @see org.osgi.util.tracker.ServiceTrackerCustomizer#addingService(org.osgi.framework.ServiceReference) */ @Override public Object addingService(ServiceReference sr) { Bundle contributor = sr.getBundle(); - Server server = (Server) contributor.getBundleContext().getService(sr); - String name = (String) sr.getProperty(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME); - if (name == null) { throw new IllegalArgumentException("The property " + OSGiServerConstants.MANAGED_JETTY_SERVER_NAME + " is mandatory"); } - if (LOG.isDebugEnabled()) LOG.debug("Adding Server {}", name); + Server server = (Server)contributor.getBundleContext().getService(sr); + String name = (String)sr.getProperty(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME); + if (name == null) + { + throw new IllegalArgumentException("The property " + OSGiServerConstants.MANAGED_JETTY_SERVER_NAME + " is mandatory"); + } + if (LOG.isDebugEnabled()) + LOG.debug("Adding Server {}", name); ServerInstanceWrapper wrapper = new ServerInstanceWrapper(name); - Dictionary props = new Hashtable<>(); + Dictionary props = new Hashtable<>(); for (String key : sr.getPropertyKeys()) { props.put(key, sr.getProperty(key)); @@ -72,7 +73,7 @@ public class JettyServerServiceTracker implements ServiceTrackerCustomizer } } - /** + /** * @see org.osgi.util.tracker.ServiceTrackerCustomizer#modifiedService(org.osgi.framework.ServiceReference, java.lang.Object) */ @Override @@ -82,7 +83,7 @@ public class JettyServerServiceTracker implements ServiceTrackerCustomizer addingService(reference); } - /** + /** * @see org.osgi.util.tracker.ServiceTrackerCustomizer#removedService(org.osgi.framework.ServiceReference, java.lang.Object) */ @Override @@ -94,13 +95,12 @@ public class JettyServerServiceTracker implements ServiceTrackerCustomizer { ServerInstanceWrapper wrapper = (ServerInstanceWrapper)service; wrapper.stop(); - LOG.info("Stopped Server {}",wrapper.getManagedServerName()); + LOG.info("Stopped Server {}", wrapper.getManagedServerName()); } catch (Exception e) { LOG.warn(e); } } - } } diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/ServerInstanceWrapper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/ServerInstanceWrapper.java index 9e126ec4d67..7da9475bf74 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/ServerInstanceWrapper.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/ServerInstanceWrapper.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,7 +18,6 @@ package org.eclipse.jetty.osgi.boot.internal.serverfactory; -import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.Collection; @@ -58,8 +57,8 @@ import org.eclipse.jetty.xml.XmlConfiguration; /** * ServerInstanceWrapper - * - * Configures and starts a jetty Server instance. + * + * Configures and starts a jetty Server instance. */ public class ServerInstanceWrapper { @@ -70,13 +69,10 @@ public class ServerInstanceWrapper * support the case where the bundle is zipped. */ public static final String PROPERTY_THIS_JETTY_XML_FOLDER_URL = "this.jetty.xml.parent.folder.url"; - - + private static Collection __containerTldBundleDiscoverers = new ArrayList<>(); private static Logger LOG = Log.getLogger(ServerInstanceWrapper.class.getName()); - - private final String _managedServerName; @@ -95,36 +91,31 @@ public class ServerInstanceWrapper private ClassLoader _commonParentClassLoaderForWebapps; private DeploymentManager _deploymentManager; - - - - /* ------------------------------------------------------------ */ - public static void addContainerTldBundleDiscoverer (TldBundleDiscoverer tldBundleDiscoverer) + + public static void addContainerTldBundleDiscoverer(TldBundleDiscoverer tldBundleDiscoverer) { __containerTldBundleDiscoverers.add(tldBundleDiscoverer); } - - /* ------------------------------------------------------------ */ + public static Collection getContainerTldBundleDiscoverers() { return __containerTldBundleDiscoverers; } - - - - /* ------------------------------------------------------------ */ public static Server configure(Server server, List jettyConfigurations, Dictionary props) throws Exception { - - if (jettyConfigurations == null || jettyConfigurations.isEmpty()) { return server; } - - Map id_map = new HashMap<>(); + + if (jettyConfigurations == null || jettyConfigurations.isEmpty()) + { + return server; + } + + Map idMap = new HashMap<>(); if (server != null) { //Put in a mapping for the id "Server" and the name of the server as the instance being configured - id_map.put("Server", server); - id_map.put((String)props.get(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME), server); + idMap.put("Server", server); + idMap.put((String)props.get(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME), server); } Map properties = new HashMap<>(); @@ -136,18 +127,19 @@ public class ServerInstanceWrapper String key = en.nextElement(); Object value = props.get(key); properties.put(key, value.toString()); - if (server != null) server.setAttribute(key, value); + if (server != null) + server.setAttribute(key, value); } } for (URL jettyConfiguration : jettyConfigurations) { - try(InputStream in = jettyConfiguration.openStream()) + try { // Execute a Jetty configuration file - XmlConfiguration config = new XmlConfiguration(in); + XmlConfiguration config = new XmlConfiguration(jettyConfiguration); - config.getIdMap().putAll(id_map); + config.getIdMap().putAll(idMap); config.getProperties().putAll(properties); // #334062 compute the URL of the folder that contains the @@ -165,7 +157,7 @@ public class ServerInstanceWrapper if (server == null) server = (Server)o; - id_map = config.getIdMap(); + idMap = config.getIdMap(); } catch (Exception e) { @@ -176,37 +168,28 @@ public class ServerInstanceWrapper return server; } - - - - - /* ------------------------------------------------------------ */ + public ServerInstanceWrapper(String managedServerName) { _managedServerName = managedServerName; } - /* ------------------------------------------------------------ */ public String getManagedServerName() { return _managedServerName; } - - - /* ------------------------------------------------------------ */ + /** * The classloader that should be the parent classloader for each webapp * deployed on this server. - * + * * @return the classloader */ public ClassLoader getParentClassLoaderForWebapps() { return _commonParentClassLoaderForWebapps; } - - - /* ------------------------------------------------------------ */ + /** * @return The deployment manager registered on this server. */ @@ -214,9 +197,7 @@ public class ServerInstanceWrapper { return _deploymentManager; } - - - /* ------------------------------------------------------------ */ + /** * @return The app provider registered on this server. */ @@ -225,7 +206,6 @@ public class ServerInstanceWrapper return _server; } - /* ------------------------------------------------------------ */ /** * @return The collection of context handlers */ @@ -233,9 +213,8 @@ public class ServerInstanceWrapper { return _ctxtCollection; } - - /* ------------------------------------------------------------ */ - public void start(Server server, Dictionary props) throws Exception + + public void start(Server server, Dictionary props) throws Exception { _server = server; ClassLoader contextCl = Thread.currentThread().getContextClassLoader(); @@ -247,17 +226,18 @@ public class ServerInstanceWrapper // makes sure there is access to all the jetty's bundles ClassLoader libExtClassLoader = LibExtClassLoaderHelper.createLibExtClassLoader(null, sharedURLs, JettyBootstrapActivator.class.getClassLoader()); - if (LOG.isDebugEnabled()) LOG.debug("LibExtClassLoader = "+libExtClassLoader); - + if (LOG.isDebugEnabled()) + LOG.debug("LibExtClassLoader = " + libExtClassLoader); + Thread.currentThread().setContextClassLoader(libExtClassLoader); - String jettyConfigurationUrls = (String) props.get(OSGiServerConstants.MANAGED_JETTY_XML_CONFIG_URLS); + String jettyConfigurationUrls = (String)props.get(OSGiServerConstants.MANAGED_JETTY_XML_CONFIG_URLS); List jettyConfigurations = jettyConfigurationUrls != null ? Util.fileNamesAsURLs(jettyConfigurationUrls, Util.DEFAULT_DELIMS) : null; - + _server = configure(server, jettyConfigurations, props); init(); - + //if support for jsp is enabled, we need to convert locations of bundles that contain tlds into urls. //these are tlds that we want jasper to treat as if they are on the container's classpath. Web bundles //can use the Require-TldBundle MANIFEST header to name other tld-containing bundles that should be regarded @@ -266,22 +246,24 @@ public class ServerInstanceWrapper { Set urls = new HashSet<>(); //discover bundles with tlds that need to be on the container's classpath as URLs - for (TldBundleDiscoverer d:__containerTldBundleDiscoverers) + for (TldBundleDiscoverer d : __containerTldBundleDiscoverers) { URL[] list = d.getUrlsForBundlesWithTlds(_deploymentManager, BundleFileLocatorHelperFactory.getFactory().getHelper()); if (list != null) { - for (URL u:list) + for (URL u : list) + { urls.add(u); + } } } - _commonParentClassLoaderForWebapps = new FakeURLClassLoader(libExtClassLoader, urls.toArray(new URL[urls.size()])); + _commonParentClassLoaderForWebapps = new FakeURLClassLoader(libExtClassLoader, urls.toArray(new URL[urls.size()])); } else _commonParentClassLoaderForWebapps = libExtClassLoader; - - if (LOG.isDebugEnabled()) LOG.debug("common classloader = "+_commonParentClassLoaderForWebapps); + if (LOG.isDebugEnabled()) + LOG.debug("common classloader = " + _commonParentClassLoaderForWebapps); server.start(); } @@ -306,7 +288,6 @@ public class ServerInstanceWrapper } } - /* ------------------------------------------------------------ */ public void stop() { try @@ -321,36 +302,31 @@ public class ServerInstanceWrapper LOG.warn(e); } } - - - - - /* ------------------------------------------------------------ */ + /** - * Must be called after the server is configured. - * + * Must be called after the server is configured. + * * It is assumed the server has already been configured with the ContextHandlerCollection structure. - * */ private void init() { // Get the context handler - _ctxtCollection = (ContextHandlerCollection) _server.getChildHandlerByClass(ContextHandlerCollection.class); + _ctxtCollection = _server.getChildHandlerByClass(ContextHandlerCollection.class); - if (_ctxtCollection == null) + if (_ctxtCollection == null) throw new IllegalStateException("ERROR: No ContextHandlerCollection configured in Server"); - + List providerClassNames = new ArrayList<>(); - + // get a deployerManager and some providers Collection deployers = _server.getBeans(DeploymentManager.class); if (deployers != null && !deployers.isEmpty()) { _deploymentManager = deployers.iterator().next(); - + for (AppProvider provider : _deploymentManager.getAppProviders()) { - providerClassNames.add(provider.getClass().getName()); + providerClassNames.add(provider.getClass().getName()); } } else @@ -368,7 +344,7 @@ public class ServerInstanceWrapper deploymentLifeCycleBindings.add(new StandardStopper()); deploymentLifeCycleBindings.add(new OSGiUndeployer(this)); _deploymentManager.setLifeCycleBindings(deploymentLifeCycleBindings); - + if (!providerClassNames.contains(BundleWebAppProvider.class.getName())) { // create it on the fly with reasonable default values. @@ -424,7 +400,6 @@ public class ServerInstanceWrapper } } - /** * Get the Jetty Shared Lib Folder URLs in a form that is suitable for * {@link LibExtClassLoaderHelper} to use. @@ -432,9 +407,9 @@ public class ServerInstanceWrapper * @param props the properties to look for the configuration in * @return the list of URLs found, or null if none found */ - private List getManagedJettySharedLibFolderUrls(Dictionary props) + private List getManagedJettySharedLibFolderUrls(Dictionary props) { - String sharedURLs = (String) props.get(OSGiServerConstants.MANAGED_JETTY_SHARED_LIB_FOLDER_URLS); + String sharedURLs = (String)props.get(OSGiServerConstants.MANAGED_JETTY_SHARED_LIB_FOLDER_URLS); if (StringUtil.isBlank(sharedURLs)) { return null; diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/LibExtClassLoaderHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/LibExtClassLoaderHelper.java index 95123b51f50..46c026ff5f1 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/LibExtClassLoaderHelper.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/LibExtClassLoaderHelper.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -55,10 +55,10 @@ import java.util.Set; */ public class LibExtClassLoaderHelper { - /* ------------------------------------------------------------ */ + /** * IFilesInJettyHomeResourcesProcessor - * + * * Interface for callback impls */ public interface IFilesInJettyHomeResourcesProcessor @@ -66,23 +66,22 @@ public class LibExtClassLoaderHelper void processFilesInResourcesFolder(File jettyHome, Map filesInResourcesFolder); } - - public static final Set registeredFilesInJettyHomeResourcesProcessors = new HashSet<>(); - - /* ------------------------------------------------------------ */ /** - * @param jettyHome the jetty home + * @param jettyHome the jetty home * @param parentClassLoader the parent classloader * @return a url classloader with the jars of resources, lib/ext and the - * jars passed in the other argument. The parent classloader usually - * is the JettyBootStrapper (an osgi classloader. + * jars passed in the other argument. The parent classloader usually + * is the JettyBootStrapper (an osgi classloader. * @throws MalformedURLException if the jetty home reference is invalid */ public static ClassLoader createLibEtcClassLoader(File jettyHome, ClassLoader parentClassLoader) throws MalformedURLException { - if (jettyHome == null) { return parentClassLoader; } + if (jettyHome == null) + { + return parentClassLoader; + } ArrayList urls = new ArrayList<>(); File jettyResources = new File(jettyHome, "resources"); if (jettyResources.exists()) @@ -116,7 +115,8 @@ public class LibExtClassLoaderHelper // cheap to tolerate folders so let's do it. URL url = f.toURI().toURL(); if (f.isFile()) - {// is this necessary anyways? + { + // is this necessary anyways? url = new URL("jar:" + url.toString() + "!/"); } urls.add(url); @@ -127,22 +127,23 @@ public class LibExtClassLoaderHelper return new URLClassLoader(urls.toArray(new URL[urls.size()]), parentClassLoader); } - - /* ------------------------------------------------------------ */ /** * @param jarsContainerOrJars the jars via file references * @param otherJarsOrFolder more jars via url references * @param parentClassLoader the parent classloader * @return a url classloader with the jars of resources, lib/ext and the - * jars passed in the other argument. The parent classloader usually - * is the JettyBootStrapper (an osgi classloader). If there was no - * extra jars to insert, then just return the parentClassLoader. + * jars passed in the other argument. The parent classloader usually + * is the JettyBootStrapper (an osgi classloader). If there was no + * extra jars to insert, then just return the parentClassLoader. * @throws MalformedURLException if there is a bad jar file reference */ - public static ClassLoader createLibExtClassLoader(List jarsContainerOrJars, List otherJarsOrFolder, ClassLoader parentClassLoader) - throws MalformedURLException + public static ClassLoader createLibExtClassLoader(List jarsContainerOrJars, List otherJarsOrFolder, ClassLoader parentClassLoader) + throws MalformedURLException { - if (jarsContainerOrJars == null && otherJarsOrFolder == null) { return parentClassLoader; } + if (jarsContainerOrJars == null && otherJarsOrFolder == null) + { + return parentClassLoader; + } List urls = new ArrayList<>(); if (otherJarsOrFolder != null) { @@ -174,7 +175,6 @@ public class LibExtClassLoaderHelper return new URLClassLoader(urls.toArray(new URL[urls.size()]), parentClassLoader); } - /* ------------------------------------------------------------ */ /** * When we find files typically used for central logging configuration we do * what it takes in this method to do what the user expects. Without @@ -187,6 +187,7 @@ public class LibExtClassLoaderHelper *

        * We recommend that slf4j jars are all placed in the osgi framework. And a * single implementation if possible packaged as an osgi bundle is there. + * * @param jettyHome the jetty home reference * @param childrenFiles the map of child files */ @@ -197,5 +198,4 @@ public class LibExtClassLoaderHelper processor.processFilesInResourcesFolder(jettyHome, childrenFiles); } } - } diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/OSGiWebappClassLoader.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/OSGiWebappClassLoader.java index 3642373d861..9cfdc747513 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/OSGiWebappClassLoader.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/OSGiWebappClassLoader.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -30,10 +30,10 @@ import java.util.List; import java.util.Set; import java.util.StringTokenizer; import java.util.jar.JarFile; - import javax.servlet.http.HttpServlet; import org.eclipse.jetty.osgi.boot.utils.BundleClassLoaderHelperFactory; +import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.resource.Resource; @@ -44,8 +44,8 @@ import org.osgi.framework.BundleReference; /** * OSGiWebappClassLoader - * - * + * + * * Extends the webapp classloader to also use the classloader of the Bundle defining the webapp. */ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleReference @@ -61,12 +61,12 @@ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleRe public static void addClassThatIdentifiesAJarThatMustBeRejected(Class zclass) { - JAR_WITH_SUCH_CLASS_MUST_BE_EXCLUDED.add(zclass.getName().replace('.', '/') + ".class"); + JAR_WITH_SUCH_CLASS_MUST_BE_EXCLUDED.add(TypeUtil.toClassReference(zclass.getName())); } public static void addClassThatIdentifiesAJarThatMustBeRejected(String zclassName) { - JAR_WITH_SUCH_CLASS_MUST_BE_EXCLUDED.add(zclassName.replace('.', '/') + ".class"); + JAR_WITH_SUCH_CLASS_MUST_BE_EXCLUDED.add(TypeUtil.toClassReference(zclassName)); } static @@ -78,7 +78,6 @@ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleRe private Bundle _contributor; - /* ------------------------------------------------------------ */ /** * @param parent The parent classloader. * @param context The WebAppContext @@ -86,14 +85,12 @@ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleRe * @throws IOException if unable to cerate the OSGiWebappClassLoader */ public OSGiWebappClassLoader(ClassLoader parent, WebAppContext context, Bundle contributor) - throws IOException + throws IOException { super(parent, context); _contributor = contributor; _osgiBundleClassLoader = BundleClassLoaderHelperFactory.getFactory().getHelper().getBundleClassLoader(contributor); } - - @Override protected Class findClass(String name) throws ClassNotFoundException @@ -116,12 +113,11 @@ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleRe } } - /* ------------------------------------------------------------ */ /** * Returns the Bundle that defined this web-application. - * + * * @return The Bundle object associated with this - * BundleReference. + * BundleReference. */ @Override public Bundle getBundle() @@ -129,7 +125,6 @@ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleRe return _contributor; } - /* ------------------------------------------------------------ */ @Override public Enumeration getResources(String name) throws IOException { @@ -138,35 +133,29 @@ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleRe List resources = toList(osgiUrls, urls); return Collections.enumeration(resources); } - - /* ------------------------------------------------------------ */ + @Override public URL getResource(String name) { URL url = _osgiBundleClassLoader.getResource(name); return url != null ? url : super.getResource(name); } - - - - + @Override public URL findResource(String name) { URL url = _osgiBundleClassLoader.getResource(name); return url != null ? url : super.findResource(name); } - - - /** + /** * Try to load the class from the bundle classloader. * We do NOT load it as a resource as the WebAppClassLoader does because the * url that is returned is an osgi-special url that does not play * properly with WebAppClassLoader's method of extracting the class * from the resource. This implementation directly asks the osgi * bundle classloader to load the given class name. - * + * * @see org.eclipse.jetty.webapp.WebAppClassLoader#loadAsResource(java.lang.String, boolean) */ @Override @@ -189,18 +178,20 @@ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleRe } } - /* ------------------------------------------------------------ */ private List toList(Enumeration e, Enumeration e2) { List list = new ArrayList<>(); while (e != null && e.hasMoreElements()) + { list.add(e.nextElement()); + } while (e2 != null && e2.hasMoreElements()) + { list.add(e2.nextElement()); + } return list; - } - - /* ------------------------------------------------------------ */ + } + /** * Parse the classpath ourselves to be able to filter things. This is a * derivative work of the super class @@ -226,13 +217,9 @@ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleRe __logger.info("Did not add " + path + " to the classloader of the webapp " + getContext()); } } - } - - /* ------------------------------------------------------------ */ /** - * @param lib * @return true if the lib should be included in the webapp classloader. */ private boolean isAcceptableLibrary(File file, Set pathToClassFiles) @@ -243,7 +230,10 @@ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleRe { for (String criteria : pathToClassFiles) { - if (new File(file, criteria).exists()) { return false; } + if (new File(file, criteria).exists()) + { + return false; + } } } else @@ -254,18 +244,22 @@ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleRe jar = new JarFile(file); for (String criteria : pathToClassFiles) { - if (jar.getEntry(criteria) != null) { return false; } + if (jar.getEntry(criteria) != null) + { + return false; + } } } finally { - if (jar != null) try - { - jar.close(); - } - catch (IOException ioe) - { - } + if (jar != null) + try + { + jar.close(); + } + catch (IOException ignored) + { + } } } } @@ -279,14 +273,13 @@ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleRe private static Field _contextField; - - /* ------------------------------------------------------------ */ /** * In the case of the generation of a webapp via a jetty context file we * need a proper classloader to setup the app before we have the * WebappContext So we place a fake one there to start with. We replace it * with the actual webapp context with this method. We also apply the * extraclasspath there at the same time. + * * @param webappContext the web app context */ public void setWebappContext(WebAppContext webappContext) diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleClassLoaderHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleClassLoaderHelper.java index 533c20d1a76..4863ff960ee 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleClassLoaderHelper.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleClassLoaderHelper.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -23,7 +23,7 @@ import org.osgi.framework.Bundle; /** * BundleClassLoaderHelper - *

        + *

        * Is there a clean OSGi way to go from the Bundle object to the classloader of * the Bundle ? You can certainly take a class inside the bundle and get the * bundle's classloader that way. Getting the classloader directly from the @@ -39,17 +39,20 @@ import org.osgi.framework.Bundle; public interface BundleClassLoaderHelper { - /** The name of the custom implementation for this interface in a fragment. */ - public static final String CLASS_NAME = "org.eclipse.jetty.osgi.boot.utils.BundleClassLoaderHelperImpl"; + /** + * The name of the custom implementation for this interface in a fragment. + */ + String CLASS_NAME = "org.eclipse.jetty.osgi.boot.utils.BundleClassLoaderHelperImpl"; - /** The default instance supports felix and equinox */ - public static BundleClassLoaderHelper DEFAULT = new DefaultBundleClassLoaderHelper(); + /** + * The default instance supports felix and equinox + */ + BundleClassLoaderHelper DEFAULT = new DefaultBundleClassLoaderHelper(); /** * @param bundle the bundle * @return The classloader of a given bundle. Assuming the bundle is - * started. + * started. */ - public ClassLoader getBundleClassLoader(Bundle bundle); - + ClassLoader getBundleClassLoader(Bundle bundle); } diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleClassLoaderHelperFactory.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleClassLoaderHelperFactory.java index a3f8213561c..d52375109e1 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleClassLoaderHelperFactory.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleClassLoaderHelperFactory.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -29,22 +29,18 @@ import org.eclipse.jetty.util.log.Logger; public class BundleClassLoaderHelperFactory { private static final Logger LOG = Log.getLogger(BundleClassLoaderHelperFactory.class); - + private static BundleClassLoaderHelperFactory _instance = new BundleClassLoaderHelperFactory(); - - - /* ------------------------------------------------------------ */ + public static BundleClassLoaderHelperFactory getFactory() { return _instance; } - - /* ------------------------------------------------------------ */ + private BundleClassLoaderHelperFactory() { } - - /* ------------------------------------------------------------ */ + public BundleClassLoaderHelper getHelper() { //use the default @@ -52,15 +48,14 @@ public class BundleClassLoaderHelperFactory try { //if a fragment has not provided their own impl - helper = (BundleClassLoaderHelper) Class.forName(BundleClassLoaderHelper.CLASS_NAME) + helper = (BundleClassLoaderHelper)Class.forName(BundleClassLoaderHelper.CLASS_NAME) .getDeclaredConstructor().newInstance(); } catch (Throwable t) { LOG.ignore(t); } - + return helper; } - } diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleFileLocatorHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleFileLocatorHelper.java index 0d6cfbc51ab..84a1caf0880 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleFileLocatorHelper.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleFileLocatorHelper.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -27,18 +27,22 @@ import org.osgi.framework.Bundle; /** * BundleFileLocatorHelper - *

        + *

        * From a bundle to its location on the filesystem. Assumes the bundle is not a * jar. */ public interface BundleFileLocatorHelper { - /** The name of the custom implementation for this interface in a fragment. */ - public static final String CLASS_NAME = "org.eclipse.jetty.osgi.boot.utils.FileLocatorHelperImpl"; + /** + * The name of the custom implementation for this interface in a fragment. + */ + String CLASS_NAME = "org.eclipse.jetty.osgi.boot.utils.FileLocatorHelperImpl"; - /** The default instance supports felix and equinox */ - public static BundleFileLocatorHelper DEFAULT = new DefaultFileLocatorHelper(); + /** + * The default instance supports felix and equinox + */ + BundleFileLocatorHelper DEFAULT = new DefaultFileLocatorHelper(); /** * Works with equinox, felix, nuxeo and probably more. Not exactly in the @@ -46,22 +50,22 @@ public interface BundleFileLocatorHelper * other situations. *

        * Currently only works with bundles that are not jar. - * + * * @param bundle The bundle * @return Its installation location as a file. * @throws Exception if unable to get the install location */ - public File getBundleInstallLocation(Bundle bundle) throws Exception; + File getBundleInstallLocation(Bundle bundle) throws Exception; /** * Locate a file inside a bundle. - * + * * @param bundle the bundle * @param path the path * @return file the file object * @throws Exception if unable to get the file */ - public File getFileInBundle(Bundle bundle, String path) throws Exception; + File getFileInBundle(Bundle bundle, String path) throws Exception; /** * If the bundle is a jar, returns the jar. If the bundle is a folder, look @@ -71,37 +75,37 @@ public interface BundleFileLocatorHelper * files inside jars alone. In fact we only support the second situation for * development purpose where the bundle was imported in pde and the classes * kept in a jar. - * + * * @param bundle the bundle * @return The jar(s) file that is either the bundle itself, either the jars - * embedded inside it. + * embedded inside it. * @throws Exception if unable to locate the jars */ - public File[] locateJarsInsideBundle(Bundle bundle) throws Exception; + File[] locateJarsInsideBundle(Bundle bundle) throws Exception; /** * Helper method equivalent to Bundle#getEntry(String entryPath) except that * it searches for entries in the fragments by using the findEntries method. - * + * * @param bundle the bundle * @param entryPath the entry path * @return null or all the entries found for that path. */ - public Enumeration findEntries(Bundle bundle, String entryPath); - + Enumeration findEntries(Bundle bundle, String entryPath); + /** * Only useful for equinox: on felix we get the file:// or jar:// url * already. Other OSGi implementations have not been tested *

        * Get a URL to the bundle entry that uses a common protocol (i.e. file: * jar: or http: etc.). - * - * @param url the url + * + * @param url the url * @return a URL to the bundle entry that uses a common protocol * @throws Exception if unable to get the local url */ - public URL getLocalURL(URL url) throws Exception; - + URL getLocalURL(URL url) throws Exception; + /** * Only useful for equinox: on felix we get the file:// url already. Other * OSGi implementations have not been tested @@ -109,12 +113,11 @@ public interface BundleFileLocatorHelper * Get a URL to the content of the bundle entry that uses the file: * protocol. The content of the bundle entry may be downloaded or extracted * to the local file system in order to create a file: URL. - * - * @param url the url + * + * @param url the url * @return a URL to the content of the bundle entry that uses the file: - * protocol + * protocol * @throws Exception if unable to get the file url */ - public URL getFileURL(URL url) throws Exception; - + URL getFileURL(URL url) throws Exception; } diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleFileLocatorHelperFactory.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleFileLocatorHelperFactory.java index 7ed0cec8a62..a9335f1eebc 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleFileLocatorHelperFactory.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleFileLocatorHelperFactory.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -27,25 +27,27 @@ import org.eclipse.jetty.util.log.Logger; * Obtain a helper for locating files based on the bundle. */ public class BundleFileLocatorHelperFactory -{ +{ private static final Logger LOG = Log.getLogger(BundleFileLocatorHelperFactory.class); - + private static BundleFileLocatorHelperFactory _instance = new BundleFileLocatorHelperFactory(); - - private BundleFileLocatorHelperFactory() {} - + + private BundleFileLocatorHelperFactory() + { + } + public static BundleFileLocatorHelperFactory getFactory() { return _instance; } - + public BundleFileLocatorHelper getHelper() { BundleFileLocatorHelper helper = BundleFileLocatorHelper.DEFAULT; try { //see if a fragment has supplied an alternative - helper = (BundleFileLocatorHelper) Class.forName(BundleFileLocatorHelper.CLASS_NAME) + helper = (BundleFileLocatorHelper)Class.forName(BundleFileLocatorHelper.CLASS_NAME) .getDeclaredConstructor().newInstance(); } catch (Throwable t) @@ -54,5 +56,4 @@ public class BundleFileLocatorHelperFactory } return helper; } - } diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/EventSender.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/EventSender.java index fb63f55b210..ed6798e3a94 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/EventSender.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/EventSender.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -31,43 +31,44 @@ import org.osgi.util.tracker.ServiceTracker; * Utility class for emitting OSGi EventAdmin events */ public class EventSender -{ +{ //OSGi Event Admin events for webapps public static final String DEPLOYING_EVENT = "org/osgi/service/web/DEPLOYING"; public static final String DEPLOYED_EVENT = "org/osgi/service/web/DEPLOYED"; public static final String UNDEPLOYING_EVENT = "org/osgi/service/web/UNDEPLOYING"; - public static final String UNDEPLOYED_EVENT = "org/osgi/service/web/UNDEPLOYED"; - public static final String FAILED_EVENT = "org/osgi/service/web/FAILED"; - + public static final String UNDEPLOYED_EVENT = "org/osgi/service/web/UNDEPLOYED"; + public static final String FAILED_EVENT = "org/osgi/service/web/FAILED"; + private static final EventSender __instance = new EventSender(); private Bundle _myBundle; private ServiceTracker _serviceTracker; - - private EventSender () + + private EventSender() { _myBundle = FrameworkUtil.getBundle(EventSender.class); - _serviceTracker = new ServiceTracker(_myBundle.getBundleContext(),EventAdmin.class.getName(),null); + _serviceTracker = new ServiceTracker(_myBundle.getBundleContext(), EventAdmin.class.getName(), null); _serviceTracker.open(); } - + public static EventSender getInstance() { return __instance; } - public void send (String topic, Bundle wab, String contextPath) + public void send(String topic, Bundle wab, String contextPath) { - if (topic==null || wab==null || contextPath==null) + if (topic == null || wab == null || contextPath == null) return; - + send(topic, wab, contextPath, null); } - - public void send (String topic, Bundle wab, String contextPath, Exception ex) - { + + public void send(String topic, Bundle wab, String contextPath, Exception ex) + { EventAdmin service = (EventAdmin)_serviceTracker.getService(); - if (service != null) { - Dictionary props = new Hashtable<>(); + if (service != null) + { + Dictionary props = new Hashtable<>(); props.put("bundle.symbolicName", wab.getSymbolicName()); props.put("bundle.id", wab.getBundleId()); props.put("bundle", wab); @@ -78,10 +79,10 @@ public class EventSender props.put("extender.bundle.symbolicName", _myBundle.getSymbolicName()); props.put("extender.bundle.id", _myBundle.getBundleId()); props.put("extender.bundle.version", _myBundle.getVersion()); - - if (FAILED_EVENT.equalsIgnoreCase(topic) && ex != null) + + if (FAILED_EVENT.equalsIgnoreCase(topic) && ex != null) props.put("exception", ex); - + service.sendEvent(new Event(topic, props)); } } diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/FakeURLClassLoader.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/FakeURLClassLoader.java index 9fffcd97fbf..f755f85bbbb 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/FakeURLClassLoader.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/FakeURLClassLoader.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -35,18 +35,16 @@ import java.net.URLClassLoader; public class FakeURLClassLoader extends URLClassLoader { private URL[] _jars; - - /* ------------------------------------------------------------ */ + public FakeURLClassLoader(ClassLoader osgiClassLoader, URL[] jars) { - super(new URL[] {},osgiClassLoader); + super(new URL[]{}, osgiClassLoader); _jars = jars; } - /* ------------------------------------------------------------ */ /** * @return the jars that contains tlds so that TldLocationsCache or - * TldScanner can find them. + * TldScanner can find them. */ @Override public URL[] getURLs() @@ -54,9 +52,7 @@ public class FakeURLClassLoader extends URLClassLoader return _jars; } - - /* ------------------------------------------------------------ */ - /** + /** * @see java.lang.Object#toString() */ @Override @@ -66,8 +62,10 @@ public class FakeURLClassLoader extends URLClassLoader if (_jars != null) { - for (URL u:_jars) - builder.append(" "+u.toString()); + for (URL u : _jars) + { + builder.append(" " + u.toString()); + } return builder.toString(); } else diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/OSGiClassLoader.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/OSGiClassLoader.java index 0b7f86e6528..6c7a44d804f 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/OSGiClassLoader.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/OSGiClassLoader.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -39,13 +39,11 @@ import org.osgi.framework.Bundle; public class OSGiClassLoader extends URLClassLoader { private static final Logger LOG = Log.getLogger(OSGiClassLoader.class); - - + private Bundle _bundle; private ClassLoader _osgiBundleClassLoader; private ClassLoader _parent; - - /* ------------------------------------------------------------ */ + public OSGiClassLoader(ClassLoader parent, Bundle bundle) { super(new URL[]{}, parent); @@ -53,24 +51,20 @@ public class OSGiClassLoader extends URLClassLoader _bundle = bundle; _osgiBundleClassLoader = BundleClassLoaderHelperFactory.getFactory().getHelper().getBundleClassLoader(_bundle); } - - - - /* ------------------------------------------------------------ */ + /** * Get a resource from the classloader - * + * * Copied from WebAppClassLoader */ @Override public URL getResource(String name) { - URL url= null; - boolean tried_parent= false; + URL url = null; + boolean triedParent = false; - if (url == null) - { + { url = _osgiBundleClassLoader.getResource(name); if (url == null && name.startsWith("/")) @@ -82,47 +76,45 @@ public class OSGiClassLoader extends URLClassLoader } } - if (url == null && !tried_parent) + if (url == null && !triedParent) { - if (_parent!=null) - url= _parent.getResource(name); + if (_parent != null) + url = _parent.getResource(name); } if (url != null) if (LOG.isDebugEnabled()) - LOG.debug("getResource("+name+")=" + url); + LOG.debug("getResource(" + name + ")=" + url); return url; } - - /* ------------------------------------------------------------ */ + @Override public Class loadClass(String name) throws ClassNotFoundException { return loadClass(name, false); } - /* ------------------------------------------------------------ */ @Override protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException { Class c = findLoadedClass(name); - ClassNotFoundException ex= null; - boolean tried_parent= false; - + ClassNotFoundException ex = null; + boolean triedParent = false; + if (c == null) { try { - c= this.findClass(name); + c = this.findClass(name); } catch (ClassNotFoundException e) { - ex= e; + ex = e; } } - if (c == null && _parent!=null && !tried_parent) + if (c == null && _parent != null && !triedParent) c = _parent.loadClass(name); if (c == null) @@ -132,12 +124,11 @@ public class OSGiClassLoader extends URLClassLoader resolveClass(c); if (LOG.isDebugEnabled()) - LOG.debug("loaded " + c+ " from "+c.getClassLoader()); - + LOG.debug("loaded " + c + " from " + c.getClassLoader()); + return c; } - - /* ------------------------------------------------------------ */ + @Override public Enumeration getResources(String name) throws IOException { @@ -145,32 +136,27 @@ public class OSGiClassLoader extends URLClassLoader Enumeration urls = super.getResources(name); return Collections.enumeration(toList(osgiUrls, urls)); } - - - /* ------------------------------------------------------------ */ + @Override protected Class findClass(String name) throws ClassNotFoundException { - return _osgiBundleClassLoader.loadClass(name); + return _osgiBundleClassLoader.loadClass(name); } - - - - - /* ------------------------------------------------------------ */ /** - * @param e - * @param e2 - * @return + * */ private List toList(Enumeration e, Enumeration e2) { List list = new ArrayList<>(); while (e != null && e.hasMoreElements()) + { list.add(e.nextElement()); + } while (e2 != null && e2.hasMoreElements()) + { list.add(e2.nextElement()); + } return list; } } diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/ServerConnectorListener.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/ServerConnectorListener.java index 311e3ee9225..3e2a3538082 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/ServerConnectorListener.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/ServerConnectorListener.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,7 +16,6 @@ // ======================================================================== // - package org.eclipse.jetty.osgi.boot.utils; import java.io.FileWriter; @@ -30,7 +29,7 @@ import org.eclipse.jetty.util.component.LifeCycle; /** * ServerConnectorListener * - * This is for test support, where we need jetty to run on a random port, and we need + * This is for test support, where we need jetty to run on a random port, and we need * a client to be able to find out which port was picked. */ public class ServerConnectorListener extends AbstractLifeCycleListener @@ -39,9 +38,7 @@ public class ServerConnectorListener extends AbstractLifeCycleListener private Path _filePath; private String _sysPropertyName; - - - /** + /** * @see org.eclipse.jetty.util.component.AbstractLifeCycle.AbstractLifeCycleListener#lifeCycleStarted(org.eclipse.jetty.util.component.LifeCycle) */ @Override @@ -57,13 +54,13 @@ public class ServerConnectorListener extends AbstractLifeCycleListener } catch (Exception e) { - throw new RuntimeException (e); + throw new RuntimeException(e); } } - + if (getSysPropertyName() != null) { - System.setProperty(_sysPropertyName,String.valueOf(((ServerConnector)event).getLocalPort())); + System.setProperty(_sysPropertyName, String.valueOf(((ServerConnector)event).getLocalPort())); } super.lifeCycleStarted(event); } @@ -99,6 +96,4 @@ public class ServerConnectorListener extends AbstractLifeCycleListener { _sysPropertyName = sysPropertyName; } - - } diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/TldBundleDiscoverer.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/TldBundleDiscoverer.java index fdaa4b8c96f..efd3d6321a0 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/TldBundleDiscoverer.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/TldBundleDiscoverer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -22,22 +22,20 @@ import java.net.URL; import org.eclipse.jetty.deploy.DeploymentManager; - /** * TldBundleDiscoverer - * + * * Convert bundles that contain tlds into URL locations for consumption by jasper. */ public interface TldBundleDiscoverer { /** * Find bundles that contain tlds and convert into URL references to their location. - * + * * @param manager The {@link DeploymentManager} instance to use * @param fileLocator the {@link BundleFileLocatorHelper} instance to use * @return array of URLs representing locations of tld containing bundles * @throws Exception In case of errors during resolving TLDs files */ URL[] getUrlsForBundlesWithTlds(DeploymentManager manager, BundleFileLocatorHelper fileLocator) throws Exception; - } diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/Util.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/Util.java index c28846ab975..1d257f44890 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/Util.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/Util.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,7 +16,6 @@ // ======================================================================== // - package org.eclipse.jetty.osgi.boot.utils; import java.net.URL; @@ -38,65 +37,57 @@ public class Util { public static final String DEFAULT_DELIMS = ",;"; - /** * Create an osgi filter for the given classname and server name. - * + * * @param bundleContext the {@link BundleContext} instance to use * @param classname the class to match on the filter * @param managedServerName the name of the jetty server instance * @return a new filter - * * @throws InvalidSyntaxException If the filter contains an invalid string that cannot be parsed. */ - public static Filter createFilter (BundleContext bundleContext, String classname, String managedServerName) throws InvalidSyntaxException + public static Filter createFilter(BundleContext bundleContext, String classname, String managedServerName) throws InvalidSyntaxException { if (StringUtil.isBlank(managedServerName) || managedServerName.equals(OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME)) { - return bundleContext.createFilter("(&(objectclass=" + classname - + ")(|(managedServerName="+managedServerName - +")(!(managedServerName=*))))"); + return bundleContext.createFilter("(&(objectclass=" + classname + ")(|(managedServerName=" + managedServerName + ")(!(managedServerName=*))))"); } else { - return bundleContext.createFilter("(&(objectclass=" + classname+ ")(managedServerName="+managedServerName+"))"); + return bundleContext.createFilter("(&(objectclass=" + classname + ")(managedServerName=" + managedServerName + "))"); } - } - + /** * Get the value of a manifest header. - * + * * @param name the name of the header * @param altName an alternative name for the header (useful for deprecated names) * @param manifest the dictionary * @return the value from the manifest */ - public static String getManifestHeaderValue (String name, String altName, Dictionary manifest) + public static String getManifestHeaderValue(String name, String altName, Dictionary manifest) { if (manifest == null) return null; if (name == null && altName == null) return null; if (name != null) - return (String)manifest.get(name); - return (String)manifest.get(altName); + return manifest.get(name); + return manifest.get(altName); } - - - - /* ------------------------------------------------------------ */ + /** * Treating the string as a separated list of filenames, * convert and return the list of urls. - * + * * @param val the separated list of filenames * @param delims the separators (default is ,;) * @return the list of URLs found in the input list * @throws Exception if unable to convert entry to a URL */ - public static List fileNamesAsURLs(String val, String delims) - throws Exception + public static List fileNamesAsURLs(String val, String delims) + throws Exception { String separators = DEFAULT_DELIMS; if (delims == null) @@ -110,34 +101,36 @@ public class Util } return urls; } - - - /* ------------------------------------------------------------ */ - public static void setProperty(Dictionary properties, String key, Object value) + + public static void setProperty(Dictionary properties, String key, Object value) { if (value != null) { properties.put(key, value); } } - - - /* ------------------------------------------------------------ */ + /** * recursively substitute the ${sysprop} by their actual system property. * ${sysprop,defaultvalue} will use 'defaultvalue' as the value if no * sysprop is defined. Not the most efficient code but we are shooting for * simplicity and speed of development here. - * + * * @param value the input string * @return the string with replaced properties */ public static String resolvePropertyValue(String value) { int ind = value.indexOf("${"); - if (ind == -1) { return value; } + if (ind == -1) + { + return value; + } int ind2 = value.indexOf('}', ind); - if (ind2 == -1) { return value; } + if (ind2 == -1) + { + return value; + } String sysprop = value.substring(ind + 2, ind2); String defaultValue = null; int comma = sysprop.indexOf(','); diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultBundleClassLoaderHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultBundleClassLoaderHelper.java index 53a754535dd..7cbc2fd963e 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultBundleClassLoaderHelper.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultBundleClassLoaderHelper.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -36,7 +36,12 @@ import org.osgi.framework.Bundle; public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper { private static final Logger LOG = Log.getLogger(BundleClassLoaderHelper.class); - private static enum OSGiContainerType {EquinoxOld, EquinoxLuna, FelixOld, Felix403, Concierge}; + + private enum OSGiContainerType + { + EquinoxOld, EquinoxLuna, FelixOld, Felix403, Concierge + } + private static OSGiContainerType osgiContainer; private static Class Equinox_BundleHost_Class; private static Class Equinox_EquinoxBundle_Class; @@ -47,26 +52,25 @@ public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper private static Method Equinox_BundleLoader_createClassLoader_method; //new equinox private static Method Equinox_EquinoxBundle_getModuleClassLoader_Method; - + //new felix private static Method Felix_BundleImpl_Adapt_Method; //old felix private static Field Felix_BundleImpl_m_Modules_Field; private static Field Felix_ModuleImpl_m_ClassLoader_Field; private static Method Felix_BundleWiring_getClassLoader_Method; - + // Concierge private static Class Concierge_BundleImpl_Class; private static Class Concierge_BundleWiring_Class; private static Method Concierge_BundleImpl_Adapt_Method; private static Method Concierge_BundleWiring_getClassLoader_Method; - - - private static void checkContainerType (Bundle bundle) + + private static void checkContainerType(Bundle bundle) { if (osgiContainer != null) return; - + try { Equinox_BundleHost_Class = bundle.getClass().getClassLoader().loadClass("org.eclipse.osgi.framework.internal.core.BundleHost"); @@ -88,14 +92,14 @@ public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper { LOG.ignore(e); } - + try - { + { //old felix or new felix? - Felix_BundleImpl_Class = bundle.getClass().getClassLoader().loadClass("org.apache.felix.framework.BundleImpl"); + Felix_BundleImpl_Class = bundle.getClass().getClassLoader().loadClass("org.apache.felix.framework.BundleImpl"); try { - Felix_BundleImpl_Adapt_Method = Felix_BundleImpl_Class.getDeclaredMethod("adapt", new Class[] {Class.class}); + Felix_BundleImpl_Adapt_Method = Felix_BundleImpl_Class.getDeclaredMethod("adapt", Class.class); osgiContainer = OSGiContainerType.Felix403; return; } @@ -109,7 +113,7 @@ public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper { LOG.ignore(e); } - + try { Concierge_BundleImpl_Class = bundle.getClass().getClassLoader().loadClass("org.eclipse.concierge.BundleImpl"); @@ -125,24 +129,20 @@ public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper return; } - - - - /** * Assuming the bundle is started. - * + * * @param bundle the bundle * @return classloader object */ @Override public ClassLoader getBundleClassLoader(Bundle bundle) { - String bundleActivator = (String) bundle.getHeaders().get("Bundle-Activator"); - + String bundleActivator = (String)bundle.getHeaders().get("Bundle-Activator"); + if (bundleActivator == null) { - bundleActivator = (String) bundle.getHeaders().get("Jetty-ClassInBundle"); + bundleActivator = (String)bundle.getHeaders().get("Jetty-ClassInBundle"); } if (bundleActivator != null) { @@ -155,24 +155,23 @@ public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper LOG.warn(e); } } - + // resort to introspection return getBundleClassLoaderForContainer(bundle); } - + /** - * @param bundle - * @return + * */ - private ClassLoader getBundleClassLoaderForContainer (Bundle bundle) + private ClassLoader getBundleClassLoaderForContainer(Bundle bundle) { - checkContainerType (bundle); + checkContainerType(bundle); if (osgiContainer == null) { LOG.warn("No classloader for unknown OSGi container type"); return null; } - + switch (osgiContainer) { case EquinoxOld: @@ -184,28 +183,24 @@ public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper case FelixOld: case Felix403: { - return internalGetFelixBundleClassLoader(bundle); + return internalGetFelixBundleClassLoader(bundle); } case Concierge: { - return internalGetConciergeBundleClassLoader(bundle); + return internalGetConciergeBundleClassLoader(bundle); } default: { - LOG.warn("No classloader found for bundle "+bundle.getSymbolicName()); + LOG.warn("No classloader found for bundle " + bundle.getSymbolicName()); return null; - } } } - - /** - * @param bundle - * @return + * */ private static ClassLoader internalGetEquinoxBundleClassLoader(Bundle bundle) { @@ -215,18 +210,18 @@ public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper { if (Equinox_BundleHost_getBundleLoader_method == null) { - Equinox_BundleHost_getBundleLoader_method = - Equinox_BundleHost_Class.getDeclaredMethod("getBundleLoader", new Class[] {}); + Equinox_BundleHost_getBundleLoader_method = + Equinox_BundleHost_Class.getDeclaredMethod("getBundleLoader"); Equinox_BundleHost_getBundleLoader_method.setAccessible(true); } - Object bundleLoader = Equinox_BundleHost_getBundleLoader_method.invoke(bundle, new Object[] {}); + Object bundleLoader = Equinox_BundleHost_getBundleLoader_method.invoke(bundle); if (Equinox_BundleLoader_createClassLoader_method == null && bundleLoader != null) { - Equinox_BundleLoader_createClassLoader_method = - bundleLoader.getClass().getClassLoader().loadClass("org.eclipse.osgi.internal.loader.BundleLoader").getDeclaredMethod("createClassLoader", new Class[] {}); + Equinox_BundleLoader_createClassLoader_method = + bundleLoader.getClass().getClassLoader().loadClass("org.eclipse.osgi.internal.loader.BundleLoader").getDeclaredMethod("createClassLoader"); Equinox_BundleLoader_createClassLoader_method.setAccessible(true); } - return (ClassLoader) Equinox_BundleLoader_createClassLoader_method.invoke(bundleLoader, new Object[] {}); + return (ClassLoader)Equinox_BundleLoader_createClassLoader_method.invoke(bundleLoader, new Object[]{}); } catch (ClassNotFoundException t) { @@ -239,16 +234,18 @@ public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper return null; } } - + if (osgiContainer == OSGiContainerType.EquinoxLuna) { try { if (Equinox_EquinoxBundle_getModuleClassLoader_Method == null) - Equinox_EquinoxBundle_getModuleClassLoader_Method = Equinox_EquinoxBundle_Class.getDeclaredMethod("getModuleClassLoader", new Class[] {Boolean.TYPE}); + Equinox_EquinoxBundle_getModuleClassLoader_Method = Equinox_EquinoxBundle_Class.getDeclaredMethod("getModuleClassLoader", Boolean.TYPE); Equinox_EquinoxBundle_getModuleClassLoader_Method.setAccessible(true); - return (ClassLoader)Equinox_EquinoxBundle_getModuleClassLoader_Method.invoke(bundle, new Object[] {Boolean.FALSE}); + return (ClassLoader)Equinox_EquinoxBundle_getModuleClassLoader_Method.invoke(bundle, new Object[]{ + Boolean.FALSE + }); } catch (Exception e) { @@ -256,22 +253,18 @@ public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper return null; } } - - LOG.warn("No classloader for equinox platform for bundle "+bundle.getSymbolicName()); + + LOG.warn("No classloader for equinox platform for bundle " + bundle.getSymbolicName()); return null; } - - - /** - * @param bundle - * @return + * */ @SuppressWarnings("unchecked") private static ClassLoader internalGetFelixBundleClassLoader(Bundle bundle) { - + if (osgiContainer == OSGiContainerType.Felix403) { try @@ -279,7 +272,6 @@ public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper if (Felix_BundleWiring_Class == null) Felix_BundleWiring_Class = bundle.getClass().getClassLoader().loadClass("org.osgi.framework.wiring.BundleWiring"); - Felix_BundleImpl_Adapt_Method.setAccessible(true); if (Felix_BundleWiring_getClassLoader_Method == null) @@ -288,8 +280,7 @@ public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper Felix_BundleWiring_getClassLoader_Method.setAccessible(true); } - - Object wiring = Felix_BundleImpl_Adapt_Method.invoke(bundle, new Object[] {Felix_BundleWiring_Class}); + Object wiring = Felix_BundleImpl_Adapt_Method.invoke(bundle, Felix_BundleWiring_Class); return (ClassLoader)Felix_BundleWiring_getClassLoader_Method.invoke(wiring); } catch (Exception e) @@ -299,9 +290,8 @@ public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper } } - if (osgiContainer == OSGiContainerType.FelixOld) - { + { try { if (Felix_BundleImpl_m_Modules_Field == null) @@ -315,14 +305,14 @@ public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper try { - Object[] moduleArray = (Object[]) Felix_BundleImpl_m_Modules_Field.get(bundle); + Object[] moduleArray = (Object[])Felix_BundleImpl_m_Modules_Field.get(bundle); currentModuleImpl = moduleArray[moduleArray.length - 1]; } - catch (Throwable t2) + catch (Throwable ex) { try { - List moduleArray = (List) Felix_BundleImpl_m_Modules_Field.get(bundle); + List moduleArray = (List)Felix_BundleImpl_m_Modules_Field.get(bundle); currentModuleImpl = moduleArray.get(moduleArray.size() - 1); } catch (Exception e) @@ -352,7 +342,7 @@ public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper ClassLoader cl = null; try { - cl = (ClassLoader) Felix_ModuleImpl_m_ClassLoader_Field.get(currentModuleImpl); + cl = (ClassLoader)Felix_ModuleImpl_m_ClassLoader_Field.get(currentModuleImpl); if (cl != null) return cl; } @@ -369,7 +359,7 @@ public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper try { bundle.loadClass("java.lang.Object"); - cl = (ClassLoader) Felix_ModuleImpl_m_ClassLoader_Field.get(currentModuleImpl); + cl = (ClassLoader)Felix_ModuleImpl_m_ClassLoader_Field.get(currentModuleImpl); return cl; } catch (Exception e) @@ -377,21 +367,20 @@ public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper LOG.warn(e); return null; } - } + } catch (Exception e) { LOG.warn(e); return null; } } - - LOG.warn("No classloader for felix platform for bundle "+bundle.getSymbolicName()); + + LOG.warn("No classloader for felix platform for bundle " + bundle.getSymbolicName()); return null; } - + /** - * @param bundle - * @return + * */ private static ClassLoader internalGetConciergeBundleClassLoader(Bundle bundle) { @@ -399,33 +388,34 @@ public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper { try { - /** + /** * In Concierge: - * + * * Option A: *
                          * Concierge concierge = new Concierge(...);
                          * BundleWiring bundleWiring = concierge.getWiring(); // method is public
                          * 
        * Problem: getWiring not yet implementd - * + * * Option B: *
                          * Concierge concierge = new Concierge(...);
                          * BundleWiring bundleWiring = concierge.adapt(org.osgi.framework.wiring.BundleWiring);
                          * 
        * Same approach as done in Felix. - * + * */ - if (Concierge_BundleWiring_Class == null) { + if (Concierge_BundleWiring_Class == null) + { Concierge_BundleWiring_Class = bundle.getClass().getClassLoader().loadClass("org.osgi.framework.wiring.BundleWiring"); - Concierge_BundleImpl_Adapt_Method = Concierge_BundleImpl_Class.getMethod("adapt", new Class[] {Class.class}); + Concierge_BundleImpl_Adapt_Method = Concierge_BundleImpl_Class.getMethod("adapt", Class.class); Concierge_BundleImpl_Adapt_Method.setAccessible(true); Concierge_BundleWiring_getClassLoader_Method = Concierge_BundleWiring_Class.getMethod("getClassLoader"); Concierge_BundleWiring_getClassLoader_Method.setAccessible(true); } - Object wiring = Concierge_BundleImpl_Adapt_Method.invoke(bundle, new Object[] {Concierge_BundleWiring_Class}); + Object wiring = Concierge_BundleImpl_Adapt_Method.invoke(bundle, Concierge_BundleWiring_Class); ClassLoader cl = (ClassLoader)Concierge_BundleWiring_getClassLoader_Method.invoke(wiring); return cl; } @@ -436,7 +426,7 @@ public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper } } - LOG.warn("No classloader for Concierge platform for bundle "+bundle.getSymbolicName()); + LOG.warn("No classloader for Concierge platform for bundle " + bundle.getSymbolicName()); return null; } } diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultFileLocatorHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultFileLocatorHelper.java index 96c2b6cc1a0..43c69b5d598 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultFileLocatorHelper.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultFileLocatorHelper.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -37,7 +37,7 @@ import org.osgi.framework.Bundle; /** * DefaultFileLocatorHelper - *

        + *

        * From a bundle to its location on the filesystem. Assumes the bundle is not a * jar. */ @@ -59,30 +59,38 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper // DirZipBundleEntry private static Field ZIP_FILE_FILED_FOR_ZIP_BUNDLE_FILE = null;// ZipFile - - private static final String[] FILE_BUNDLE_ENTRY_CLASSES = {"org.eclipse.osgi.baseadaptor.bundlefile.FileBundleEntry","org.eclipse.osgi.storage.bundlefile.FileBundleEntry"}; - private static final String[] ZIP_BUNDLE_ENTRY_CLASSES = {"org.eclipse.osgi.baseadaptor.bundlefile.ZipBundleEntry","org.eclipse.osgi.storage.bundlefile.ZipBundleEntry"}; - private static final String[] DIR_ZIP_BUNDLE_ENTRY_CLASSES = {"org.eclipse.osgi.baseadaptor.bundlefile.DirZipBundleEntry","org.eclipse.osgi.storage.bundlefile.DirZipBundleEntry"}; - private static final String[] BUNDLE_URL_CONNECTION_CLASSES = {"org.eclipse.osgi.framework.internal.core.BundleURLConnection", "org.eclipse.osgi.storage.url.BundleURLConnection"}; + private static final String[] FILE_BUNDLE_ENTRY_CLASSES = { + "org.eclipse.osgi.baseadaptor.bundlefile.FileBundleEntry", "org.eclipse.osgi.storage.bundlefile.FileBundleEntry" + }; + private static final String[] ZIP_BUNDLE_ENTRY_CLASSES = { + "org.eclipse.osgi.baseadaptor.bundlefile.ZipBundleEntry", "org.eclipse.osgi.storage.bundlefile.ZipBundleEntry" + }; + private static final String[] DIR_ZIP_BUNDLE_ENTRY_CLASSES = { + "org.eclipse.osgi.baseadaptor.bundlefile.DirZipBundleEntry", "org.eclipse.osgi.storage.bundlefile.DirZipBundleEntry" + }; + private static final String[] BUNDLE_URL_CONNECTION_CLASSES = { + "org.eclipse.osgi.framework.internal.core.BundleURLConnection", "org.eclipse.osgi.storage.url.BundleURLConnection" + }; - public static boolean match (String name, String... names) + public static boolean match(String name, String... names) { if (name == null || names == null) return false; boolean matched = false; - for (int i=0; i< names.length && !matched; i++) + for (int i = 0; i < names.length && !matched; i++) + { if (name.equals(names[i])) matched = true; + } return matched; } - - + /** * Works with equinox, felix, nuxeo and probably more. Not exactly in the * spirit of OSGi but quite necessary to support self-contained webapps and * other situations. - * + * * @param bundle The bundle * @return Its installation location as a file. * @throws Exception if unable to get the bundle install location @@ -122,7 +130,7 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper BUNDLE_ENTRY_FIELD.setAccessible(true); } Object bundleEntry = BUNDLE_ENTRY_FIELD.get(con); - + if (match(bundleEntry.getClass().getName(), FILE_BUNDLE_ENTRY_CLASSES)) { if (FILE_FIELD == null) @@ -130,7 +138,7 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper FILE_FIELD = bundleEntry.getClass().getDeclaredField("file"); FILE_FIELD.setAccessible(true); } - File f = (File) FILE_FIELD.get(bundleEntry); + File f = (File)FILE_FIELD.get(bundleEntry); return f.getParentFile().getParentFile().getCanonicalFile(); } else if (match(bundleEntry.getClass().getName(), ZIP_BUNDLE_ENTRY_CLASSES)) @@ -141,7 +149,8 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper con.setDefaultUseCaches(Resource.getDefaultUseCaches()); if (BUNDLE_ENTRY_FIELD == null) - {// this one will be a DirZipBundleEntry + { + // this one will be a DirZipBundleEntry BUNDLE_ENTRY_FIELD = con.getClass().getDeclaredField("bundleEntry"); BUNDLE_ENTRY_FIELD.setAccessible(true); } @@ -157,10 +166,10 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper ZIP_FILE_FILED_FOR_ZIP_BUNDLE_FILE = zipBundleFile.getClass().getDeclaredField("zipFile"); ZIP_FILE_FILED_FOR_ZIP_BUNDLE_FILE.setAccessible(true); } - ZipFile zipFile = (ZipFile) ZIP_FILE_FILED_FOR_ZIP_BUNDLE_FILE.get(zipBundleFile); + ZipFile zipFile = (ZipFile)ZIP_FILE_FILED_FOR_ZIP_BUNDLE_FILE.get(zipBundleFile); return new File(zipFile.getName()); } - else if (match (bundleEntry.getClass().getName(), DIR_ZIP_BUNDLE_ENTRY_CLASSES)) + else if (match(bundleEntry.getClass().getName(), DIR_ZIP_BUNDLE_ENTRY_CLASSES)) { // that will not happen as we did ask for the manifest not a // directory. @@ -181,18 +190,20 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper // it is relative to relative to the BundleArchive's // m_archiveRootDir File res = new File(location.substring("file:".length())); - if (!res.exists()) { return null; - // Object bundleArchive = getFelixBundleArchive(bundle); - // File archiveRoot = - // getFelixBundleArchiveRootDir(bundleArchive); - // String currentLocation = - // getFelixBundleArchiveCurrentLocation(bundleArchive); - // System.err.println("Got the archive root " + - // archiveRoot.getAbsolutePath() - // + " current location " + currentLocation + - // " is directory ?"); - // res = new File(archiveRoot, currentLocation != null - // ? currentLocation : location.substring("file:".length())); + if (!res.exists()) + { + return null; + // Object bundleArchive = getFelixBundleArchive(bundle); + // File archiveRoot = + // getFelixBundleArchiveRootDir(bundleArchive); + // String currentLocation = + // getFelixBundleArchiveCurrentLocation(bundleArchive); + // System.err.println("Got the archive root " + + // archiveRoot.getAbsolutePath() + // + " current location " + currentLocation + + // " is directory ?"); + // res = new File(archiveRoot, currentLocation != null + // ? currentLocation : location.substring("file:".length())); } return res; } @@ -208,7 +219,7 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper /** * Locate a file inside a bundle. - * + * * @param bundle the bundle * @param path the path * @return file object @@ -223,12 +234,11 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper } File bundleInstall = getBundleInstallLocation(bundle); File webapp = path != null && path.length() != 0 ? new File(bundleInstall, path) : bundleInstall; - if (!webapp.exists()) { throw new IllegalArgumentException("Unable to locate " + path - + " inside " - + bundle.getSymbolicName() - + " (" - + (bundleInstall != null ? bundleInstall.getAbsolutePath() : " no_bundle_location ") - + ")"); } + if (!webapp.exists()) + { + throw new IllegalArgumentException("Unable to locate " + path + " inside " + bundle.getSymbolicName() + + " (" + (bundleInstall != null ? bundleInstall.getAbsolutePath() : " no_bundle_location ") + ")"); + } return webapp; } @@ -236,7 +246,7 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper * Helper method equivalent to Bundle#getEntry(String entryPath) except that * it searches for entries in the fragments by using the Bundle#findEntries * method. - * + * * @param bundle the bundle * @param entryPath the entry path * @return null or all the entries found for that path. @@ -265,10 +275,10 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper * development purpose where the bundle was imported in pde and the classes * kept in a jar. *

        - * + * * @param bundle the bundle * @return The jar(s) file that is either the bundle itself, either the jars - * embedded inside it. + * embedded inside it. */ @Override public File[] locateJarsInsideBundle(Bundle bundle) throws Exception @@ -299,7 +309,7 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper } else { - return new File[] { jasperLocation }; + return new File[]{jasperLocation}; } } @@ -318,12 +328,12 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper * Get a URL to the bundle entry that uses a common protocol (i.e. file: * jar: or http: etc.). *

        - * + * * @return a URL to the bundle entry that uses a common protocol */ @Override public URL getLocalURL(URL url) - throws Exception + throws Exception { if ("bundleresource".equals(url.getProtocol()) || "bundleentry".equals(url.getProtocol())) { @@ -335,7 +345,10 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper BUNDLE_URL_CONNECTION_getLocalURL = conn.getClass().getMethod("getLocalURL"); BUNDLE_URL_CONNECTION_getLocalURL.setAccessible(true); } - if (BUNDLE_URL_CONNECTION_getLocalURL != null) { return (URL) BUNDLE_URL_CONNECTION_getLocalURL.invoke(conn); } + if (BUNDLE_URL_CONNECTION_getLocalURL != null) + { + return (URL)BUNDLE_URL_CONNECTION_getLocalURL.invoke(conn); + } } return url; } @@ -347,32 +360,31 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper * Get a URL to the content of the bundle entry that uses the file: * protocol. The content of the bundle entry may be downloaded or extracted * to the local file system in order to create a file: URL. - * + * * @return a URL to the content of the bundle entry that uses the file: - * protocol - *

        - * @throws Exception if unable to get the file url + * protocol + *

        + * @throws Exception if unable to get the file url */ @Override public URL getFileURL(URL url) throws Exception - + { if ("bundleresource".equals(url.getProtocol()) || "bundleentry".equals(url.getProtocol())) { URLConnection conn = url.openConnection(); conn.setDefaultUseCaches(Resource.getDefaultUseCaches()); - if (BUNDLE_URL_CONNECTION_getFileURL == null - && - match (conn.getClass().getName(), BUNDLE_URL_CONNECTION_CLASSES)) + if (BUNDLE_URL_CONNECTION_getFileURL == null && match(conn.getClass().getName(), BUNDLE_URL_CONNECTION_CLASSES)) { BUNDLE_URL_CONNECTION_getFileURL = conn.getClass().getMethod("getFileURL"); BUNDLE_URL_CONNECTION_getFileURL.setAccessible(true); } - if (BUNDLE_URL_CONNECTION_getFileURL != null) { return (URL) BUNDLE_URL_CONNECTION_getFileURL.invoke(conn); } - + if (BUNDLE_URL_CONNECTION_getFileURL != null) + { + return (URL)BUNDLE_URL_CONNECTION_getFileURL.invoke(conn); + } } return url; } - } diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/PackageAdminServiceTracker.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/PackageAdminServiceTracker.java index 50616767cee..3a4eafd739a 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/PackageAdminServiceTracker.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/PackageAdminServiceTracker.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -39,7 +39,7 @@ import org.osgi.service.startlevel.StartLevel; *

        * When the PackageAdmin service is activated we can look for the fragments * attached to this bundle and do a fake "activate" on them. - *

        + *

        * See particularly the jetty-osgi-boot-jsp fragment bundle that uses this * facility. */ @@ -83,12 +83,13 @@ public class PackageAdminServiceTracker implements ServiceListener { ServiceReference sr = _context.getServiceReference(PackageAdmin.class.getName()); _fragmentsWereActivated = sr != null; - if (sr != null) invokeFragmentActivators(sr); + if (sr != null) + invokeFragmentActivators(sr); sr = _context.getServiceReference(StartLevel.class.getName()); if (sr != null) { - _startLevel = (StartLevel) _context.getService(sr); + _startLevel = (StartLevel)_context.getService(sr); try { _maxStartLevel = Integer.parseInt(System.getProperty("osgi.startLevel", "6")); @@ -107,7 +108,7 @@ public class PackageAdminServiceTracker implements ServiceListener * bundle activator for a fragment must be in the package that is defined by * the symbolic name of the fragment and the name of the class must be * 'FragmentActivator'. - * + * * @param event The ServiceEvent object. */ @Override @@ -123,7 +124,7 @@ public class PackageAdminServiceTracker implements ServiceListener * Helper to access the PackageAdmin and return the fragments hosted by a * bundle. when we drop the support for the older versions of OSGi, we will * stop using the PackageAdmin service. - * + * * @param bundle the bundle * @return the bundle fragment list */ @@ -131,10 +132,11 @@ public class PackageAdminServiceTracker implements ServiceListener { ServiceReference sr = _context.getServiceReference(PackageAdmin.class.getName()); if (sr == null) - {// we should never be here really. + { + // we should never be here really. return null; } - PackageAdmin admin = (PackageAdmin) _context.getService(sr); + PackageAdmin admin = (PackageAdmin)_context.getService(sr); return admin.getFragments(bundle); } @@ -142,7 +144,7 @@ public class PackageAdminServiceTracker implements ServiceListener * Returns the fragments and the required-bundles of a bundle. Recursively * collect the required-bundles and fragment when the directive * visibility:=reexport is added to a required-bundle. - * + * * @param bundle the bundle * @return the bundle fragment and required list */ @@ -150,10 +152,11 @@ public class PackageAdminServiceTracker implements ServiceListener { ServiceReference sr = _context.getServiceReference(PackageAdmin.class.getName()); if (sr == null) - {// we should never be here really. + { + // we should never be here really. return null; } - PackageAdmin admin = (PackageAdmin) _context.getService(sr); + PackageAdmin admin = (PackageAdmin)_context.getService(sr); LinkedHashMap deps = new LinkedHashMap<>(); collectFragmentsAndRequiredBundles(bundle, admin, deps, false); return deps.values().toArray(new Bundle[deps.size()]); @@ -163,14 +166,14 @@ public class PackageAdminServiceTracker implements ServiceListener * Returns the fragments and the required-bundles. Collects them * transitively when the directive 'visibility:=reexport' is added to a * required-bundle. - * + * * @param bundle the bundle * @param admin the admin package * @param deps The map of fragment and required bundles associated to the value of the - * jetty-web attribute. + * jetty-web attribute. * @param onlyReexport true to collect resources and web-fragments - * transitively if and only if the directive visibility is - * reexport. + * transitively if and only if the directive visibility is + * reexport. */ protected void collectFragmentsAndRequiredBundles(Bundle bundle, PackageAdmin admin, Map deps, boolean onlyReexport) { @@ -195,19 +198,22 @@ public class PackageAdminServiceTracker implements ServiceListener /** * A simplistic but good enough parser for the Require-Bundle header. Parses * the version range attribute and the visibility directive. - * + * * @param bundle the bundle - * @param admin the admin package + * @param admin the admin package * @param deps The map of required bundles associated to the value of the - * jetty-web attribute. + * jetty-web attribute. * @param onlyReexport true to collect resources and web-fragments - * transitively if and only if the directive visibility is - * reexport. + * transitively if and only if the directive visibility is + * reexport. */ protected void collectRequiredBundles(Bundle bundle, PackageAdmin admin, Map deps, boolean onlyReexport) { - String requiredBundleHeader = (String) bundle.getHeaders().get("Require-Bundle"); - if (requiredBundleHeader == null) { return; } + String requiredBundleHeader = (String)bundle.getHeaders().get("Require-Bundle"); + if (requiredBundleHeader == null) + { + return; + } StringTokenizer tokenizer = new ManifestTokenizer(requiredBundleHeader); while (tokenizer.hasMoreTokens()) { @@ -241,7 +247,10 @@ public class PackageAdminServiceTracker implements ServiceListener reexport = true; } } - if (!reexport && onlyReexport) { return; } + if (!reexport && onlyReexport) + { + return; + } Bundle[] reqBundles = admin.getBundles(symbolicName, versionRange); if (reqBundles != null && reqBundles.length != 0) { @@ -268,9 +277,12 @@ public class PackageAdminServiceTracker implements ServiceListener private void invokeFragmentActivators(ServiceReference sr) { - PackageAdmin admin = (PackageAdmin) _context.getService(sr); + PackageAdmin admin = (PackageAdmin)_context.getService(sr); Bundle[] fragments = admin.getFragments(_context.getBundle()); - if (fragments == null) { return; } + if (fragments == null) + { + return; + } for (Bundle frag : fragments) { // find a convention to look for a class inside the fragment. @@ -280,7 +292,7 @@ public class PackageAdminServiceTracker implements ServiceListener Class c = Class.forName(fragmentActivator); if (c != null) { - BundleActivator bActivator = (BundleActivator) c.getDeclaredConstructor().newInstance(); + BundleActivator bActivator = (BundleActivator)c.getDeclaredConstructor().newInstance(); bActivator.start(_context); _activatedFragments.add(bActivator); } @@ -313,7 +325,7 @@ public class PackageAdminServiceTracker implements ServiceListener */ public boolean frameworkHasCompletedAutostarts() { - return _startLevel == null ? true : _startLevel.getStartLevel() >= _maxStartLevel; + return _startLevel == null || _startLevel.getStartLevel() >= _maxStartLevel; } private static class ManifestTokenizer extends StringTokenizer @@ -342,7 +354,10 @@ public class PackageAdminServiceTracker implements ServiceListener do { int quote = getQuote(token, i + 1); - if (quote < 0) { return false; } + if (quote < 0) + { + return false; + } i = token.indexOf(quote, i + 1); i = token.indexOf(quote, i + 1); @@ -366,12 +381,16 @@ public class PackageAdminServiceTracker implements ServiceListener return '\''; } } - if (j < 0) { return '"'; } - if (i < j) { return '"'; } + if (j < 0) + { + return '"'; + } + if (i < j) + { + return '"'; + } return '\''; } - } - } diff --git a/jetty-osgi/jetty-osgi-httpservice/build.properties b/jetty-osgi/jetty-osgi-httpservice/build.properties deleted file mode 100644 index 5fc538bc83f..00000000000 --- a/jetty-osgi/jetty-osgi-httpservice/build.properties +++ /dev/null @@ -1,4 +0,0 @@ -source.. = src/main/java/ -output.. = target/classes/ -bin.includes = META-INF/,\ - . diff --git a/jetty-osgi/jetty-osgi-httpservice/contexts/httpservice.xml b/jetty-osgi/jetty-osgi-httpservice/contexts/httpservice.xml index 98c00314b90..950a6243eec 100644 --- a/jetty-osgi/jetty-osgi-httpservice/contexts/httpservice.xml +++ b/jetty-osgi/jetty-osgi-httpservice/contexts/httpservice.xml @@ -1,5 +1,4 @@ - - + diff --git a/jetty-osgi/jetty-osgi-httpservice/pom.xml b/jetty-osgi/jetty-osgi-httpservice/pom.xml index 332d259616c..eb289b09feb 100644 --- a/jetty-osgi/jetty-osgi-httpservice/pom.xml +++ b/jetty-osgi/jetty-osgi-httpservice/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 jetty-httpservice @@ -46,7 +46,7 @@ - + @@ -57,24 +57,19 @@ - org.apache.felix - maven-bundle-plugin - true - - - org.eclipse.jetty.osgi.httpservice - OSGi HttpService - contexts/httpservice.xml - org.eclipse.jetty.server.handler;version="[9.1,10.0)", -org.eclipse.jetty.util.component;version="[9.1,10.0)", -org.eclipse.jetty.server.session;version="[9.1,10.0)", -org.eclipse.jetty.servlet;version="[9.1,10.0)", -org.eclipse.equinox.http.servlet, -* - - <_nouses>true - - + org.apache.felix + maven-bundle-plugin + true + + + org.eclipse.jetty.osgi.httpservice + OSGi HttpService + contexts/httpservice.xml + org.eclipse.jetty.server.handler;version="[9.1,10.0)", org.eclipse.jetty.util.component;version="[9.1,10.0)", org.eclipse.jetty.server.session;version="[9.1,10.0)", org.eclipse.jetty.servlet;version="[9.1,10.0)", org.eclipse.equinox.http.servlet, * + + <_nouses>true + + org.codehaus.mojo diff --git a/jetty-osgi/jetty-osgi-httpservice/src/main/java/org/eclipse/jetty/osgi/httpservice/HttpServiceErrorHandlerHelper.java b/jetty-osgi/jetty-osgi-httpservice/src/main/java/org/eclipse/jetty/osgi/httpservice/HttpServiceErrorHandlerHelper.java index 83089f4de1c..e14208c6212 100644 --- a/jetty-osgi/jetty-osgi-httpservice/src/main/java/org/eclipse/jetty/osgi/httpservice/HttpServiceErrorHandlerHelper.java +++ b/jetty-osgi/jetty-osgi-httpservice/src/main/java/org/eclipse/jetty/osgi/httpservice/HttpServiceErrorHandlerHelper.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -30,16 +30,15 @@ import javax.servlet.http.HttpServlet; */ public class HttpServiceErrorHandlerHelper { - private static HttpServlet _customErrorHandler; + private static HttpServlet _customErrorHandler; - public static HttpServlet getCustomErrorHandler() - { - return _customErrorHandler; - } - - public static void setHttpServiceErrorHandler(HttpServlet servlet) - { - _customErrorHandler = servlet; - } - + public static HttpServlet getCustomErrorHandler() + { + return _customErrorHandler; + } + + public static void setHttpServiceErrorHandler(HttpServlet servlet) + { + _customErrorHandler = servlet; + } } diff --git a/jetty-osgi/jetty-osgi-httpservice/src/main/java/org/eclipse/jetty/osgi/httpservice/HttpServiceErrorPageErrorHandler.java b/jetty-osgi/jetty-osgi-httpservice/src/main/java/org/eclipse/jetty/osgi/httpservice/HttpServiceErrorPageErrorHandler.java index eedbf6ecaf0..85e22fb065c 100644 --- a/jetty-osgi/jetty-osgi-httpservice/src/main/java/org/eclipse/jetty/osgi/httpservice/HttpServiceErrorPageErrorHandler.java +++ b/jetty-osgi/jetty-osgi-httpservice/src/main/java/org/eclipse/jetty/osgi/httpservice/HttpServiceErrorPageErrorHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -19,7 +19,6 @@ package org.eclipse.jetty.osgi.httpservice; import java.io.IOException; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -35,46 +34,44 @@ import org.eclipse.jetty.servlet.ErrorPageErrorHandler; public class HttpServiceErrorPageErrorHandler extends ErrorPageErrorHandler { - private static HttpServiceErrorPageErrorHandler INSTANCE; - - public static HttpServiceErrorPageErrorHandler getInstance() - { - return INSTANCE; - } - - public HttpServiceErrorPageErrorHandler() - { - INSTANCE = this; - } + private static HttpServiceErrorPageErrorHandler INSTANCE; - @Override - public void handle(String target, Request baseRequest, - HttpServletRequest request, HttpServletResponse response) - throws IOException { - if (HttpServiceErrorHandlerHelper.getCustomErrorHandler() != null) - { - try - { - HttpServiceErrorHandlerHelper.getCustomErrorHandler().service(request, response); - } - catch (ServletException e) - { - //well - } - } - if (!response.isCommitted()) - { - super.handle(target, baseRequest, request, response); - } - } + public static HttpServiceErrorPageErrorHandler getInstance() + { + return INSTANCE; + } - @Override - protected void doStop() throws Exception + public HttpServiceErrorPageErrorHandler() + { + INSTANCE = this; + } + + @Override + public void handle(String target, Request baseRequest, + HttpServletRequest request, HttpServletResponse response) + throws IOException + { + if (HttpServiceErrorHandlerHelper.getCustomErrorHandler() != null) { - INSTANCE = null; - super.doStop(); + try + { + HttpServiceErrorHandlerHelper.getCustomErrorHandler().service(request, response); + } + catch (ServletException e) + { + //well + } } - - - + if (!response.isCommitted()) + { + super.handle(target, baseRequest, request, response); + } + } + + @Override + protected void doStop() throws Exception + { + INSTANCE = null; + super.doStop(); + } } diff --git a/jetty-osgi/pom.xml b/jetty-osgi/pom.xml index 090cc250a42..02d730c721e 100644 --- a/jetty-osgi/pom.xml +++ b/jetty-osgi/pom.xml @@ -1,10 +1,8 @@ - + org.eclipse.jetty jetty-project - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 @@ -39,15 +37,15 @@ META-INF/.. true - **/.* - **/*.jar - .settings/**/* - pom.xml - - jettyhome/**/* - src/**/* - target/**/* - build.properties + **/.* + **/*.jar + .settings/**/* + pom.xml + + jettyhome/**/* + src/**/* + target/**/* + build.properties META-INF/**/* @@ -56,7 +54,7 @@ src/main/java - **/*.java + **/*.java @@ -145,6 +143,11 @@ javax.servlet servlet-api + + + org.apache.felix + org.osgi.foundation + diff --git a/jetty-osgi/test-jetty-osgi-context/pom.xml b/jetty-osgi/test-jetty-osgi-context/pom.xml index 69146e5f38a..96d11a85eee 100644 --- a/jetty-osgi/test-jetty-osgi-context/pom.xml +++ b/jetty-osgi/test-jetty-osgi-context/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 test-jetty-osgi-context @@ -49,7 +49,7 @@ org.apache.maven.plugins maven-deploy-plugin - + true diff --git a/jetty-osgi/test-jetty-osgi-context/src/main/context/acme.xml b/jetty-osgi/test-jetty-osgi-context/src/main/context/acme.xml index f6c5cf581a6..5186cf99343 100644 --- a/jetty-osgi/test-jetty-osgi-context/src/main/context/acme.xml +++ b/jetty-osgi/test-jetty-osgi-context/src/main/context/acme.xml @@ -1,5 +1,4 @@ - - + diff --git a/jetty-osgi/test-jetty-osgi-context/src/main/java/com/acme/osgi/Activator.java b/jetty-osgi/test-jetty-osgi-context/src/main/java/com/acme/osgi/Activator.java index 3abe2a26536..95e5ff8632a 100644 --- a/jetty-osgi/test-jetty-osgi-context/src/main/java/com/acme/osgi/Activator.java +++ b/jetty-osgi/test-jetty-osgi-context/src/main/java/com/acme/osgi/Activator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -20,7 +20,6 @@ package com.acme.osgi; import java.util.Dictionary; import java.util.Hashtable; - import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; @@ -31,27 +30,26 @@ import org.osgi.framework.ServiceRegistration; /** * Bootstrap a ContextHandler - * - * */ public class Activator implements BundleActivator { private ServiceRegistration _sr; + /** - * - * @param context + * */ @Override public void start(final BundleContext context) throws Exception { ContextHandler ch = new ContextHandler(); - ch.addEventListener(new ServletContextListener () { + ch.addEventListener(new ServletContextListener() + { @Override public void contextInitialized(ServletContextEvent sce) { - //System.err.println("Context is initialized"); + //System.err.println("Context is initialized"); } @Override @@ -59,19 +57,17 @@ public class Activator implements BundleActivator { //System.err.println("CONTEXT IS DESTROYED!"); } - }); Dictionary props = new Hashtable(); - props.put("contextPath","/acme"); + props.put("contextPath", "/acme"); props.put("Jetty-ContextFilePath", "acme.xml"); - _sr = context.registerService(ContextHandler.class.getName(),ch,props); + _sr = context.registerService(ContextHandler.class.getName(), ch, props); } /** * Stop the activator. - * - * @see - * org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) + * + * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) */ @Override public void stop(BundleContext context) throws Exception diff --git a/jetty-osgi/test-jetty-osgi-fragment/pom.xml b/jetty-osgi/test-jetty-osgi-fragment/pom.xml index 19e44564f78..6880f5faa34 100644 --- a/jetty-osgi/test-jetty-osgi-fragment/pom.xml +++ b/jetty-osgi/test-jetty-osgi-fragment/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT ../pom.xml 4.0.0 @@ -13,37 +13,37 @@ ${project.groupId}.webapp.fragment - - - - src/main/resources - - + + + + src/main/resources + + + + + + org.apache.maven.plugins + maven-deploy-plugin + + + true + + + + org.apache.felix + maven-bundle-plugin + true + + + ${bundle-symbolic-name} + Jetty OSGi Test WebApp Fragment + J2SE-1.5 + org.eclipse.jetty.tests.test-spec-webapp + / + + + + + - - - org.apache.maven.plugins - maven-deploy-plugin - - - true - - - - org.apache.felix - maven-bundle-plugin - true - - - ${bundle-symbolic-name} - Jetty OSGi Test WebApp Fragment - J2SE-1.5 -org.eclipse.jetty.tests.test-spec-webapp -/ - - - - - - diff --git a/jetty-osgi/test-jetty-osgi-server/pom.xml b/jetty-osgi/test-jetty-osgi-server/pom.xml index 57f376a32a1..685eb4a16f3 100644 --- a/jetty-osgi/test-jetty-osgi-server/pom.xml +++ b/jetty-osgi/test-jetty-osgi-server/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT 4.0.0 test-jetty-osgi-server @@ -15,7 +15,7 @@ org.eclipse.jetty - jetty-server + jetty-webapp ${project.version} @@ -40,7 +40,7 @@ org.apache.maven.plugins maven-deploy-plugin - + true diff --git a/jetty-osgi/test-jetty-osgi-server/src/main/java/com/acme/osgi/Activator.java b/jetty-osgi/test-jetty-osgi-server/src/main/java/com/acme/osgi/Activator.java index a45f567d57d..00e6d2b4dd0 100644 --- a/jetty-osgi/test-jetty-osgi-server/src/main/java/com/acme/osgi/Activator.java +++ b/jetty-osgi/test-jetty-osgi-server/src/main/java/com/acme/osgi/Activator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -21,38 +21,36 @@ package com.acme.osgi; import java.util.Dictionary; import java.util.Hashtable; -import org.eclipse.jetty.util.component.AbstractLifeCycle.AbstractLifeCycleListener; -import org.eclipse.jetty.util.component.LifeCycle; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.handler.ContextHandlerCollection; +import org.eclipse.jetty.util.component.AbstractLifeCycle.AbstractLifeCycleListener; +import org.eclipse.jetty.util.component.LifeCycle; +import org.eclipse.jetty.webapp.Configuration; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; /** * Bootstrap a Server - * - * */ public class Activator implements BundleActivator { private ServiceRegistration _sr; - + /** - * - * @param context + * */ @Override public void start(BundleContext context) throws Exception - { + { //For test purposes, use a random port Server server = new Server(0); server.getConnectors()[0].addLifeCycleListener(new AbstractLifeCycleListener() { - /** + /** * @see org.eclipse.jetty.util.component.AbstractLifeCycle.AbstractLifeCycleListener#lifeCycleStarted(org.eclipse.jetty.util.component.LifeCycle) */ @Override @@ -61,12 +59,21 @@ public class Activator implements BundleActivator System.setProperty("bundle.server.port", String.valueOf(((ServerConnector)event).getLocalPort())); super.lifeCycleStarted(event); } - - - }); ContextHandlerCollection contexts = new ContextHandlerCollection(); server.setHandler(contexts); + //server.setDumpAfterStart(true); + + Configuration.ClassList list = new Configuration.ClassList(new String[]{ + "org.eclipse.jetty.osgi.boot.OSGiWebInfConfiguration", + "org.eclipse.jetty.webapp.WebXmlConfiguration", + "org.eclipse.jetty.webapp.MetaInfConfiguration", + "org.eclipse.jetty.webapp.FragmentConfiguration", + "org.eclipse.jetty.webapp.JettyWebXmlConfiguration" + }); + server.addBean(list); + server.setAttribute("org.eclipse.jetty.webapp.configuration", list); + Configuration.ClassList.setServerDefault(server); Dictionary serverProps = new Hashtable(); //define the unique name of the server instance @@ -78,9 +85,8 @@ public class Activator implements BundleActivator /** * Stop the activator. - * - * @see - * org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) + * + * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) */ @Override public void stop(BundleContext context) throws Exception diff --git a/jetty-osgi/test-jetty-osgi-webapp/pom.xml b/jetty-osgi/test-jetty-osgi-webapp/pom.xml index 8eb88115390..55af869ba1b 100644 --- a/jetty-osgi/test-jetty-osgi-webapp/pom.xml +++ b/jetty-osgi/test-jetty-osgi-webapp/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT ../pom.xml 4.0.0 diff --git a/jetty-osgi/test-jetty-osgi-webapp/src/main/java/com/acme/osgi/Activator.java b/jetty-osgi/test-jetty-osgi-webapp/src/main/java/com/acme/osgi/Activator.java index c73ce4945bf..a3ac4a3d23a 100644 --- a/jetty-osgi/test-jetty-osgi-webapp/src/main/java/com/acme/osgi/Activator.java +++ b/jetty-osgi/test-jetty-osgi-webapp/src/main/java/com/acme/osgi/Activator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -22,13 +22,11 @@ import java.io.IOException; import java.io.PrintWriter; import java.util.Dictionary; import java.util.Hashtable; - import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.webapp.WebAppContext; import org.osgi.framework.BundleActivator; @@ -37,8 +35,6 @@ import org.osgi.framework.ServiceRegistration; /** * Bootstrap a webapp - * - * */ public class Activator implements BundleActivator { @@ -49,7 +45,7 @@ public class Activator implements BundleActivator public static class TestServlet extends HttpServlet { - /** + /** * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override @@ -59,17 +55,13 @@ public class Activator implements BundleActivator String mimetype = req.getServletContext().getMimeType("file.gz"); resp.setContentType("text/html"); PrintWriter writer = resp.getWriter(); - writer.write("

        MIMETYPE="+mimetype+"

        "); + writer.write("

        MIMETYPE=" + mimetype + "

        "); writer.flush(); } - } - - /** - * - * @param context + * */ @Override public void start(BundleContext context) throws Exception @@ -78,11 +70,11 @@ public class Activator implements BundleActivator WebAppContext webapp = new WebAppContext(); webapp.addServlet(new ServletHolder(new TestServlet()), "/mime"); Dictionary props = new Hashtable(); - props.put("war","webappA"); - props.put("contextPath","/acme"); + props.put("war", "webappA"); + props.put("contextPath", "/acme"); props.put("managedServerName", "defaultJettyServer"); - _srA = context.registerService(WebAppContext.class.getName(),webapp,props); - + _srA = context.registerService(WebAppContext.class.getName(), webapp, props); + //Create a second webappB as a Service and target it at a custom Server //deployed by another bundle WebAppContext webappB = new WebAppContext(); @@ -95,14 +87,13 @@ public class Activator implements BundleActivator /** * Stop the activator. - * - * @see - * org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) + * + * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) */ @Override public void stop(BundleContext context) throws Exception { - _srA.unregister(); + _srA.unregister(); _srB.unregister(); } } diff --git a/jetty-osgi/test-jetty-osgi/pom.xml b/jetty-osgi/test-jetty-osgi/pom.xml index f7efe0e8d6e..db75fe6195c 100644 --- a/jetty-osgi/test-jetty-osgi/pom.xml +++ b/jetty-osgi/test-jetty-osgi/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.4.13-SNAPSHOT + 9.4.21-SNAPSHOT ../pom.xml 4.0.0 @@ -14,8 +14,8 @@ ${project.groupId}.boot.test.osgi http://download.eclipse.org/jetty/orbit/ target/distribution - 4.11.0 - 2.5.2 + 4.13.1 + 2.6.1 1.0 true @@ -35,22 +35,28 @@ - org.ops4j.pax.exam - pax-exam-container-forked - ${exam.version} - test + org.ops4j.pax.exam + pax-exam-container-forked + ${exam.version} + test + + + org.ops4j.pax.swissbox + pax-swissbox-framework + 1.8.3 + test + + + org.ops4j.pax.swissbox + pax-swissbox-tracker + 1.8.3 + test org.ops4j.pax.exam pax-exam-junit4 ${exam.version} test - - - junit - junit - - org.ops4j.pax.exam @@ -75,23 +81,23 @@ bndlib 2.4.0 - - org.osgi - org.osgi.core - + + org.osgi + org.osgi.core + org.eclipse.platform org.eclipse.osgi - 3.12.50 + 3.13.100 test - org.eclipse.platform - org.eclipse.osgi.services - 3.6.0 - test + org.eclipse.platform + org.eclipse.osgi.services + 3.7.100 + test @@ -152,15 +158,27 @@ test - org.apache.aries.spifly + org.apache.aries.spifly org.apache.aries.spifly.dynamic.bundle - 1.0.10 - test + 1.2.3 + test + + + org.apache.felix + org.apache.felix.framework + + - org.glassfish.web - javax.servlet.jsp.jstl - 1.2.2 + com.sun.activation + javax.activation + 1.2.0 + test + + + org.glassfish.web + javax.servlet.jsp.jstl + 1.2.2 javax.servlet.jsp.jstl @@ -181,19 +199,19 @@ - org.eclipse.jetty.orbit - javax.servlet.jsp.jstl - 1.2.0.v201105211821 - - - org.eclipse.jetty.orbit - javax.servlet - - - org.eclipse.jetty.orbit - javax.servlet.jsp - - + org.eclipse.jetty.orbit + javax.servlet.jsp.jstl + 1.2.0.v201105211821 + + + org.eclipse.jetty.orbit + javax.servlet + + + org.eclipse.jetty.orbit + javax.servlet.jsp + + @@ -402,13 +420,11 @@ org.ow2.asm asm - ${asm.version} test org.ow2.asm asm-commons - ${asm.version} test @@ -433,8 +449,17 @@ ${skipTests} ${settings.localRepository} + ${env.GLOBAL_MVN_SETTINGS} + + + + org.apache.maven.surefire + surefire-junit47 + ${maven.surefire.version} + + @@ -521,16 +546,15 @@ - + maven-surefire-plugin - - **/TestJettyOSGiBootHTTP2JDK9* + **/TestJettyOSGiBootHTTP2JDK9* - -Dmortbay-alpn-boot=${settings.localRepository}/org/mortbay/jetty/alpn/alpn-boot/${alpn.version}/alpn-boot-${alpn.version}.jar + -Dmortbay-alpn-boot=${settings.localRepository}/org/mortbay/jetty/alpn/alpn-boot/${alpn.version}/alpn-boot-${alpn.version}.jar -Dconscrypt-version=${conscrypt.version} @@ -554,12 +578,6 @@ ${project.version} test - - org.conscrypt - conscrypt-openjdk-uber - 1.0.0.RC11 - test - org.eclipse.jetty jetty-alpn-java-server @@ -572,23 +590,24 @@ ${project.version} test - + false - - - - maven-surefire-plugin - - ${skipTests} - - **/TestJettyOSGiBootHTTP2 - - - - - + + + + maven-surefire-plugin + + ${skipTests} + + **/TestJettyOSGiBootHTTP2 + + -Dconscrypt-version=${conscrypt.version} + + + + diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-alpn.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-alpn.xml index 14f9a5b6d2d..79018dc96e4 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-alpn.xml +++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-alpn.xml @@ -1,5 +1,4 @@ - - + diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-deployer.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-deployer.xml index 19b3a5db090..d00c7995453 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-deployer.xml +++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-deployer.xml @@ -1,5 +1,4 @@ - - + diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-context-as-service.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-context-as-service.xml index 6a7fa8fd2fb..8e2360b85ca 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-context-as-service.xml +++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-context-as-service.xml @@ -1,15 +1,10 @@ - - + - - - - - + - + diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-webapp-as-service.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-webapp-as-service.xml index dc91ba73205..bccf90e1204 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-webapp-as-service.xml +++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-webapp-as-service.xml @@ -1,15 +1,10 @@ - - + - - - - - + - + diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-annotations.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-annotations.xml index 3c06b9a313e..eab6f8936c8 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-annotations.xml +++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-annotations.xml @@ -1,15 +1,10 @@ - - + - - - - - + - + diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-javax-websocket.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-javax-websocket.xml index 13ce3f3df5b..dca7d650b74 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-javax-websocket.xml +++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-javax-websocket.xml @@ -1,15 +1,10 @@ - - + - - - - - + - + diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-jsp.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-jsp.xml index b967a95795b..38b5a790496 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-jsp.xml +++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-jsp.xml @@ -1,15 +1,10 @@ - - + - - - - - + - + diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-websocket.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-websocket.xml index ecab2fe4198..e6857ba7b89 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-websocket.xml +++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http-boot-with-websocket.xml @@ -1,15 +1,10 @@ - - + - - - - - + - + diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http.xml index e2ca8266243..11c1650548d 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http.xml +++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http.xml @@ -1,15 +1,10 @@ - - + - - - - - + - + diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http2-jdk9.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http2-jdk9.xml index 2de7f348d0a..56777719fdf 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http2-jdk9.xml +++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http2-jdk9.xml @@ -1,9 +1,6 @@ - - + - - - + diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http2.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http2.xml index 2de7f348d0a..5e85f018046 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http2.xml +++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http2.xml @@ -1,9 +1,6 @@ - - + - - - + @@ -21,6 +18,13 @@ true + + + + TLSv1.3 + + + diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-https.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-https.xml index 75b77f7ec3c..30199cb8677 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-https.xml +++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-https.xml @@ -1,11 +1,6 @@ - - + - - - - - + diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-ssl.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-ssl.xml index 4a0e6245a83..d5743db1f8d 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-ssl.xml +++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-ssl.xml @@ -9,7 +9,7 @@ - + @@ -29,13 +29,12 @@ - + / / - diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-testrealm.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-testrealm.xml index a9d9987cb15..1c4077450a4 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-testrealm.xml +++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-testrealm.xml @@ -1,5 +1,4 @@ - - + diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty.xml index f47a40a2bc4..43e978db7f0 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty.xml +++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty.xml @@ -41,25 +41,34 @@ - - https - - 32768 - 8192 - 8192 - true - false - 4096 + + + + + + + + + + + + + + + + + + - true - 1000 - false - false + + + + diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/realm.properties b/jetty-osgi/test-jetty-osgi/src/test/config/etc/realm.properties index cbf905de9fb..a3badb04827 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/realm.properties +++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/realm.properties @@ -11,11 +11,11 @@ # If DIGEST Authentication is used, the password must be in a recoverable # format, either plain text or OBF:. # -jetty: MD5:164c88b302622e17050af52c89945d44,user -admin: CRYPT:adpexzg3FUZAk,server-administrator,content-administrator,admin -other: OBF:1xmk1w261u9r1w1c1xmq,user -plain: plain,user -user: password,user +jetty= MD5:164c88b302622e17050af52c89945d44,user +admin= CRYPT:adpexzg3FUZAk,server-administrator,content-administrator,admin +other= OBF:1xmk1w261u9r1w1c1xmq,user +plain= plain,user +user= password,user # This entry is for digest auth. The credential is a MD5 hash of username:realmname:password -digest: MD5:6e120743ad67abfbc385bc2bb754e297,user +digest= MD5:6e120743ad67abfbc385bc2bb754e297,user diff --git a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/SimpleEchoSocket.java b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/SimpleEchoSocket.java index 3c21433eb9e..e9efb00917b 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/SimpleEchoSocket.java +++ b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/SimpleEchoSocket.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -46,7 +46,7 @@ public class SimpleEchoSocket public boolean awaitClose(int duration, TimeUnit unit) throws InterruptedException { - return this.closeLatch.await(duration,unit); + return this.closeLatch.await(duration, unit); } @OnWebSocketClose @@ -68,10 +68,10 @@ public class SimpleEchoSocket //System.err.println("Sending Foo!"); fut = session.getRemote().sendStringByFuture("Foo"); - fut.get(2,TimeUnit.SECONDS); // wait for send to complete. + fut.get(2, TimeUnit.SECONDS); // wait for send to complete. //System.err.println("Foo complete"); - session.close(StatusCode.NORMAL,"I'm done"); + session.close(StatusCode.NORMAL, "I'm done"); } catch (Throwable t) { diff --git a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/SimpleJavaxWebSocket.java b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/SimpleJavaxWebSocket.java index cbea7817258..4dd450d77b7 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/SimpleJavaxWebSocket.java +++ b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/SimpleJavaxWebSocket.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,10 +18,7 @@ package org.eclipse.jetty.osgi.test; -import static org.junit.Assert.fail; - import java.util.concurrent.CountDownLatch; - import javax.websocket.ClientEndpoint; import javax.websocket.CloseReason; import javax.websocket.OnClose; @@ -30,19 +27,21 @@ import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; +import static org.junit.Assert.fail; + @ClientEndpoint( - subprotocols = { "chat"}) + subprotocols = {"chat"}) public class SimpleJavaxWebSocket { private Session session; public CountDownLatch messageLatch = new CountDownLatch(1); public CountDownLatch closeLatch = new CountDownLatch(1); - + @OnError - public void onError (Throwable t) + public void onError(Throwable t) { //t.printStackTrace(); - fail (t.getMessage()); + fail(t.getMessage()); } @OnClose diff --git a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootContextAsService.java b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootContextAsService.java index d897e8988b8..ee355731089 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootContextAsService.java +++ b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootContextAsService.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,21 +18,13 @@ package org.eclipse.jetty.osgi.test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.ops4j.pax.exam.CoreOptions.mavenBundle; -import static org.ops4j.pax.exam.CoreOptions.systemProperty; - import java.util.ArrayList; - import javax.inject.Inject; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.api.ContentResponse; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.server.handler.ContextHandler; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.ops4j.pax.exam.Configuration; @@ -43,20 +35,24 @@ import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.ops4j.pax.exam.CoreOptions.mavenBundle; +import static org.ops4j.pax.exam.CoreOptions.systemProperty; + /** * TestJettyOSGiBootContextAsService - * + * * Tests deployment of a ContextHandler as an osgi Service. - * + * * Tests the ServiceContextProvider. - * */ @RunWith(PaxExam.class) public class TestJettyOSGiBootContextAsService { private static final String LOG_LEVEL = "WARN"; - @Inject BundleContext bundleContext = null; @@ -74,26 +70,20 @@ public class TestJettyOSGiBootContextAsService options.add(mavenBundle().groupId("org.eclipse.jetty.osgi").artifactId("test-jetty-osgi-context").versionAsInProject().start()); options.add(systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value(LOG_LEVEL)); options.add(systemProperty("org.eclipse.jetty.LEVEL").value(LOG_LEVEL)); - options.add( systemProperty( "org.ops4j.pax.url.mvn.localRepository" ).value( System.getProperty( "mavenRepoPath" ) ) ); - + options.add(systemProperty("org.ops4j.pax.url.mvn.localRepository").value(System.getProperty("mavenRepoPath"))); + return options.toArray(new Option[options.size()]); } - - - - @Ignore - public void assertAllBundlesActiveOrResolved() - { - TestOSGiUtil.assertAllBundlesActiveOrResolved(bundleContext); - } - - /** + * */ @Test public void testContextHandlerAsOSGiService() throws Exception { + if (Boolean.getBoolean(TestOSGiUtil.BUNDLE_DEBUG)) + TestOSGiUtil.assertAllBundlesActiveOrResolved(bundleContext); + // now test the context HttpClient client = new HttpClient(); try @@ -116,7 +106,7 @@ public class TestJettyOSGiBootContextAsService ServiceReference[] refs = bundleContext.getServiceReferences(ContextHandler.class.getName(), null); assertNotNull(refs); assertEquals(1, refs.length); - ContextHandler ch = (ContextHandler) bundleContext.getService(refs[0]); + ContextHandler ch = (ContextHandler)bundleContext.getService(refs[0]); assertEquals("/acme", ch.getContextPath()); // Stop the bundle with the ContextHandler in it and check the jetty diff --git a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootHTTP2.java b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootHTTP2.java index bb6152af2e5..ac3331d0656 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootHTTP2.java +++ b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootHTTP2.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -18,20 +18,12 @@ package org.eclipse.jetty.osgi.test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.ops4j.pax.exam.CoreOptions.mavenBundle; -import static org.ops4j.pax.exam.CoreOptions.systemProperty; - import java.io.File; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executor; - import javax.inject.Inject; import org.eclipse.jetty.client.HttpClient; @@ -41,7 +33,6 @@ import org.eclipse.jetty.http2.client.HTTP2Client; import org.eclipse.jetty.http2.client.http.HttpClientTransportOverHTTP2; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.thread.QueuedThreadPool; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.ops4j.pax.exam.Configuration; @@ -54,29 +45,32 @@ import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; -/** - * HTTP2 setup. - */ +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.ops4j.pax.exam.CoreOptions.mavenBundle; +import static org.ops4j.pax.exam.CoreOptions.systemProperty; + @RunWith(PaxExam.class) @ExamReactorStrategy(PerClass.class) public class TestJettyOSGiBootHTTP2 { private static final String LOG_LEVEL = "WARN"; - @Inject private BundleContext bundleContext; @Configuration public Option[] config() { - ArrayList