diff --git a/.netflixoss b/.netflixoss
new file mode 100644
index 0000000000..f591e68404
--- /dev/null
+++ b/.netflixoss
@@ -0,0 +1,2 @@
+jdk=8
+
diff --git a/.travis.yml b/.travis.yml
index 03f48b5ce9..ee282a1ffb 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,5 +1,15 @@
language: java
jdk:
- - oraclejdk7
- - openjdk6
- - openjdk7
\ No newline at end of file
+- oraclejdk8
+sudo: false
+install: "./installViaTravis.sh"
+script: "./buildViaTravis.sh"
+cache:
+ directories:
+ - "$HOME/.gradle"
+env:
+ global:
+ - secure: eCJZsdb6dhCyD9qnxzabonrqSn02l+vtoYX/v3DED7AZi5SnbC7iloy7borBm3yz9xcd5ajxuke+Y9eLzLx79DfE9B8Z2/xL1Yx2xSIgFBD8FgFAq62Okdi71SYwP11yGIqLNf0FWmT5UCWZ94nN0QzX7pfagWc2LQ/r+EI+XVs=
+ - secure: WVfJ5Cix+pIY5BKek9YeaSRKRnUFZZ7WUTDcfQ+64N+BoU0QUMoFt+VDaeigXKauDybUQ47SkVV7HdnBIwIO6wM1dVbw8UHWIa/Y346pxnCOqNsyk2eE6pqgIa2RoQgq2Jx34WBYJVtQ8eMvRF0H33jGUZefov64B5ocZVtf/yY=
+ - secure: Kj/AIbAO0Iao1umA0hct3aoJR5244m8R9/c9mmVPrtO/gwWin2r82kjdwT62RbQHZqGTTXfBNLUFe//QwQgkUhyJUIvLkmA6tjcJnmpWJUhpZoJMgzTxMueTebDCtsri8haFf5AUD5eAge6EIYcB0hQc4g2QTH9Thqiqa17m77U=
+ - secure: eKgq3A10rhjFS0oP4KtOvtc9ZcyDkAA/0NABsaMpnHW8phO+/nax3wUgMVzWyz4vzaItB56NmyenpE+3NP5PIoLBmxsOq8Cbt8mZAieWWg6oJdW5w/AMaVbvEnAoewNhxj0CCiSloBDSS+J6y79EdT5uh1vjMHkAQARJO6tVdt0=
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/build.gradle b/build.gradle
index 69af4a06ae..27c59c1942 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,23 +1,35 @@
-ext.githubProjectName = rootProject.name
-
buildscript {
- repositories { mavenCentral() }
- apply from: file('gradle/buildscript.gradle'), to: buildscript
+ repositories { jcenter() }
+ dependencies {
+ classpath 'com.netflix.nebula:gradle-extra-configurations-plugin:2.2.0'
+ }
}
-allprojects {
- repositories { mavenCentral() }
+plugins {
+ id 'nebula.netflixoss' version '3.0.0'
}
-apply plugin: 'idea'
-apply from: file('gradle/convention.gradle')
-apply from: file('gradle/maven.gradle')
-apply from: file('gradle/license.gradle')
-apply from: file('gradle/release.gradle')
+ext.githubProjectName = rootProject.name
+
+idea {
+ project {
+ languageLevel = '1.7'
+ }
+}
subprojects {
+ apply plugin: 'nebula.netflixoss'
+ apply plugin: 'java'
+ apply plugin: 'nebula.provided-base'
+
+ repositories {
+ jcenter()
+ }
group = "com.netflix.${githubProjectName}"
+
+ sourceCompatibility = '1.7'
+ targetCompatibility = '1.7'
sourceSets.test.java.srcDir 'src/main/java'
diff --git a/buildViaTravis.sh b/buildViaTravis.sh
new file mode 100755
index 0000000000..17a33a5fb9
--- /dev/null
+++ b/buildViaTravis.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+# This script will build the project.
+
+if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then
+ echo -e "Build Pull Request #$TRAVIS_PULL_REQUEST => Branch [$TRAVIS_BRANCH]"
+ ./gradlew build
+elif [ "$TRAVIS_PULL_REQUEST" == "false" ] && [ "$TRAVIS_TAG" == "" ]; then
+ echo -e 'Build Branch with Snapshot => Branch ['$TRAVIS_BRANCH']'
+ ./gradlew -Prelease.travisci=true -PbintrayUser="${bintrayUser}" -PbintrayKey="${bintrayKey}" -PsonatypeUsername="${sonatypeUsername}" -PsonatypePassword="${sonatypePassword}" build snapshot
+elif [ "$TRAVIS_PULL_REQUEST" == "false" ] && [ "$TRAVIS_TAG" != "" ]; then
+ echo -e 'Build Branch for Release => Branch ['$TRAVIS_BRANCH'] Tag ['$TRAVIS_TAG']'
+ case "$TRAVIS_TAG" in
+ *-rc\.*)
+ ./gradlew -Prelease.travisci=true -Prelease.useLastTag=true -PbintrayUser="${bintrayUser}" -PbintrayKey="${bintrayKey}" -PsonatypeUsername="${sonatypeUsername}" -PsonatypePassword="${sonatypePassword}" candidate
+ ;;
+ *)
+ ./gradlew -Prelease.travisci=true -Prelease.useLastTag=true -PbintrayUser="${bintrayUser}" -PbintrayKey="${bintrayKey}" -PsonatypeUsername="${sonatypeUsername}" -PsonatypePassword="${sonatypePassword}" final
+ ;;
+ esac
+else
+ echo -e 'WARN: Should not be here => Branch ['$TRAVIS_BRANCH'] Tag ['$TRAVIS_TAG'] Pull Request ['$TRAVIS_PULL_REQUEST']'
+ ./gradlew build
+fi
diff --git a/codequality/HEADER b/codequality/HEADER
deleted file mode 100644
index 3102e4b449..0000000000
--- a/codequality/HEADER
+++ /dev/null
@@ -1,13 +0,0 @@
-Copyright ${year} Netflix, Inc.
-
-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/gradle.properties b/gradle.properties
index a5779ee7b6..e69de29bb2 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1 +0,0 @@
-version=1.0.28
diff --git a/gradle/buildViaTravis.sh b/gradle/buildViaTravis.sh
new file mode 100755
index 0000000000..d98e5eb603
--- /dev/null
+++ b/gradle/buildViaTravis.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+# This script will build the project.
+
+if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then
+ echo -e "Build Pull Request #$TRAVIS_PULL_REQUEST => Branch [$TRAVIS_BRANCH]"
+ ./gradlew -Prelease.useLastTag=true build
+elif [ "$TRAVIS_PULL_REQUEST" == "false" ] && [ "$TRAVIS_TAG" == "" ]; then
+ echo -e 'Build Branch with Snapshot => Branch ['$TRAVIS_BRANCH']'
+ ./gradlew -Prelease.travisci=true -PbintrayUser="${bintrayUser}" -PbintrayKey="${bintrayKey}" -PsonatypeUsername="${sonatypeUsername}" -PsonatypePassword="${sonatypePassword}" build snapshot --stacktrace
+elif [ "$TRAVIS_PULL_REQUEST" == "false" ] && [ "$TRAVIS_TAG" != "" ]; then
+ echo -e 'Build Branch for Release => Branch ['$TRAVIS_BRANCH'] Tag ['$TRAVIS_TAG']'
+ ./gradlew -Prelease.travisci=true -Prelease.useLastTag=true -PbintrayUser="${bintrayUser}" -PbintrayKey="${bintrayKey}" -PsonatypeUsername="${sonatypeUsername}" -PsonatypePassword="${sonatypePassword}" final --stacktrace
+else
+ echo -e 'WARN: Should not be here => Branch ['$TRAVIS_BRANCH'] Tag ['$TRAVIS_TAG'] Pull Request ['$TRAVIS_PULL_REQUEST']'
+ ./gradlew -Prelease.useLastTag=true build
+fi
diff --git a/gradle/buildscript.gradle b/gradle/buildscript.gradle
deleted file mode 100644
index 4d6a29aabe..0000000000
--- a/gradle/buildscript.gradle
+++ /dev/null
@@ -1,13 +0,0 @@
-// Executed in context of buildscript
-repositories {
- // Repo in addition to maven central
- maven {
- name 'build-repo'
- url 'https://raw.github.com/Netflix-Skunkworks/build-repo/master/releases/' // gradle-release/gradle-release/1.0-SNAPSHOT/gradle-release-1.0-SNAPSHOT.jar
- }
-}
-dependencies {
- classpath 'nl.javadude.gradle.plugins:license-gradle-plugin:0.6.0'
- classpath 'com.mapvine:gradle-cobertura-plugin:0.1'
- classpath 'gradle-release:gradle-release:1.0-SNAPSHOT'
-}
diff --git a/gradle/check.gradle b/gradle/check.gradle
deleted file mode 100644
index 7617f17b35..0000000000
--- a/gradle/check.gradle
+++ /dev/null
@@ -1,25 +0,0 @@
-subprojects {
- // Checkstyle
- apply plugin: 'checkstyle'
- tasks.withType(Checkstyle) { ignoreFailures = true }
- checkstyle {
- ignoreFailures = true // Waiting on GRADLE-2163
- configFile = rootProject.file('codequality/checkstyle.xml')
- }
-
- // FindBugs
- apply plugin: 'findbugs'
- //tasks.withType(Findbugs) { reports.html.enabled true }
-
- // PMD
- apply plugin: 'pmd'
- //tasks.withType(Pmd) { reports.html.enabled true }
-
- apply plugin: 'cobertura'
- cobertura {
- sourceDirs = sourceSets.main.java.srcDirs
- format = 'html'
- includes = ['**/*.java', '**/*.groovy']
- excludes = []
- }
-}
diff --git a/gradle/convention.gradle b/gradle/convention.gradle
deleted file mode 100644
index 8b877071d9..0000000000
--- a/gradle/convention.gradle
+++ /dev/null
@@ -1,83 +0,0 @@
-
-// For Artifactory
-rootProject.status = version.contains('-SNAPSHOT')?'snapshot':'release'
-
-subprojects { project ->
- apply plugin: 'java' // Plugin as major conventions
-
- version = rootProject.version
-
- sourceCompatibility = 1.6
-
- // GRADLE-2087 workaround, perform after java plugin
- status = rootProject.status
-
- task sourcesJar(type: Jar, dependsOn:classes) {
- from sourceSets.main.allSource
- classifier 'sources'
- extension 'jar'
- }
-
- task javadocJar(type: Jar, dependsOn:javadoc) {
- from javadoc.destinationDir
- classifier 'javadoc'
- extension 'jar'
- }
-
- configurations.add('sources')
- configurations.add('javadoc')
- configurations.archives {
- extendsFrom configurations.sources
- extendsFrom configurations.javadoc
- }
-
- // When outputing to an Ivy repo, we want to use the proper type field
- gradle.taskGraph.whenReady {
- def isNotMaven = !it.hasTask(project.uploadMavenCentral)
- if (isNotMaven) {
- def artifacts = project.configurations.sources.artifacts
- def sourceArtifact = artifacts.iterator().next()
- sourceArtifact.type = 'sources'
- }
- }
-
- artifacts {
- sources(sourcesJar) {
- // Weird Gradle quirk where type will be used for the extension, but only for sources
- type 'jar'
- }
- javadoc(javadocJar) {
- type 'javadoc'
- }
- }
-
- // Ensure output is on a new line
- javadoc.doFirst { println "" }
-
- configurations {
- provided {
- description = 'much like compile, but indicates you expect the JDK or a container to provide it. It is only available on the compilation classpath, and is not transitive.'
- transitive = true
- visible = true
- }
- }
-
- project.sourceSets {
- main.compileClasspath += project.configurations.provided
- main.runtimeClasspath -= project.configurations.provided
- test.compileClasspath += project.configurations.provided
- test.runtimeClasspath += project.configurations.provided
- }
-}
-
-task aggregateJavadoc(type: Javadoc) {
- description = 'Aggregate all subproject docs into a single docs directory'
- source subprojects.collect {project -> project.sourceSets.main.allJava }
- classpath = files(subprojects.collect {project -> project.sourceSets.main.compileClasspath})
- destinationDir = new File(projectDir, 'doc')
-}
-
-// Generate wrapper, which is distributed as part of source to alleviate the need of installing gradle
-task createWrapper(type: Wrapper) {
- gradleVersion = '1.1'
-}
diff --git a/gradle/license.gradle b/gradle/license.gradle
deleted file mode 100644
index 11a51f1137..0000000000
--- a/gradle/license.gradle
+++ /dev/null
@@ -1,9 +0,0 @@
-// Dependency for plugin was set in buildscript.gradle
-
-subprojects {
-apply plugin: 'license' //nl.javadude.gradle.plugins.license.LicensePlugin
-license {
- header rootProject.file('codequality/HEADER')
- ext.year = Calendar.getInstance().get(Calendar.YEAR)
-}
-}
diff --git a/gradle/maven.gradle b/gradle/maven.gradle
deleted file mode 100644
index a3a3d44240..0000000000
--- a/gradle/maven.gradle
+++ /dev/null
@@ -1,62 +0,0 @@
-// Maven side of things
-subprojects {
- apply plugin: 'maven' // Java plugin has to have been already applied for the conf2scope mappings to work
- apply plugin: 'signing'
-
- signing {
- required { gradle.taskGraph.hasTask(uploadMavenCentral) }
- sign configurations.archives
- }
-
- /**
- * Publishing to Maven Central example provided from http://jedicoder.blogspot.com/2011/11/automated-gradle-project-deployment-to.html
- */
- task uploadMavenCentral(type:Upload, dependsOn: signArchives) {
- configuration = configurations.archives
- doFirst {
- repositories.mavenDeployer {
- beforeDeployment { org.gradle.api.artifacts.maven.MavenDeployment deployment -> signing.signPom(deployment) }
-
- // To test deployment locally, use the following instead of oss.sonatype.org
- //repository(url: "file://localhost/${rootProject.rootDir}/repo")
-
- repository(url: 'https://oss.sonatype.org/service/local/staging/deploy/maven2') {
- authentication(userName: rootProject.sonatypeUsername, password: rootProject.sonatypePassword)
- }
-
- // Prevent datastamp from being appending to artifacts during deployment
- uniqueVersion = false
-
- // Closure to configure all the POM with extra info, common to all projects
- pom.project {
- name "${project.name}"
- description "${project.name} developed by Netflix"
- developers {
- developer {
- id 'netflixgithub'
- name 'Netflix Open Source Development'
- email 'talent@netflix.com'
- }
- }
- licenses {
- license {
- name 'The Apache Software License, Version 2.0'
- url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
- distribution 'repo'
- }
- }
- url "https://github.com/Netflix/${rootProject.githubProjectName}"
- scm {
- connection "scm:git:git@github.com:Netflix/${rootProject.githubProjectName}.git"
- url "scm:git:git@github.com:Netflix/${rootProject.githubProjectName}.git"
- developerConnection "scm:git:git@github.com:Netflix/${rootProject.githubProjectName}.git"
- }
- issueManagement {
- system 'github'
- url "https://github.com/Netflix/${rootProject.githubProjectName}/issues"
- }
- }
- }
- }
- }
-}
diff --git a/gradle/netflix-oss.gradle b/gradle/netflix-oss.gradle
deleted file mode 100644
index dc9c9b8559..0000000000
--- a/gradle/netflix-oss.gradle
+++ /dev/null
@@ -1,69 +0,0 @@
-apply from: 'http://artifacts.netflix.com/gradle-netflix-local/artifactory.gradle'
-
-def replacements = [
- [ 'org.json', 'json', 'org.json:json:1.0', ['compile', 'runtime'] ],
- [ 'org.powermock', 'powermock-api-mockito', 'org.powermock:powermock-mockito:1.4.12', ['provided'] ]
-]
-
-rootProject {
-// afterEvaluate { project ->
- afterProject { project ->
- println project
- println "project.configurations: ${project.configurations}"
-
- [ 'compile', 'runtime', 'provided' ].each { config_name ->
- println "config_name: ${config_name}"
- def conf = project.configurations.findByName(config_name)
- if(conf == null) return
-
- println "found ${conf}"
-
- def deps = conf.dependencies
-
- conf.dependencies.each { d ->
- println d
- }
-
- replacements.each { r ->
- def dep = deps.find { it.group == r[0] && it.name == r[1] }
- if (dep == null) return
-
- println "removing ${dep}"
- deps.remove(dep)
-
- r[3].each { dep_config_name ->
- println "adding ${dep_config_name} ${r[2]}"
- project.dependencies.add(dep_config_name, r[2])
- }
- }
- }
-/*
- def compileConf = project.configurations.findByName('compile')
- if (compileConf != null) {
- def deps = compileConf.dependencies
-
- def jsonDep = deps.find { it.group == 'org.json' && it.name == 'json' }
- if (jsonDep != null) {
- print "removing ${jsonDep}"
- deps.remove(jsonDep)
- project.dependencies.add('compile', "org.json:json:1.0")
- // project.dependencies.add('compile', "netflix:json:1.0")
- }
- }
-
- def providedConf = project.configurations.findByName('provided')
- if (providedConf != null) {
- def deps = providedConf.dependencies
-
- def powermockDep = deps.find { it.group == 'org.powermock' && it.name == 'powermock-api-mockito' }
- if (powermockDep != null) {
- print "removing ${powermockDep}"
- deps.remove(powermockDep)
- // project.dependencies.add('compile', "org.json:json:1.0")
- // project.dependencies.add('compile', "netflix:json:1.0")
- }
- }
-*/
-
- }
-}
diff --git a/gradle/release.gradle b/gradle/release.gradle
deleted file mode 100644
index cd135643bd..0000000000
--- a/gradle/release.gradle
+++ /dev/null
@@ -1,65 +0,0 @@
-apply plugin: 'release'
-
-// Ignore release plugin's task because it calls out via GradleBuild. This is a good place to put an email to send out
-task release(overwrite: true, dependsOn: commitNewVersion) << {
- // This is a good place to put an email to send out
-}
-commitNewVersion.dependsOn updateVersion
-updateVersion.dependsOn createReleaseTag
-createReleaseTag.dependsOn preTagCommit
-def buildTasks = tasks.matching { it.name =~ /:build/ }
-preTagCommit.dependsOn buildTasks
-preTagCommit.dependsOn checkSnapshotDependencies
-//checkSnapshotDependencies.dependsOn confirmReleaseVersion // Introduced in 1.0, forces readLine
-//confirmReleaseVersion.dependsOn unSnapshotVersion
-checkSnapshotDependencies.dependsOn unSnapshotVersion // Remove once above is fixed
-unSnapshotVersion.dependsOn checkUpdateNeeded
-checkUpdateNeeded.dependsOn checkCommitNeeded
-checkCommitNeeded.dependsOn initScmPlugin
-
-[
- uploadIvyLocal: 'uploadLocal',
- uploadArtifactory: 'artifactoryPublish', // Call out to compile against internal repository
- buildWithArtifactory: 'build' // Build against internal repository
-].each { key, value ->
- // Call out to compile against internal repository
- task "${key}"(type: GradleBuild) {
- startParameter = project.gradle.startParameter.newInstance()
- startParameter.addInitScript( file('gradle/netflix-oss.gradle') )
- startParameter.getExcludedTaskNames().add('check')
- tasks = [ 'build', value ]
- }
-}
-task releaseArtifactory(dependsOn: [checkSnapshotDependencies, uploadArtifactory])
-
-// Ensure upload happens before taggging but after all pre-checks
-releaseArtifactory.dependsOn checkSnapshotDependencies
-createReleaseTag.dependsOn releaseArtifactory
-gradle.taskGraph.whenReady { taskGraph ->
- if ( taskGraph.hasTask(uploadArtifactory) && rootProject.status == 'release' && !taskGraph.hasTask(':release') ) {
- throw new GradleException('"release" task has to be run before uploading a release to Artifactory')
- }
-}
-subprojects.each { project ->
- project.uploadMavenCentral.dependsOn rootProject.checkSnapshotDependencies
- rootProject.createReleaseTag.dependsOn project.uploadMavenCentral
-
- gradle.taskGraph.whenReady { taskGraph ->
- if ( taskGraph.hasTask(project.uploadMavenCentral) && !taskGraph.hasTask(':release') ) {
- throw new GradleException('"release" task has to be run before uploading to Maven Central')
- }
- }
-}
-
-// Prevent plugin from asking for a version number interactively
-ext.'gradle.release.useAutomaticVersion' = "true"
-
-release {
- // http://tellurianring.com/wiki/gradle/release
- failOnCommitNeeded=true
- failOnPublishNeeded=true
- failOnUnversionedFiles=true
- failOnUpdateNeeded=true
- includeProjectNameInTag=true
- requireBranch = null
-}
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index faa569a9a0..d43a4e55af 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 9829a99a5b..d8a4dc0bd1 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Tue Aug 14 16:28:54 PDT 2012
+#Thu Sep 10 13:23:01 PDT 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=http\://services.gradle.org/distributions/gradle-1.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.6-bin.zip
diff --git a/gradlew b/gradlew
index e61422d06d..97fac783e1 100755
--- a/gradlew
+++ b/gradlew
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
##############################################################################
##
@@ -42,11 +42,6 @@ case "`uname`" in
;;
esac
-# For Cygwin, ensure paths are in UNIX format before anything is touched.
-if $cygwin ; then
- [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
-fi
-
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
@@ -61,9 +56,9 @@ while [ -h "$PRG" ] ; do
fi
done
SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/"
+cd "`dirname \"$PRG\"`/" >&-
APP_HOME="`pwd -P`"
-cd "$SAVED"
+cd "$SAVED" >&-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@@ -114,6 +109,7 @@ fi
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
diff --git a/installViaTravis.sh b/installViaTravis.sh
new file mode 100755
index 0000000000..b51fe10e94
--- /dev/null
+++ b/installViaTravis.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+# This script will build the project.
+
+if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then
+ echo -e "Assemble Pull Request #$TRAVIS_PULL_REQUEST => Branch [$TRAVIS_BRANCH]"
+ ./gradlew assemble
+elif [ "$TRAVIS_PULL_REQUEST" == "false" ] && [ "$TRAVIS_TAG" == "" ]; then
+ echo -e 'Assemble Branch with Snapshot => Branch ['$TRAVIS_BRANCH']'
+ ./gradlew -Prelease.travisci=true assemble
+elif [ "$TRAVIS_PULL_REQUEST" == "false" ] && [ "$TRAVIS_TAG" != "" ]; then
+ echo -e 'Assemble Branch for Release => Branch ['$TRAVIS_BRANCH'] Tag ['$TRAVIS_TAG']'
+ ./gradlew -Prelease.travisci=true -Prelease.useLastTag=true assemble
+else
+ echo -e 'WARN: Should not be here => Branch ['$TRAVIS_BRANCH'] Tag ['$TRAVIS_TAG'] Pull Request ['$TRAVIS_PULL_REQUEST']'
+ ./gradlew assemble
+fi
\ No newline at end of file
diff --git a/zuul-core/build.gradle b/zuul-core/build.gradle
index 16774d10f2..bea3aaa0ce 100644
--- a/zuul-core/build.gradle
+++ b/zuul-core/build.gradle
@@ -1,17 +1,13 @@
-apply plugin: 'java'
apply plugin: 'groovy'
-apply plugin: 'eclipse'
-apply plugin: 'idea'
dependencies {
compile 'commons-io:commons-io:2.4'
- compile 'org.codehaus.groovy:groovy-all:2.3.1'
+ compile 'org.codehaus.groovy:groovy-all:2.3.6'
compile 'org.mockito:mockito-all:1.9.5'
compile 'org.slf4j:slf4j-api:1.7.6'
provided 'junit:junit-dep:4.10'
provided 'javax.servlet:servlet-api:2.5'
- groovy "org.codehaus.groovy:groovy-all:2.3.1"
compile 'com.netflix.archaius:archaius-core:0.6.0'
compile 'com.netflix.servo:servo-core:0.7.2'
@@ -30,15 +26,7 @@ javadoc {
eclipse {
classpath {
- plusConfigurations += configurations.provided
downloadSources = true
downloadJavadoc = true
}
}
-
-
-idea {
- module {
- scopes.PROVIDED.plus += configurations.provided
- }
-}
diff --git a/zuul-core/src/main/java/com/netflix/zuul/ZuulFilter.java b/zuul-core/src/main/java/com/netflix/zuul/ZuulFilter.java
index 2d87c098a1..225d1a09bd 100644
--- a/zuul-core/src/main/java/com/netflix/zuul/ZuulFilter.java
+++ b/zuul-core/src/main/java/com/netflix/zuul/ZuulFilter.java
@@ -105,7 +105,7 @@ public boolean isFilterDisabled() {
*/
public ZuulFilterResult runFilter() {
ZuulFilterResult zr = new ZuulFilterResult();
- if (!filterDisabled.get()) {
+ if (!isFilterDisabled()) {
if (shouldFilter()) {
Tracer t = TracerFactory.instance().startMicroTracer("ZUUL::" + this.getClass().getSimpleName());
try {
@@ -197,5 +197,49 @@ public Object run() {
}
+ @Test
+ public void testIsFilterDisabled() {
+ class TestZuulFilter extends ZuulFilter {
+
+ @Override
+ public String filterType() {
+ return null;
+ }
+
+ @Override
+ public int filterOrder() {
+ return 0;
+ }
+
+ public boolean isFilterDisabled() {
+ return false;
+ }
+
+ public boolean shouldFilter() {
+ return true;
+ }
+
+ public Object run() {
+ return null;
+ }
+ }
+
+ TestZuulFilter tf1 = spy(new TestZuulFilter());
+ TestZuulFilter tf2 = spy(new TestZuulFilter());
+
+ when(tf1.isFilterDisabled()).thenReturn(false);
+ when(tf2.isFilterDisabled()).thenReturn(true);
+
+ try {
+ tf1.runFilter();
+ tf2.runFilter();
+ verify(tf1, times(1)).run();
+ verify(tf2, times(0)).run();
+ } catch (Throwable throwable) {
+ throwable.printStackTrace();
+ }
+
+ }
+
}
}
diff --git a/zuul-core/src/main/java/com/netflix/zuul/ZuulRunner.java b/zuul-core/src/main/java/com/netflix/zuul/ZuulRunner.java
index 7b5964441c..4f01d5fcd1 100644
--- a/zuul-core/src/main/java/com/netflix/zuul/ZuulRunner.java
+++ b/zuul-core/src/main/java/com/netflix/zuul/ZuulRunner.java
@@ -15,17 +15,10 @@
*/
package com.netflix.zuul;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.io.PrintWriter;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
+import com.netflix.zuul.context.RequestContext;
+import com.netflix.zuul.exception.ZuulException;
+import com.netflix.zuul.http.HttpServletRequestWrapper;
+import com.netflix.zuul.http.HttpServletResponseWrapper;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -33,10 +26,12 @@
import org.mockito.MockitoAnnotations;
import org.mockito.runners.MockitoJUnitRunner;
-import com.netflix.zuul.context.RequestContext;
-import com.netflix.zuul.exception.ZuulException;
-import com.netflix.zuul.http.HttpServletRequestWrapper;
-import com.netflix.zuul.http.HttpServletResponseWrapper;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.PrintWriter;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.*;
/**
@@ -48,10 +43,21 @@
*/
public class ZuulRunner {
+ private boolean bufferRequests;
+
/**
* Creates a new ZuulRunner
instance.
*/
public ZuulRunner() {
+ this.bufferRequests = true;
+ }
+
+ /**
+ *
+ * @param bufferRequests - whether to wrap the ServletRequest in HttpServletRequestWrapper and buffer the body.
+ */
+ public ZuulRunner(boolean bufferRequests) {
+ this.bufferRequests = bufferRequests;
}
/**
@@ -61,9 +67,15 @@ public ZuulRunner() {
* @param servletResponse
*/
public void init(HttpServletRequest servletRequest, HttpServletResponse servletResponse) {
- RequestContext.getCurrentContext().setRequest(new HttpServletRequestWrapper(servletRequest));
- RequestContext.getCurrentContext().setResponse(new HttpServletResponseWrapper(servletResponse));
- //RequestContext.getCurrentContext().setResponseStatusCode(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+
+ RequestContext ctx = RequestContext.getCurrentContext();
+ if (bufferRequests) {
+ ctx.setRequest(new HttpServletRequestWrapper(servletRequest));
+ } else {
+ ctx.setRequest(servletRequest);
+ }
+
+ ctx.setResponse(new HttpServletResponseWrapper(servletResponse));
}
/**
diff --git a/zuul-core/src/main/java/com/netflix/zuul/filters/ZuulServletFilter.java b/zuul-core/src/main/java/com/netflix/zuul/filters/ZuulServletFilter.java
index 2330235a1f..8e22648ffe 100644
--- a/zuul-core/src/main/java/com/netflix/zuul/filters/ZuulServletFilter.java
+++ b/zuul-core/src/main/java/com/netflix/zuul/filters/ZuulServletFilter.java
@@ -49,11 +49,14 @@
*/
public class ZuulServletFilter implements Filter {
-
- private ZuulRunner zuulRunner = new ZuulRunner();
+ private ZuulRunner zuulRunner;
public void init(FilterConfig filterConfig) throws ServletException {
+ String bufferReqsStr = filterConfig.getInitParameter("buffer-requests");
+ boolean bufferReqs = bufferReqsStr != null && bufferReqsStr.equals("true") ? true : false;
+
+ zuulRunner = new ZuulRunner(bufferReqs);
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
@@ -106,7 +109,6 @@ void init(HttpServletRequest servletRequest, HttpServletResponse servletResponse
void error(ZuulException e) {
RequestContext.getCurrentContext().setThrowable(e);
zuulRunner.error();
- e.printStackTrace();
}
public void destroy() {
diff --git a/zuul-core/src/main/java/com/netflix/zuul/http/HttpServletRequestWrapper.java b/zuul-core/src/main/java/com/netflix/zuul/http/HttpServletRequestWrapper.java
index c5305c8eaa..cec3eff2da 100755
--- a/zuul-core/src/main/java/com/netflix/zuul/http/HttpServletRequestWrapper.java
+++ b/zuul-core/src/main/java/com/netflix/zuul/http/HttpServletRequestWrapper.java
@@ -33,6 +33,7 @@
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.*;
+import java.net.SocketTimeoutException;
import java.net.URLDecoder;
import java.security.Principal;
import java.util.*;
@@ -60,8 +61,10 @@ public class HttpServletRequestWrapper implements HttpServletRequest {
protected static final Logger LOG = LoggerFactory.getLogger(HttpServletRequestWrapper.class);
private HttpServletRequest req;
- private byte[] contentData;
- private HashMap parameters;
+ private byte[] contentData = null;
+ private HashMap parameters = null;
+
+ private long bodyBufferingTimeNs = 0;
public HttpServletRequestWrapper() {
//a trick for Groovy
@@ -98,12 +101,11 @@ public HttpServletRequest getRequest() {
/**
* This method is safe to use multiple times.
- * Changing the returned array will not interfere with this class operation.
*
- * @return The cloned content data.
+ * @return The request body data.
*/
public byte[] getContentData() {
- return contentData.clone();
+ return contentData;
}
@@ -139,17 +141,25 @@ private void parseRequest() throws IOException {
}
}
- LOG.debug("Path = " + req.getPathInfo());
- LOG.debug("Transfer-Encoding = " + String.valueOf(req.getHeader(ZuulHeaders.TRANSFER_ENCODING)));
- LOG.debug("Content-Encoding = " + String.valueOf(req.getHeader(ZuulHeaders.CONTENT_ENCODING)));
-
- LOG.debug("Content-Length header = " + req.getContentLength());
- if (req.getContentLength() > 0) {
+ if (shouldBufferBody()) {
// Read the request body inputstream into a byte array.
ByteArrayOutputStream baos = new ByteArrayOutputStream();
- IOUtils.copy(req.getInputStream(), baos);
- contentData = baos.toByteArray();
+ try {
+ // Copy all bytes from inputstream to byte array, and record time taken.
+ long bufferStartTime = System.nanoTime();
+ IOUtils.copy(req.getInputStream(), baos);
+ bodyBufferingTimeNs = System.nanoTime() - bufferStartTime;
+
+ contentData = baos.toByteArray();
+ } catch (SocketTimeoutException e) {
+ // This can happen if the request body is smaller than the size specified in the
+ // Content-Length header, and using tomcat APR connector.
+ LOG.error("SocketTimeoutException reading request body from inputstream. error=" + String.valueOf(e.getMessage()));
+ if (contentData == null) {
+ contentData = new byte[0];
+ }
+ }
try {
LOG.debug("Length of contentData byte array = " + contentData.length);
@@ -160,48 +170,46 @@ private void parseRequest() throws IOException {
LOG.error("Error checking if request body gzipped!", e);
}
- String enc = req.getCharacterEncoding();
-
- if (enc == null)
- enc = "UTF-8";
- String s = new String(contentData, enc), name, value;
- StringTokenizer st = new StringTokenizer(s, "&");
- int i;
-
- boolean decode = req.getContentType() != null && req.getContentType().equalsIgnoreCase("application/x-www-form-urlencoded");
- while (st.hasMoreTokens()) {
- s = st.nextToken();
- i = s.indexOf("=");
- if (i > 0 && s.length() > i + 1) {
- name = s.substring(0, i);
- value = s.substring(i + 1);
- if (decode) {
- try {
- name = URLDecoder.decode(name, "UTF-8");
- } catch (Exception e) {
+ final boolean isPost = req.getMethod().equals("POST");
+
+ String contentType = req.getContentType();
+ final boolean isFormBody = contentType != null && contentType.contains("application/x-www-form-urlencoded");
+
+ // only does magic body param parsing for POST form bodies
+ if (isPost && isFormBody) {
+ String enc = req.getCharacterEncoding();
+
+ if (enc == null) enc = "UTF-8";
+ String s = new String(contentData, enc), name, value;
+ StringTokenizer st = new StringTokenizer(s, "&");
+ int i;
+
+ boolean decode = req.getContentType() != null;
+ while (st.hasMoreTokens()) {
+ s = st.nextToken();
+ i = s.indexOf("=");
+ if (i > 0 && s.length() > i + 1) {
+ name = s.substring(0, i);
+ value = s.substring(i + 1);
+ if (decode) {
+ try {
+ name = URLDecoder.decode(name, "UTF-8");
+ } catch (Exception e) {
+ }
+ try {
+ value = URLDecoder.decode(value, "UTF-8");
+ } catch (Exception e) {
+ }
}
- try {
- value = URLDecoder.decode(value, "UTF-8");
- } catch (Exception e) {
+ list = mapA.get(name);
+ if (list == null) {
+ list = new LinkedList();
+ mapA.put(name, list);
}
+ list.add(value);
}
- list = mapA.get(name);
- if (list == null) {
- list = new LinkedList();
- mapA.put(name, list);
- }
- list.add(value);
}
}
-
- } else if (req.getContentLength() == -1) {
- final String transferEncoding = req.getHeader(ZuulHeaders.TRANSFER_ENCODING);
- if (transferEncoding != null && transferEncoding.equals(ZuulHeaders.CHUNKED)) {
- RequestContext.getCurrentContext().setChunkedRequestBody();
- LOG.debug("Set flag that request body is chunked.");
- }
- } else {
- LOG.warn("Content-Length is neither greater than zero or -1. = " + req.getContentLength());
}
HashMap map = new HashMap(mapA.size() * 2);
@@ -214,6 +222,39 @@ private void parseRequest() throws IOException {
}
+ private boolean shouldBufferBody() {
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Path = " + req.getPathInfo());
+ LOG.debug("Transfer-Encoding = " + String.valueOf(req.getHeader(ZuulHeaders.TRANSFER_ENCODING)));
+ LOG.debug("Content-Encoding = " + String.valueOf(req.getHeader(ZuulHeaders.CONTENT_ENCODING)));
+ LOG.debug("Content-Length header = " + req.getContentLength());
+ }
+
+ boolean should = false;
+ if (req.getContentLength() > 0) {
+ should = true;
+ }
+ else if (req.getContentLength() == -1) {
+ final String transferEncoding = req.getHeader(ZuulHeaders.TRANSFER_ENCODING);
+ if (transferEncoding != null && transferEncoding.equals(ZuulHeaders.CHUNKED)) {
+ RequestContext.getCurrentContext().setChunkedRequestBody();
+ should = true;
+ }
+ }
+
+ return should;
+ }
+
+ /**
+ * Time taken to buffer the request body in nanoseconds.
+ * @return
+ */
+ public long getBodyBufferingTimeNs()
+ {
+ return bodyBufferingTimeNs;
+ }
+
/**
* This method is safe to call multiple times.
* Calling it will not interfere with getParameterXXX() or getReader().
@@ -224,11 +265,7 @@ private void parseRequest() throws IOException {
public ServletInputStream getInputStream() throws IOException {
parseRequest();
- if (RequestContext.getCurrentContext().isChunkedRequestBody()) {
- return req.getInputStream();
- } else {
- return new ServletInputStreamWrapper(contentData);
- }
+ return new ServletInputStreamWrapper(contentData);
}
/**
@@ -681,6 +718,9 @@ public void before() {
MockitoAnnotations.initMocks(this);
RequestContext.getCurrentContext().setRequest(request);
+
+ method("GET");
+ contentType("zuul/test-content-type");
}
private void body(byte[] body) throws IOException {
@@ -688,6 +728,45 @@ private void body(byte[] body) throws IOException {
when(request.getContentLength()).thenReturn(body.length);
}
+ private void method(String s) {
+ when(request.getMethod()).thenReturn(s);
+ }
+
+ private void contentType(String s) {
+ when(request.getContentType()).thenReturn(s);
+ }
+
+ private static String readZipInputStream(InputStream input) throws IOException {
+
+ byte[] uploadedBytes = getBytesFromInputStream(input);
+ input.close();
+
+ /* try to read it as a zip file */
+ String uploadFileTxt = null;
+ ZipInputStream zInput = new ZipInputStream(new ByteArrayInputStream(uploadedBytes));
+ ZipEntry zipEntry = zInput.getNextEntry();
+ if (zipEntry != null) {
+ // we have a ZipEntry, so this is a zip file
+ while (zipEntry != null) {
+ byte[] fileBytes = getBytesFromInputStream(zInput);
+ uploadFileTxt = new String(fileBytes);
+
+ zipEntry = zInput.getNextEntry();
+ }
+ }
+ return uploadFileTxt;
+ }
+
+ private static byte[] getBytesFromInputStream(InputStream input) throws IOException {
+ int v = 0;
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ while ((v = input.read()) != -1) {
+ bos.write(v);
+ }
+ bos.close();
+ return bos.toByteArray();
+ }
+
@Test
public void handlesDuplicateParams() {
when(request.getQueryString()).thenReturn("path=one&key1=val1&path=two");
@@ -751,41 +830,52 @@ public void handlesZipRequestBody() throws IOException {
assertEquals(body, readZipInputStream(wrapper.getInputStream()));
+ }
+ @Test
+ public void parsesParamsFromFormBody() throws Exception {
+ method("POST");
+ body("one=1&two=2".getBytes());
+ contentType("application/x-www-form-urlencoded");
+ final HttpServletRequestWrapper wrapper = new HttpServletRequestWrapper(request);
+ final Map params = wrapper.getParameterMap();
+ assertTrue(params.containsKey("one"));
+ assertTrue(params.containsKey("two"));
}
- public String readZipInputStream(InputStream input) throws IOException {
+ @Test
+ public void ignoresParamsInBodyForNonPosts() throws Exception {
+ method("PUT");
+ body("one=1&two=2".getBytes());
+ contentType("application/x-www-form-urlencoded");
- byte[] uploadedBytes = getBytesFromInputStream(input);
- input.close();
+ final HttpServletRequestWrapper wrapper = new HttpServletRequestWrapper(request);
+ final Map params = wrapper.getParameterMap();
+ assertFalse(params.containsKey("one"));
+ }
- /* try to read it as a zip file */
- String uploadFileTxt = null;
- ZipInputStream zInput = new ZipInputStream(new ByteArrayInputStream(uploadedBytes));
- ZipEntry zipEntry = zInput.getNextEntry();
- if (zipEntry != null) {
- // we have a ZipEntry, so this is a zip file
- while (zipEntry != null) {
- byte[] fileBytes = getBytesFromInputStream(zInput);
- uploadFileTxt = new String(fileBytes);
+ @Test
+ public void ignoresParamsInBodyForNonForms() throws Exception {
+ method("POST");
+ body("one=1&two=2".getBytes());
+ contentType("application/json");
- zipEntry = zInput.getNextEntry();
- }
- }
- return uploadFileTxt;
+ final HttpServletRequestWrapper wrapper = new HttpServletRequestWrapper(request);
+ final Map params = wrapper.getParameterMap();
+ assertFalse(params.containsKey("one"));
}
- private byte[] getBytesFromInputStream(InputStream input) throws IOException {
- int v = 0;
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- while ((v = input.read()) != -1) {
- bos.write(v);
- }
- bos.close();
- return bos.toByteArray();
- }
+ @Test
+ public void handlesPostsWithNoContentTypeHeader() throws Exception {
+ method("POST");
+ body("one=1&two=2".getBytes());
+ contentType(null);
+ final HttpServletRequestWrapper wrapper = new HttpServletRequestWrapper(request);
+ final Map params = wrapper.getParameterMap();
+ assertFalse(params.containsKey("one"));
+ }
}
diff --git a/zuul-core/src/main/java/com/netflix/zuul/http/ZuulServlet.java b/zuul-core/src/main/java/com/netflix/zuul/http/ZuulServlet.java
index d11260ac00..0a97c6bd13 100644
--- a/zuul-core/src/main/java/com/netflix/zuul/http/ZuulServlet.java
+++ b/zuul-core/src/main/java/com/netflix/zuul/http/ZuulServlet.java
@@ -15,33 +15,27 @@
*/
package com.netflix.zuul.http;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-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 com.netflix.zuul.FilterProcessor;
+import com.netflix.zuul.ZuulRunner;
+import com.netflix.zuul.context.RequestContext;
+import com.netflix.zuul.exception.ZuulException;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.runners.MockitoJUnitRunner;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import com.netflix.zuul.FilterProcessor;
-import com.netflix.zuul.ZuulRunner;
-import com.netflix.zuul.context.RequestContext;
-import com.netflix.zuul.exception.ZuulException;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.*;
/**
* Core Zuul servlet which intializes and orchestrates zuulFilter execution
@@ -51,10 +45,20 @@
* Time: 10:44 AM
*/
public class ZuulServlet extends HttpServlet {
-
+
private static final long serialVersionUID = -3374242278843351500L;
- private ZuulRunner zuulRunner = new ZuulRunner();
- private static Logger LOG = LoggerFactory.getLogger(ZuulServlet.class);
+ private ZuulRunner zuulRunner;
+
+
+ @Override
+ public void init(ServletConfig config) throws ServletException {
+ super.init(config);
+
+ String bufferReqsStr = config.getInitParameter("buffer-requests");
+ boolean bufferReqs = bufferReqsStr != null && bufferReqsStr.equals("true") ? true : false;
+
+ zuulRunner = new ZuulRunner(bufferReqs);
+ }
@Override
public void service(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) throws ServletException, IOException {
@@ -90,6 +94,7 @@ public void service(javax.servlet.ServletRequest servletRequest, javax.servlet.S
} catch (Throwable e) {
error(new ZuulException(e, 500, "UNHANDLED_EXCEPTION_" + e.getClass().getName()));
} finally {
+ RequestContext.getCurrentContext().unset();
}
}
@@ -138,7 +143,6 @@ void init(HttpServletRequest servletRequest, HttpServletResponse servletResponse
void error(ZuulException e) {
RequestContext.getCurrentContext().setThrowable(e);
zuulRunner.error();
- LOG.error(e.getMessage(), e);
}
@RunWith(MockitoJUnitRunner.class)
@@ -188,7 +192,7 @@ public void testProcessZuulFilter() {
RequestContext.testSetCurrentContext(null);
} catch (Exception e) {
- LOG.error(e.getMessage(), e);
+ e.printStackTrace();
}
diff --git a/zuul-core/src/main/java/com/netflix/zuul/util/HTTPRequestUtils.java b/zuul-core/src/main/java/com/netflix/zuul/util/HTTPRequestUtils.java
index 8fb2d567c1..6ec6b95924 100755
--- a/zuul-core/src/main/java/com/netflix/zuul/util/HTTPRequestUtils.java
+++ b/zuul-core/src/main/java/com/netflix/zuul/util/HTTPRequestUtils.java
@@ -15,8 +15,10 @@
*/
package com.netflix.zuul.util;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
import java.net.URLDecoder;
import java.util.ArrayList;
@@ -30,7 +32,10 @@
import javax.servlet.http.HttpServletRequest;
+import org.junit.Before;
import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import com.netflix.zuul.context.RequestContext;
@@ -163,7 +168,7 @@ public Map> getQueryParams() {
while (st.hasMoreTokens()) {
String s = st.nextToken();
i = s.indexOf("=");
- if (i > 0 && s.length() > i + 1) {
+ if (i > 0 && s.length() >= i + 1) {
String name = s.substring(0, i);
String value = s.substring(i + 1);
@@ -184,6 +189,24 @@ public Map> getQueryParams() {
valueList.add(value);
}
+ else if (i == -1)
+ {
+ String name=s;
+ String value="";
+ try {
+ name = URLDecoder.decode(name, "UTF-8");
+ } catch (Exception e) {
+ }
+
+ List valueList = qp.get(name);
+ if (valueList == null) {
+ valueList = new LinkedList();
+ qp.put(name, valueList);
+ }
+
+ valueList.add(value);
+
+ }
}
RequestContext.getCurrentContext().setRequestQueryParams(qp);
@@ -222,6 +245,16 @@ public boolean isGzipped(String contentEncoding) {
public static class UnitTest {
+ @Mock
+ private RequestContext mockContext;
+ @Mock
+ private HttpServletRequest request;
+
+ @Before
+ public void before() {
+ MockitoAnnotations.initMocks(this);
+ }
+
@Test
public void detectsGzip() {
assertTrue(HTTPRequestUtils.getInstance().isGzipped("gzip"));
@@ -236,6 +269,36 @@ public void detectsNonGzip() {
public void detectsGzipAmongOtherEncodings() {
assertTrue(HTTPRequestUtils.getInstance().isGzipped("gzip, deflate"));
}
+
+ @Test
+ public void testGetQueryParams() {
+ Map> qp;
+ LinkedList blankValue = new LinkedList();
+ blankValue.add("");
+
+ RequestContext.testSetCurrentContext(mockContext);
+ when(mockContext.getRequestQueryParams()).thenReturn(null);
+ when(mockContext.getRequest()).thenReturn(request);
+ when(request.getQueryString()).thenReturn("wsdl");
+
+ qp = HTTPRequestUtils.getInstance().getQueryParams();
+ assertEquals(blankValue, qp.get("wsdl"));
+
+ when(request.getQueryString()).thenReturn("wsdl=");
+
+ qp = HTTPRequestUtils.getInstance().getQueryParams();
+ assertEquals(blankValue, qp.get("wsdl"));
+
+ when(request.getQueryString()).thenReturn("a=123&b=234&b=345&c&d=");
+
+ qp = HTTPRequestUtils.getInstance().getQueryParams();
+ assertEquals("123", qp.get("a").get(0));
+ // Not sure that order is supposed to be guaranteed here
+ assertEquals("234", qp.get("b").get(0));
+ assertEquals("345", qp.get("b").get(1));
+ assertEquals(blankValue, qp.get("c"));
+ assertEquals(blankValue, qp.get("d"));
+ }
}
}
diff --git a/zuul-netflix-webapp/build.gradle b/zuul-netflix-webapp/build.gradle
index 150f2e9ffb..1c173ebf49 100644
--- a/zuul-netflix-webapp/build.gradle
+++ b/zuul-netflix-webapp/build.gradle
@@ -1,7 +1,4 @@
-apply plugin: 'java'
apply plugin: 'groovy'
-apply plugin: 'eclipse'
-apply plugin: 'idea'
apply plugin: 'war'
apply plugin: 'jetty'
@@ -20,8 +17,8 @@ dependencies {
compile 'com.sun.jersey:jersey-client:1.17.1'
compile 'com.sun.jersey:jersey-servlet:1.17.1'
- groovy "org.codehaus.groovy:groovy-all:2.2.2"
- provided 'junit:junit-dep:4.10'
+ compile "org.codehaus.groovy:groovy-all:2.2.2"
+ providedCompile 'junit:junit-dep:4.10'
}
javadoc {
@@ -35,20 +32,11 @@ javadoc {
eclipse {
classpath {
- plusConfigurations += configurations.provided
downloadSources = true
downloadJavadoc = true
}
}
-
-idea {
- module {
- languageLevel = '1.7'
- scopes.PROVIDED.plus += configurations.provided
- }
-}
-
war {
webXml = file('src/main/webapp/WEB-INF/web.xml')
webInf{
diff --git a/zuul-netflix-webapp/src/main/groovy/filters/post/sendResponse.groovy b/zuul-netflix-webapp/src/main/groovy/filters/post/sendResponse.groovy
index b74a075564..dbfc594215 100644
--- a/zuul-netflix-webapp/src/main/groovy/filters/post/sendResponse.groovy
+++ b/zuul-netflix-webapp/src/main/groovy/filters/post/sendResponse.groovy
@@ -29,6 +29,7 @@ import org.junit.runner.RunWith
import org.mockito.Mockito
import org.mockito.runners.MockitoJUnitRunner
+import java.nio.charset.Charset
import java.util.zip.GZIPInputStream
import javax.servlet.http.HttpServletResponse
@@ -77,7 +78,7 @@ class sendResponse extends ZuulFilter {
try {
if (RequestContext.currentContext.responseBody != null) {
String body = RequestContext.currentContext.responseBody
- writeResponse(new ByteArrayInputStream(body.bytes), outStream)
+ writeResponse(new ByteArrayInputStream(body.getBytes(Charset.forName("UTF-8"))), outStream)
return;
}
diff --git a/zuul-netflix-webapp/src/main/groovy/filters/pre/ErrorResponse.groovy b/zuul-netflix-webapp/src/main/groovy/filters/pre/ErrorResponse.groovy
index 6bdba2fbfa..58beed032a 100644
--- a/zuul-netflix-webapp/src/main/groovy/filters/pre/ErrorResponse.groovy
+++ b/zuul-netflix-webapp/src/main/groovy/filters/pre/ErrorResponse.groovy
@@ -26,12 +26,16 @@ import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.runners.MockitoJUnitRunner
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
class ErrorResponse extends ZuulFilter {
+ private static final Logger LOG = LoggerFactory.getLogger(ErrorResponse.class);
+
@Override
String filterType() {
return 'error'
@@ -53,6 +57,7 @@ class ErrorResponse extends ZuulFilter {
RequestContext context = RequestContext.currentContext
Throwable ex = context.getThrowable()
try {
+ LOG.error(ex.getMessage(), ex);
throw ex
} catch (ZuulException e) {
String cause = e.errorCause
diff --git a/zuul-netflix-webapp/src/main/groovy/filters/route/ZuulHostRequest.groovy b/zuul-netflix-webapp/src/main/groovy/filters/route/ZuulHostRequest.groovy
index e54dbe22ad..a1802432db 100644
--- a/zuul-netflix-webapp/src/main/groovy/filters/route/ZuulHostRequest.groovy
+++ b/zuul-netflix-webapp/src/main/groovy/filters/route/ZuulHostRequest.groovy
@@ -319,35 +319,37 @@ class ZuulHostRequest extends ZuulFilter {
return true;
}
- def Header[] buildZuulRequestHeaders(HttpServletRequest request) {
- def headers = new ArrayList()
+ def Header[] buildZuulRequestHeaders(HttpServletRequest request) {
+ Map headers = new HashMap()
Enumeration headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String name = (String) headerNames.nextElement();
- String value = request.getHeader(name);
- if (isValidHeader(name)) headers.add(new BasicHeader(name, value))
+
+ final StringBuilder valBuilder = new StringBuilder();
+ for (final Enumeration vals = request.getHeaders(name); vals.hasMoreElements();) {
+ valBuilder.append(vals.nextElement());
+ valBuilder.append(',')
+ }
+ valBuilder.setLength(valBuilder.length()-1)
+
+ if (isValidHeader(name)) {
+ headers.put(name.toLowerCase(),new BasicHeader(name, valBuilder.toString()))
+ }
}
Map zuulRequestHeaders = RequestContext.getCurrentContext().getZuulRequestHeaders();
zuulRequestHeaders.keySet().each {
- String name = it.toLowerCase()
- BasicHeader h = headers.find { BasicHeader he -> he.name == name }
- if (h != null) {
- headers.remove(h)
- }
- headers.add(new BasicHeader((String) it, (String) zuulRequestHeaders[it]))
+ headers.put(it.toLowerCase(),new BasicHeader((String) it, (String) zuulRequestHeaders[it]))
}
if (RequestContext.currentContext.responseGZipped) {
- headers.add(new BasicHeader("accept-encoding", "deflate, gzip"))
+ headers.put("accept-encoding",new BasicHeader("accept-encoding", "deflate, gzip"))
}
- return headers
+ return headers.values().toArray()
}
-
-
String getVerb(HttpServletRequest request) {
String sMethod = request.getMethod();
return sMethod.toUpperCase();
diff --git a/zuul-netflix/build.gradle b/zuul-netflix/build.gradle
index d4e787c196..fd09242de5 100644
--- a/zuul-netflix/build.gradle
+++ b/zuul-netflix/build.gradle
@@ -1,7 +1,4 @@
-apply plugin: 'java'
apply plugin: 'groovy'
-apply plugin: 'eclipse'
-apply plugin: 'idea'
dependencies {
compile project(':zuul-core')
@@ -37,15 +34,7 @@ javadoc {
eclipse {
classpath {
- plusConfigurations += configurations.provided
downloadSources = true
downloadJavadoc = true
}
}
-
-
-idea {
- module {
- scopes.PROVIDED.plus += configurations.provided
- }
-}
diff --git a/zuul-netflix/src/main/java/com/netflix/zuul/FilterId.java b/zuul-netflix/src/main/java/com/netflix/zuul/FilterId.java
new file mode 100644
index 0000000000..f21a44b88d
--- /dev/null
+++ b/zuul-netflix/src/main/java/com/netflix/zuul/FilterId.java
@@ -0,0 +1,84 @@
+package com.netflix.zuul;
+
+import java.util.UUID;
+
+import org.junit.After;
+import org.junit.Test;
+
+import net.jcip.annotations.Immutable;
+import net.jcip.annotations.ThreadSafe;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+@Immutable
+@ThreadSafe
+public final class FilterId {
+
+ private String value;
+
+ private FilterId(String value) {
+ this.value = value;
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ public static class Builder {
+ private String applicationName = ZuulApplicationInfo.getApplicationName();
+ private String filterType;
+ private String filterName;
+
+ public Builder applicationName(String applicationName) {
+ this.applicationName = applicationName;
+ return this;
+ }
+
+ public Builder filterType(String filterType) {
+ this.filterType = filterType;
+ return this;
+ }
+
+ public Builder filterName(String filterName) {
+ this.filterName = filterName;
+ return this;
+ }
+
+ public FilterId build() {
+ return new FilterId(applicationName + ":" + filterName + ":" + filterType);
+ }
+ }
+
+
+ public static class UnitTest {
+
+ String zuulAppName = ZuulApplicationInfo.getApplicationName();
+
+ @After
+ public void setZuulAppNameBack() {
+ ZuulApplicationInfo.setApplicationName(zuulAppName);
+ }
+
+ @Test
+ public void filterId() {
+ FilterId filterId = new Builder().applicationName("app")
+ .filterType("com.acme.None")
+ .filterName("none")
+ .build();
+ assertThat(filterId.toString(), is("app:none:com.acme.None"));
+ }
+
+ @Test
+ public void defaultApplicationName() {
+ String applicationName = UUID.randomUUID().toString();
+ ZuulApplicationInfo.setApplicationName(applicationName);
+
+ FilterId filterId = new Builder().filterType("com.acme.None")
+ .filterName("none")
+ .build();
+ assertThat(filterId.toString(), is(applicationName + ":none:com.acme.None"));
+ }
+ }
+}
diff --git a/zuul-netflix/src/main/java/com/netflix/zuul/scriptManager/FilterInfo.java b/zuul-netflix/src/main/java/com/netflix/zuul/scriptManager/FilterInfo.java
index 9915afc566..889eae65b9 100644
--- a/zuul-netflix/src/main/java/com/netflix/zuul/scriptManager/FilterInfo.java
+++ b/zuul-netflix/src/main/java/com/netflix/zuul/scriptManager/FilterInfo.java
@@ -15,14 +15,24 @@
*/
package com.netflix.zuul.scriptManager;
-import net.jcip.annotations.ThreadSafe;
-
import java.util.Date;
import java.util.concurrent.atomic.AtomicBoolean;
+import com.netflix.zuul.FilterId;
+import com.netflix.zuul.ZuulApplicationInfo;
+import com.netflix.zuul.ZuulFilter;
+
+import org.junit.Test;
+
+import net.jcip.annotations.ThreadSafe;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
/**
* Representation of a ZuulFilter for representing and storing in a database
*/
+
@ThreadSafe
public class FilterInfo implements Comparable{
@@ -34,20 +44,14 @@ public class FilterInfo implements Comparable{
private final String filter_order;
private final String application_name;
private int revision;
- private Date creationDate;
+ private Date creationDate = new Date();
+
/* using AtomicBoolean so we can pass it into EndpointScriptMonitor */
private final AtomicBoolean isActive = new AtomicBoolean();
private final AtomicBoolean isCanary = new AtomicBoolean();
/**
- * Constructor
- * @param filter_id
- * @param filter_code
- * @param filter_type
- * @param filter_name
- * @param disablePropertyName
- * @param filter_order
- * @param application_name
+ * Constructors
*/
public FilterInfo(String filter_id, String filter_code, String filter_type, String filter_name, String disablePropertyName, String filter_order, String application_name) {
this.filter_id = filter_id;
@@ -61,6 +65,32 @@ public FilterInfo(String filter_id, String filter_code, String filter_type, Stri
isCanary.set(false);
}
+ public FilterInfo(String filterCode, String filterName, ZuulFilter filter) {
+ this.filter_code = filterCode;
+ this.filter_type = filter.filterType();
+ this.filter_name = filterName;
+ this.filter_disablePropertyName = filter.disablePropertyName();
+ this.filter_order = "" + filter.filterOrder();
+ this.application_name = ZuulApplicationInfo.getApplicationName();
+ isActive.set(false);
+ isCanary.set(false);
+ this.filter_id = buildFilterId();
+ }
+
+ public FilterInfo(String filter_id, int revision, Date creationDate, boolean isActive, boolean isCanary, String filter_code, String filter_type, String filter_name, String disablePropertyName, String filter_order, String application_name) {
+ this.filter_id = filter_id;
+ this.revision = revision;
+ this.creationDate = new Date(creationDate.getTime());
+ this.isActive.set(isActive);
+ this.isCanary.set(isCanary);
+ this.filter_code = filter_code;
+ this.filter_name = filter_name;
+ this.filter_type = filter_type;
+ this.filter_order = filter_order;
+ this.filter_disablePropertyName = disablePropertyName;
+ this.application_name = application_name;
+ }
+
/**
*
* @return the filter name; the class name of the filter
@@ -94,7 +124,6 @@ public String getFilterType() {
return filter_type;
}
-
@Override
public String toString() {
return "FilterInfo{" +
@@ -117,35 +146,6 @@ public String getApplication_name() {
return application_name;
}
- /**
- *
- * @param filter_id
- * @param revision
- * @param creationDate
- * @param isActive
- * @param isCanary
- * @param filter_code
- * @param filter_type
- * @param filter_name
- * @param disablePropertyName
- * @param filter_order
- * @param application_name
- */
- public FilterInfo(String filter_id, int revision, Date creationDate, boolean isActive, boolean isCanary, String filter_code, String filter_type, String filter_name, String disablePropertyName, String filter_order, String application_name) {
- this.filter_id = filter_id;
- this.revision = revision;
- this.creationDate = creationDate;
- this.isActive.set(isActive);
- this.isCanary.set(isCanary);
- this.filter_code = filter_code;
- this.filter_name = filter_name;
- this.filter_type = filter_type;
- this.filter_order = filter_order;
- this.filter_disablePropertyName = disablePropertyName;
- this.application_name = application_name;
-
- }
-
/**
*
* @return the revision of this filter
@@ -159,7 +159,7 @@ public int getRevision() {
* @return creation date
*/
public Date getCreationDate() {
- return creationDate;
+ return new Date(creationDate.getTime());
}
/**
@@ -179,7 +179,6 @@ public boolean isCanary() {
return isCanary.get();
}
-
/**
*
* @return unique key for the filter
@@ -204,7 +203,15 @@ public String getFilterOrder() {
* @return key is application_name:filter_name:filter_type
*/
public static String buildFilterID(String application_name, String filter_type, String filter_name) {
- return application_name + ":" + filter_name + ":" + filter_type;
+ return new FilterId.Builder().applicationName(application_name)
+ .filterType(filter_type)
+ .filterName(filter_name)
+ .build()
+ .toString();
+ }
+
+ public String buildFilterId() {
+ return buildFilterID(application_name, filter_type, filter_name);
}
@Override
@@ -247,4 +254,32 @@ public int compareTo(FilterInfo filterInfo) {
return filterInfo.getFilterName().compareTo(this.getFilterName());
}
+ public static class UnitTest {
+
+ @Test
+ public void verifyFilterId() {
+ FilterInfo filterInfo = new FilterInfo("", "", "", "", "", "", "");
+ long originalCreationTime = filterInfo.getCreationDate().getTime();
+ filterInfo.getCreationDate().setTime(0);
+ assertThat(filterInfo.getCreationDate().getTime(), is(originalCreationTime));
+ }
+
+ @Test
+ public void creationDateIsCopiedInGetter() {
+ FilterInfo filterInfo = new FilterInfo("", "", "", "", "", "", "");
+ long originalCreationTime = filterInfo.getCreationDate().getTime();
+ filterInfo.getCreationDate().setTime(0);
+ assertThat(filterInfo.getCreationDate().getTime(), is(originalCreationTime));
+ }
+
+ @Test
+ public void creationDateIsCopiedInConstructor() {
+ Date date = new Date();
+ long originalCreationTime = date.getTime();
+ FilterInfo filterInfo =
+ new FilterInfo("", 1, date, false, false, "", "", "", "", "", "");
+ date.setTime(0);
+ assertThat(filterInfo.getCreationDate().getTime(), is(originalCreationTime));
+ }
+ }
}
diff --git a/zuul-netflix/src/main/java/com/netflix/zuul/scriptManager/FilterVerifier.java b/zuul-netflix/src/main/java/com/netflix/zuul/scriptManager/FilterVerifier.java
index c776267bf2..4524c747a7 100644
--- a/zuul-netflix/src/main/java/com/netflix/zuul/scriptManager/FilterVerifier.java
+++ b/zuul-netflix/src/main/java/com/netflix/zuul/scriptManager/FilterVerifier.java
@@ -47,21 +47,18 @@ public static FilterVerifier getInstance() {
*
* @param sFilterCode
* @return a FilterInfo object representing that code
- * @throws org.codehaus.groovy.control.CompilationFailedException
+ * @throws CompilationFailedException
*
* @throws IllegalAccessException
* @throws InstantiationException
*/
- public FilterInfo verifyFilter(String sFilterCode) throws org.codehaus.groovy.control.CompilationFailedException, IllegalAccessException, InstantiationException {
+ public FilterInfo verifyFilter(String sFilterCode) throws CompilationFailedException, IllegalAccessException, InstantiationException {
Class groovyClass = compileGroovy(sFilterCode);
Object instance = instanciateClass(groovyClass);
checkZuulFilterInstance(instance);
ZuulFilter filter = (ZuulFilter) instance;
-
- String filter_id = FilterInfo.buildFilterID(ZuulApplicationInfo.getApplicationName(), filter.filterType(), groovyClass.getSimpleName());
-
- return new FilterInfo(filter_id, sFilterCode, filter.filterType(), groovyClass.getSimpleName(), filter.disablePropertyName(), "" + filter.filterOrder(), ZuulApplicationInfo.getApplicationName());
+ return new FilterInfo(sFilterCode, groovyClass.getSimpleName(), filter);
}
Object instanciateClass(Class groovyClass) throws InstantiationException, IllegalAccessException {
@@ -79,10 +76,10 @@ void checkZuulFilterInstance(Object zuulFilter) throws InstantiationException {
*
* @param sFilterCode
* @return
- * @throws org.codehaus.groovy.control.CompilationFailedException
+ * @throws CompilationFailedException
*
*/
- public Class compileGroovy(String sFilterCode) throws org.codehaus.groovy.control.CompilationFailedException {
+ public Class compileGroovy(String sFilterCode) throws CompilationFailedException {
GroovyClassLoader loader = new GroovyClassLoader();
return loader.parseClass(sFilterCode);
}
@@ -277,5 +274,3 @@ public void testVerify() {
}
}
-
-
diff --git a/zuul-netflix/src/main/java/com/netflix/zuul/scriptManager/ZuulFilterDAOCassandra.java b/zuul-netflix/src/main/java/com/netflix/zuul/scriptManager/ZuulFilterDAOCassandra.java
index e2130f4940..caef2de973 100644
--- a/zuul-netflix/src/main/java/com/netflix/zuul/scriptManager/ZuulFilterDAOCassandra.java
+++ b/zuul-netflix/src/main/java/com/netflix/zuul/scriptManager/ZuulFilterDAOCassandra.java
@@ -15,18 +15,30 @@
*/
package com.netflix.zuul.scriptManager;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Observable;
+
import com.netflix.astyanax.AstyanaxContext;
import com.netflix.astyanax.Keyspace;
import com.netflix.astyanax.model.Column;
import com.netflix.astyanax.model.ColumnList;
import com.netflix.astyanax.model.Row;
import com.netflix.astyanax.model.Rows;
+import com.netflix.zuul.FilterId;
import com.netflix.zuul.ZuulApplicationInfo;
import com.netflix.zuul.dependency.cassandra.hystrix.HystrixCassandraGetRowsByKeys;
import com.netflix.zuul.dependency.cassandra.hystrix.HystrixCassandraGetRowsByQuery;
import com.netflix.zuul.dependency.cassandra.hystrix.HystrixCassandraPut;
import com.netflix.zuul.event.ZuulEvent;
-import net.jcip.annotations.ThreadSafe;
+
import org.junit.Before;
import org.junit.Test;
import org.mockito.InOrder;
@@ -35,11 +47,22 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.*;
+import net.jcip.annotations.ThreadSafe;
-import static org.junit.Assert.*;
+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.mockito.Matchers.anyString;
-import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.anyList;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
/**
* from zuul_filters
@@ -318,8 +341,10 @@ public FilterInfo addFilter(String filtercode, String filter_type, String filter
}
public static String buildFilterID(String filter_type, String filter_name) {
- return FilterInfo.buildFilterID(ZuulApplicationInfo.getApplicationName(), filter_type, filter_name);
-
+ return new FilterId.Builder().filterType(filter_type)
+ .filterName(filter_name)
+ .build()
+ .toString();
}
@Override
diff --git a/zuul-simple-webapp/build.gradle b/zuul-simple-webapp/build.gradle
index a5ba065e6c..7f21f769d5 100644
--- a/zuul-simple-webapp/build.gradle
+++ b/zuul-simple-webapp/build.gradle
@@ -1,20 +1,16 @@
-apply plugin: 'java'
apply plugin: 'war'
-apply plugin: 'eclipse'
-apply plugin: 'idea'
apply plugin: 'jetty'
dependencies {
compile project(":zuul-core")
-
- compile 'org.apache.httpcomponents:httpclient:4.3.2'
- provided 'javax.servlet:servlet-api:2.5'
+
+ compile 'org.apache.httpcomponents:httpclient:4.5'
+ providedCompile 'javax.servlet:servlet-api:2.5'
}
eclipse {
classpath {
- plusConfigurations += configurations.provided
downloadSources = true
downloadJavadoc = true
}
@@ -29,12 +25,6 @@ war {
}
}
-idea {
- module {
- scopes.PROVIDED.plus += configurations.provided
- }
-}
-
jettyRun.contextPath = '/'
jettyRun.doFirst {
diff --git a/zuul-simple-webapp/src/main/groovy/filters/post/SendResponse.groovy b/zuul-simple-webapp/src/main/groovy/filters/post/SendResponseFilter.groovy
similarity index 74%
rename from zuul-simple-webapp/src/main/groovy/filters/post/SendResponse.groovy
rename to zuul-simple-webapp/src/main/groovy/filters/post/SendResponseFilter.groovy
index db469c9a52..c63cbf0af5 100644
--- a/zuul-simple-webapp/src/main/groovy/filters/post/SendResponse.groovy
+++ b/zuul-simple-webapp/src/main/groovy/filters/post/SendResponseFilter.groovy
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package filters.post
import com.netflix.config.DynamicBooleanProperty
import com.netflix.config.DynamicIntProperty
@@ -23,21 +24,22 @@ import com.netflix.zuul.constants.ZuulConstants
import com.netflix.zuul.constants.ZuulHeaders
import com.netflix.zuul.context.Debug
import com.netflix.zuul.context.RequestContext
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mockito
-import org.mockito.runners.MockitoJUnitRunner
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
-import java.util.zip.GZIPInputStream
import javax.servlet.http.HttpServletResponse
+import java.nio.charset.Charset
+import java.util.zip.GZIPInputStream
+import java.util.zip.ZipException
class SendResponseFilter extends ZuulFilter {
+ private static final Logger LOG = LoggerFactory.getLogger(SendResponseFilter.class);
static DynamicBooleanProperty INCLUDE_DEBUG_HEADER =
- DynamicPropertyFactory.getInstance().getBooleanProperty(ZuulConstants.ZUUL_INCLUDE_DEBUG_HEADER, false);
+ DynamicPropertyFactory.getInstance().getBooleanProperty(ZuulConstants.ZUUL_INCLUDE_DEBUG_HEADER, false);
static DynamicIntProperty INITIAL_STREAM_BUFFER_SIZE =
- DynamicPropertyFactory.getInstance().getIntProperty(ZuulConstants.ZUUL_INITIAL_STREAM_BUFFER_SIZE, 1024);
+ DynamicPropertyFactory.getInstance().getIntProperty(ZuulConstants.ZUUL_INITIAL_STREAM_BUFFER_SIZE, 1024);
static DynamicBooleanProperty SET_CONTENT_LENGTH = DynamicPropertyFactory.getInstance().getBooleanProperty(ZuulConstants.ZUUL_SET_CONTENT_LENGTH, false);
@@ -52,9 +54,9 @@ class SendResponseFilter extends ZuulFilter {
}
boolean shouldFilter() {
- return !RequestContext.currentContext.getZuulResponseHeaders().isEmpty() ||
- RequestContext.currentContext.getResponseDataStream() != null ||
- RequestContext.currentContext.responseBody != null
+ return !RequestContext.getCurrentContext().getZuulResponseHeaders().isEmpty() ||
+ RequestContext.getCurrentContext().getResponseDataStream() != null ||
+ RequestContext.getCurrentContext().responseBody != null
}
Object run() {
@@ -63,10 +65,11 @@ class SendResponseFilter extends ZuulFilter {
}
void writeResponse() {
- RequestContext context = RequestContext.currentContext
+ RequestContext context = RequestContext.getCurrentContext()
- // there is no body to send
- if (context.getResponseBody() == null && context.getResponseDataStream() == null) return;
+ if (context.getResponseBody() == null && context.getResponseDataStream() == null) {
+ return
+ };
HttpServletResponse servletResponse = context.getResponse()
servletResponse.setCharacterEncoding("UTF-8")
@@ -74,9 +77,9 @@ class SendResponseFilter extends ZuulFilter {
OutputStream outStream = servletResponse.getOutputStream();
InputStream is = null
try {
- if (RequestContext.currentContext.responseBody != null) {
- String body = RequestContext.currentContext.responseBody
- writeResponse(new ByteArrayInputStream(body.bytes), outStream)
+ if (RequestContext.getCurrentContext().responseBody != null) {
+ String body = RequestContext.getCurrentContext().responseBody
+ writeResponse(new ByteArrayInputStream(body.getBytes(Charset.forName("UTF-8"))), outStream)
return;
}
@@ -89,19 +92,16 @@ class SendResponseFilter extends ZuulFilter {
InputStream inputStream = is
if (is != null) {
if (context.sendZuulResponse()) {
- // if origin response is gzipped, and client has not requested gzip, decompress stream
- // before sending to client
- // else, stream gzip directly to client
if (context.getResponseGZipped() && !isGzipRequested)
try {
inputStream = new GZIPInputStream(is);
-
- } catch (java.util.zip.ZipException e) {
- println("gzip expected but not received assuming unencoded response" + RequestContext.currentContext.getRequest().getRequestURL().toString())
+ } catch (ZipException e) {
+ LOG.error("gzip expected but not received assuming unencoded response" + RequestContext.getCurrentContext().getRequest().getRequestURL().toString())
inputStream = is
}
- else if (context.getResponseGZipped() && isGzipRequested)
+ else if (context.getResponseGZipped() && isGzipRequested) {
servletResponse.setHeader(ZuulHeaders.CONTENT_ENCODING, "gzip")
+ }
writeResponse(inputStream, outStream)
}
}
@@ -109,11 +109,9 @@ class SendResponseFilter extends ZuulFilter {
} finally {
try {
is?.close();
-
outStream.flush()
outStream.close()
} catch (IOException e) {
-
}
}
}
@@ -122,15 +120,11 @@ class SendResponseFilter extends ZuulFilter {
byte[] bytes = new byte[INITIAL_STREAM_BUFFER_SIZE.get()];
int bytesRead = -1;
while ((bytesRead = zin.read(bytes)) != -1) {
-// if (Debug.debugRequest() && !Debug.debugRequestHeadersOnly()) {
-// Debug.addRequestDebug("OUTBOUND: < " + new String(bytes, 0, bytesRead));
-// }
try {
out.write(bytes, 0, bytesRead);
out.flush();
} catch (IOException e) {
- //ignore
e.printStackTrace()
}
@@ -154,13 +148,6 @@ class SendResponseFilter extends ZuulFilter {
debugHeader += "[[[${it}]]]";
}
- /*
- rd = (List) RequestContext.getCurrentContext().get("requestDebug");
- rd?.each {
- debugHeader += "[[[REQUEST_DEBUG::${it}]]]";
- }
- */
-
if (INCLUDE_DEBUG_HEADER.get()) servletResponse.addHeader("X-Zuul-Debug-Header", debugHeader)
if (Debug.debugRequest()) {
@@ -184,4 +171,4 @@ class SendResponseFilter extends ZuulFilter {
}
}
-}
\ No newline at end of file
+}
diff --git a/zuul-simple-webapp/src/main/groovy/filters/post/Stats.groovy b/zuul-simple-webapp/src/main/groovy/filters/post/Stats.groovy
index 041fe80eae..23b4f9800f 100755
--- a/zuul-simple-webapp/src/main/groovy/filters/post/Stats.groovy
+++ b/zuul-simple-webapp/src/main/groovy/filters/post/Stats.groovy
@@ -13,19 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package scripts.postProcess
+package filters.post
import com.netflix.zuul.ZuulFilter
import com.netflix.zuul.context.RequestContext
-import org.junit.Assert
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.runners.MockitoJUnitRunner
-
-import javax.servlet.http.HttpServletRequest
-import javax.servlet.http.HttpServletResponse
-
/**
* @author Mikey Cohen
* Date: 2/3/12
diff --git a/zuul-simple-webapp/src/main/groovy/filters/pre/Debug.groovy b/zuul-simple-webapp/src/main/groovy/filters/pre/DebugFilter.groovy
similarity index 94%
rename from zuul-simple-webapp/src/main/groovy/filters/pre/Debug.groovy
rename to zuul-simple-webapp/src/main/groovy/filters/pre/DebugFilter.groovy
index 72da19d5a3..14db5ba6e8 100644
--- a/zuul-simple-webapp/src/main/groovy/filters/pre/Debug.groovy
+++ b/zuul-simple-webapp/src/main/groovy/filters/pre/DebugFilter.groovy
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package scripts.preProcess
+package filters.pre
import com.netflix.config.DynamicBooleanProperty
import com.netflix.config.DynamicPropertyFactory
@@ -38,9 +38,11 @@ class DebugFilter extends ZuulFilter {
}
boolean shouldFilter() {
- if ("true".equals(RequestContext.getCurrentContext().getRequest().getParameter(debugParameter.get()))) return true;
- return routingDebug.get();
+ if ("true".equals(RequestContext.getCurrentContext().getRequest().getParameter(debugParameter.get()))) {
+ return true
+ }
+ return routingDebug.get();
}
Object run() {
diff --git a/zuul-simple-webapp/src/main/groovy/filters/pre/DebugRequest.groovy b/zuul-simple-webapp/src/main/groovy/filters/pre/DebugRequest.groovy
index 5fd38d6d7e..b929220503 100644
--- a/zuul-simple-webapp/src/main/groovy/filters/pre/DebugRequest.groovy
+++ b/zuul-simple-webapp/src/main/groovy/filters/pre/DebugRequest.groovy
@@ -13,21 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package scripts.preProcess
+package filters.pre
import com.netflix.zuul.ZuulFilter
import com.netflix.zuul.context.Debug
import com.netflix.zuul.context.RequestContext
-import org.junit.Assert
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.Mockito
-import org.mockito.runners.MockitoJUnitRunner
import javax.servlet.http.HttpServletRequest
-import javax.servlet.http.HttpServletResponse
-
/**
* @author Mikey Cohen
* Date: 3/12/12
@@ -62,7 +54,6 @@ class DebugRequest extends ZuulFilter {
String name = (String) headerIt.next()
String value = req.getHeader(name)
Debug.addRequestDebug("REQUEST:: > " + name + ":" + value)
-
}
final RequestContext ctx = RequestContext.getCurrentContext()
diff --git a/zuul-simple-webapp/src/main/groovy/filters/pre/PreDecoration.groovy b/zuul-simple-webapp/src/main/groovy/filters/pre/PreDecorationFilter.groovy
similarity index 92%
rename from zuul-simple-webapp/src/main/groovy/filters/pre/PreDecoration.groovy
rename to zuul-simple-webapp/src/main/groovy/filters/pre/PreDecorationFilter.groovy
index 0ef694bde3..2925753cdf 100644
--- a/zuul-simple-webapp/src/main/groovy/filters/pre/PreDecoration.groovy
+++ b/zuul-simple-webapp/src/main/groovy/filters/pre/PreDecorationFilter.groovy
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package filters.pre
import com.netflix.zuul.ZuulFilter
import com.netflix.zuul.context.RequestContext
@@ -44,6 +45,9 @@ class PreDecorationFilter extends ZuulFilter {
// sets origin
ctx.setRouteHost(new URL("http://apache.org/"));
+ // set origin host header
+ ctx.addZuulRequestHeader("Host","apache.org");
+
// sets custom header to send to the origin
ctx.addOriginResponseHeader("cache-control", "max-age=3600");
}
diff --git a/zuul-simple-webapp/src/main/groovy/filters/route/SimpleHostRequest.groovy b/zuul-simple-webapp/src/main/groovy/filters/route/SimpleHostRoutingFilter.groovy
similarity index 60%
rename from zuul-simple-webapp/src/main/groovy/filters/route/SimpleHostRequest.groovy
rename to zuul-simple-webapp/src/main/groovy/filters/route/SimpleHostRoutingFilter.groovy
index f6d477f0a0..2df81e630f 100644
--- a/zuul-simple-webapp/src/main/groovy/filters/route/SimpleHostRequest.groovy
+++ b/zuul-simple-webapp/src/main/groovy/filters/route/SimpleHostRoutingFilter.groovy
@@ -13,8 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-
+package filters.route
import com.netflix.config.DynamicIntProperty
import com.netflix.config.DynamicPropertyFactory
@@ -23,33 +22,33 @@ import com.netflix.zuul.constants.ZuulConstants
import com.netflix.zuul.context.Debug
import com.netflix.zuul.context.RequestContext
import com.netflix.zuul.util.HTTPRequestUtils
-import org.apache.http.Header
-import org.apache.http.HttpHost
-import org.apache.http.HttpRequest
-import org.apache.http.HttpResponse
+import org.apache.http.*
import org.apache.http.client.HttpClient
+import org.apache.http.client.RedirectStrategy
import org.apache.http.client.methods.HttpPost
import org.apache.http.client.methods.HttpPut
-import org.apache.http.client.params.ClientPNames
-import org.apache.http.conn.ClientConnectionManager
-import org.apache.http.conn.scheme.PlainSocketFactory
-import org.apache.http.conn.scheme.Scheme
-import org.apache.http.conn.scheme.SchemeRegistry
+import org.apache.http.client.methods.HttpUriRequest
+import org.apache.http.config.Registry
+import org.apache.http.config.RegistryBuilder
+import org.apache.http.conn.HttpClientConnectionManager
+import org.apache.http.conn.socket.ConnectionSocketFactory
+import org.apache.http.conn.socket.PlainConnectionSocketFactory
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory
+import org.apache.http.conn.ssl.SSLContexts
import org.apache.http.entity.InputStreamEntity
-import org.apache.http.impl.client.DefaultHttpClient
+import org.apache.http.impl.client.CloseableHttpClient
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler
-import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager
+import org.apache.http.impl.client.HttpClientBuilder
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager
import org.apache.http.message.BasicHeader
import org.apache.http.message.BasicHttpRequest
-import org.apache.http.params.CoreConnectionPNames
-import org.apache.http.params.HttpParams
import org.apache.http.protocol.HttpContext
import org.slf4j.Logger
import org.slf4j.LoggerFactory
+import javax.net.ssl.SSLContext
import javax.servlet.http.HttpServletRequest
import java.util.concurrent.atomic.AtomicReference
-import java.util.zip.GZIPInputStream
class SimpleHostRoutingFilter extends ZuulFilter {
@@ -64,12 +63,12 @@ class SimpleHostRoutingFilter extends ZuulFilter {
}
private static final DynamicIntProperty SOCKET_TIMEOUT =
- DynamicPropertyFactory.getInstance().getIntProperty(ZuulConstants.ZUUL_HOST_SOCKET_TIMEOUT_MILLIS, 10000)
+ DynamicPropertyFactory.getInstance().getIntProperty(ZuulConstants.ZUUL_HOST_SOCKET_TIMEOUT_MILLIS, 10000)
private static final DynamicIntProperty CONNECTION_TIMEOUT =
- DynamicPropertyFactory.getInstance().getIntProperty(ZuulConstants.ZUUL_HOST_CONNECT_TIMEOUT_MILLIS, 2000)
+ DynamicPropertyFactory.getInstance().getIntProperty(ZuulConstants.ZUUL_HOST_CONNECT_TIMEOUT_MILLIS, 2000)
- private static final AtomicReference CLIENT = new AtomicReference(newClient());
+ private static final AtomicReference CLIENT = new AtomicReference(newClient());
private static final Timer CONNECTION_MANAGER_TIMER = new Timer(true);
@@ -81,9 +80,13 @@ class SimpleHostRoutingFilter extends ZuulFilter {
@Override
void run() {
try {
- final HttpClient hc = CLIENT.get();
- if (hc == null) return;
- hc.getConnectionManager().closeExpiredConnections();
+ final CloseableHttpClient hc = CLIENT.get();
+
+ if (hc == null) {
+ return;
+ }
+
+ hc.close();
} catch (Throwable t) {
LOG.error("error closing expired connections", t);
}
@@ -93,12 +96,15 @@ class SimpleHostRoutingFilter extends ZuulFilter {
public SimpleHostRoutingFilter() {}
- private static final ClientConnectionManager newConnectionManager() {
- SchemeRegistry schemeRegistry = new SchemeRegistry();
- schemeRegistry.register(
- new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));
+ private static final HttpClientConnectionManager newConnectionManager() {
+ SSLContext sslContext = SSLContexts.createSystemDefault();
- ClientConnectionManager cm = new ThreadSafeClientConnManager(schemeRegistry);
+ Registry socketFactoryRegistry = RegistryBuilder.create()
+ .register("http", PlainConnectionSocketFactory.INSTANCE)
+ .register("https", new SSLConnectionSocketFactory(sslContext))
+ .build();
+
+ HttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
cm.setMaxTotal(Integer.parseInt(System.getProperty("zuul.max.host.connections", "200")));
cm.setDefaultMaxPerRoute(Integer.parseInt(System.getProperty("zuul.max.host.connections", "20")));
return cm;
@@ -115,18 +121,18 @@ class SimpleHostRoutingFilter extends ZuulFilter {
}
boolean shouldFilter() {
- return RequestContext.currentContext.getRouteHost() != null && RequestContext.currentContext.sendZuulResponse()
+ return RequestContext.getCurrentContext().getRouteHost() != null && RequestContext.getCurrentContext().sendZuulResponse()
}
private static final void loadClient() {
- final HttpClient oldClient = CLIENT.get();
+ final CloseableHttpClient oldClient = CLIENT.get();
CLIENT.set(newClient())
if (oldClient != null) {
CONNECTION_MANAGER_TIMER.schedule(new TimerTask() {
@Override
void run() {
try {
- oldClient.getConnectionManager().shutdown();
+ oldClient.close()
} catch (Throwable t) {
LOG.error("error shutting down old connection manager", t);
}
@@ -136,43 +142,42 @@ class SimpleHostRoutingFilter extends ZuulFilter {
}
- private static final HttpClient newClient() {
- // I could statically cache the connection manager but we will probably want to make some of its properties
- // dynamic in the near future also
- HttpClient httpclient = new DefaultHttpClient(newConnectionManager());
- HttpParams httpParams = httpclient.getParams();
- httpParams.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, SOCKET_TIMEOUT.get())
- httpParams.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, CONNECTION_TIMEOUT.get())
- httpclient.setHttpRequestRetryHandler(new DefaultHttpRequestRetryHandler(0, false))
- httpParams.setParameter(ClientPNames.COOKIE_POLICY, org.apache.http.client.params.CookiePolicy.IGNORE_COOKIES);
- httpclient.setRedirectStrategy(new org.apache.http.client.RedirectStrategy() {
+ private static final CloseableHttpClient newClient() {
+ HttpClientBuilder builder = HttpClientBuilder.create()
+ builder.setConnectionManager(newConnectionManager())
+ builder.setRetryHandler(new DefaultHttpRequestRetryHandler(0, false))
+ builder.setRedirectStrategy(new RedirectStrategy() {
@Override
- boolean isRedirected(HttpRequest httpRequest, HttpResponse httpResponse, HttpContext httpContext) {
+ boolean isRedirected(HttpRequest httpRequest, HttpResponse httpResponse, HttpContext httpContext) throws ProtocolException {
return false
}
@Override
- org.apache.http.client.methods.HttpUriRequest getRedirect(HttpRequest httpRequest, HttpResponse httpResponse, HttpContext httpContext) {
+ HttpUriRequest getRedirect(HttpRequest httpRequest, HttpResponse httpResponse, HttpContext httpContext) throws ProtocolException {
return null
}
})
- return httpclient
+
+ return builder.build()
}
Object run() {
- HttpServletRequest request = RequestContext.currentContext.getRequest();
+ HttpServletRequest request = RequestContext.getCurrentContext().getRequest();
Header[] headers = buildZuulRequestHeaders(request)
String verb = getVerb(request);
InputStream requestEntity = getRequestBody(request)
- HttpClient httpclient = CLIENT.get()
+ CloseableHttpClient httpclient = CLIENT.get()
String uri = request.getRequestURI()
- if (RequestContext.currentContext.requestURI != null) {
- uri = RequestContext.currentContext.requestURI
+ if (RequestContext.getCurrentContext().requestURI != null) {
+ uri = RequestContext.getCurrentContext().requestURI
}
try {
HttpResponse response = forward(httpclient, verb, uri, request, headers, requestEntity)
+ Debug.addRequestDebug("ZUUL :: ${uri}")
+ Debug.addRequestDebug("ZUUL :: Response statusLine > ${response.getStatusLine()}")
+ Debug.addRequestDebug("ZUUL :: Response code > ${response.getStatusLine().statusCode}")
setResponse(response)
} catch (Exception e) {
throw e;
@@ -180,18 +185,16 @@ class SimpleHostRoutingFilter extends ZuulFilter {
return null
}
- def InputStream debug(HttpClient httpclient, String verb, String uri, HttpServletRequest request, Header[] headers, InputStream requestEntity) {
+ InputStream debug(String verb, String uri, HttpServletRequest request, Header[] headers, InputStream requestEntity) {
if (Debug.debugRequest()) {
-
- Debug.addRequestDebug("ZUUL:: host=${RequestContext.currentContext.getRouteHost()}")
-
+ Debug.addRequestDebug("ZUUL:: host=${RequestContext.getCurrentContext().getRouteHost()}")
headers.each {
- Debug.addRequestDebug("ZUUL::> ${it.name} ${it.value}")
+ Debug.addRequestDebug("ZUUL:: Header > ${it.name} ${it.value}")
}
- String query = request.queryString
+ String query = request.queryString != null ? "?" + request.queryString : ""
- Debug.addRequestDebug("ZUUL:: > ${verb} ${uri}?${query} HTTP/1.1")
+ Debug.addRequestDebug("ZUUL:: > ${verb} ${uri}${query} HTTP/1.1")
if (requestEntity != null) {
requestEntity = debugRequestEntity(requestEntity)
}
@@ -201,22 +204,24 @@ class SimpleHostRoutingFilter extends ZuulFilter {
}
InputStream debugRequestEntity(InputStream inputStream) {
- if (Debug.debugRequestHeadersOnly()) return inputStream
- if (inputStream == null) return null
+ if (Debug.debugRequestHeadersOnly()) {
+ return inputStream
+ }
+
+ if (inputStream == null) {
+ return null
+ }
+
String entity = inputStream.getText()
- Debug.addRequestDebug("ZUUL::> ${entity}")
+ Debug.addRequestDebug("ZUUL:: Entity > ${entity}")
return new ByteArrayInputStream(entity.bytes)
}
- def HttpResponse forward(HttpClient httpclient, String verb, String uri, HttpServletRequest request, Header[] headers, InputStream requestEntity) {
-
- requestEntity = debug(httpclient, verb, uri, request, headers, requestEntity)
-
- org.apache.http.HttpHost httpHost
+ HttpResponse forward(CloseableHttpClient httpclient, String verb, String uri, HttpServletRequest request, Header[] headers, InputStream requestEntity) {
- httpHost = getHttpHost()
-
- org.apache.http.HttpRequest httpRequest;
+ requestEntity = debug(verb, uri, request, headers, requestEntity)
+ HttpHost httpHost = getHttpHost()
+ HttpRequest httpRequest;
switch (verb) {
case 'POST':
@@ -235,15 +240,10 @@ class SimpleHostRoutingFilter extends ZuulFilter {
try {
httpRequest.setHeaders(headers)
- HttpResponse zuulResponse = forwardRequest(httpclient, httpHost, httpRequest)
- return zuulResponse
+ return forwardRequest(httpclient, httpHost, httpRequest)
} finally {
- // When HttpClient instance is no longer needed,
- // shut down the connection manager to ensure
- // immediate deallocation of all system resources
-// httpclient.getConnectionManager().shutdown();
+ //httpclient.close();
}
-
}
HttpResponse forwardRequest(HttpClient httpclient, HttpHost httpHost, HttpRequest httpRequest) {
@@ -262,14 +262,14 @@ class SimpleHostRoutingFilter extends ZuulFilter {
}
String getQueryString() {
- HttpServletRequest request = RequestContext.currentContext.getRequest();
+ HttpServletRequest request = RequestContext.getCurrentContext().getRequest();
String query = request.getQueryString()
return (query != null) ? query : "";
}
HttpHost getHttpHost() {
HttpHost httpHost
- URL host = RequestContext.currentContext.getRouteHost()
+ URL host = RequestContext.getCurrentContext().getRouteHost()
httpHost = new HttpHost(host.getHost(), host.getPort(), host.getProtocol())
@@ -277,73 +277,94 @@ class SimpleHostRoutingFilter extends ZuulFilter {
}
- def getRequestBody(HttpServletRequest request) {
- Object requestEntity = null;
+ InputStream getRequestBody(HttpServletRequest request) {
try {
- requestEntity = request.getInputStream();
+ return request.getInputStream();
} catch (IOException e) {
- //no requestBody is ok.
+ LOG.warn(e.getMessage())
+ return null
}
- return requestEntity
}
boolean isValidHeader(String name) {
- if (name.toLowerCase().contains("content-length")) return false;
- if (!RequestContext.currentContext.responseGZipped) {
- if (name.toLowerCase().contains("accept-encoding")) return false;
+ if (name.toLowerCase().contains("content-length")) {
+ return false
+ }
+
+ if (name.toLowerCase().equals("host")) {
+ return false
}
- return true;
+
+ if (!RequestContext.getCurrentContext().responseGZipped) {
+ if (name.toLowerCase().contains("accept-encoding")) {
+ return false
+ }
+ }
+ return true
}
- def Header[] buildZuulRequestHeaders(HttpServletRequest request) {
+ Header[] buildZuulRequestHeaders(HttpServletRequest request) {
- def headers = new ArrayList()
+ ArrayList headers = new ArrayList()
Enumeration headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
- String name = (String) headerNames.nextElement();
+ String name = ((String) headerNames.nextElement()).toLowerCase();
String value = request.getHeader(name);
if (isValidHeader(name)) headers.add(new BasicHeader(name, value))
}
- Map zuulRequestHeaders = RequestContext.getCurrentContext().getZuulRequestHeaders();
+ Map zuulRequestHeaders = RequestContext.getCurrentContext().getZuulRequestHeaders();
- zuulRequestHeaders.keySet().each {
+ zuulRequestHeaders.keySet().each { String it ->
String name = it.toLowerCase()
BasicHeader h = headers.find { BasicHeader he -> he.name == name }
if (h != null) {
headers.remove(h)
}
- headers.add(new BasicHeader((String) it, (String) zuulRequestHeaders[it]))
+ headers.add(new BasicHeader(it, zuulRequestHeaders[it]))
}
- if (RequestContext.currentContext.responseGZipped) {
+ if (RequestContext.getCurrentContext().responseGZipped) {
headers.add(new BasicHeader("accept-encoding", "deflate, gzip"))
}
+
return headers
}
-
- String getVerb(HttpServletRequest request) {
- String sMethod = request.getMethod();
- return sMethod.toUpperCase();
+ String getVerb(HttpServletRequest request) {
+ return getVerb(request.getMethod().toUpperCase());
}
String getVerb(String sMethod) {
- if (sMethod == null) return "GET";
+ if (sMethod == null) {
+ return "GET"
+ }
+
sMethod = sMethod.toLowerCase();
- if (sMethod.equalsIgnoreCase("post")) return "POST"
- if (sMethod.equalsIgnoreCase("put")) return "PUT"
- if (sMethod.equalsIgnoreCase("delete")) return "DELETE"
- if (sMethod.equalsIgnoreCase("options")) return "OPTIONS"
- if (sMethod.equalsIgnoreCase("head")) return "HEAD"
+
+ if (sMethod.equalsIgnoreCase("post")) {
+ return "POST"
+ }
+ if (sMethod.equalsIgnoreCase("put")) {
+ return "PUT"
+ }
+ if (sMethod.equalsIgnoreCase("delete")) {
+ return "DELETE"
+ }
+ if (sMethod.equalsIgnoreCase("options")) {
+ return "OPTIONS"
+ }
+ if (sMethod.equalsIgnoreCase("head")) {
+ return "HEAD"
+ }
return "GET"
}
void setResponse(HttpResponse response) {
RequestContext context = RequestContext.getCurrentContext()
- RequestContext.currentContext.set("hostZuulResponse", response)
+ RequestContext.getCurrentContext().set("hostZuulResponse", response)
RequestContext.getCurrentContext().setResponseStatusCode(response.getStatusLine().statusCode)
RequestContext.getCurrentContext().responseDataStream = response?.entity?.content
@@ -368,16 +389,8 @@ class SimpleHostRoutingFilter extends ZuulFilter {
if (context.responseDataStream) {
byte[] origBytes = context.getResponseDataStream().bytes
- ByteArrayInputStream byteStream = new ByteArrayInputStream(origBytes)
- InputStream inputStream = byteStream
- if (RequestContext.currentContext.responseGZipped) {
- inputStream = new GZIPInputStream(byteStream);
- }
-
-
context.setResponseDataStream(new ByteArrayInputStream(origBytes))
}
-
} else {
response.getAllHeaders()?.each { Header header ->
RequestContext ctx = RequestContext.getCurrentContext()
@@ -406,7 +419,6 @@ class SimpleHostRoutingFilter extends ZuulFilter {
return true
}
}
-
}
diff --git a/zuul-simple-webapp/src/main/java/com/netflix/zuul/StartServer.java b/zuul-simple-webapp/src/main/java/com/netflix/zuul/StartServer.java
index 95711b7a25..aae5aaab69 100644
--- a/zuul-simple-webapp/src/main/java/com/netflix/zuul/StartServer.java
+++ b/zuul-simple-webapp/src/main/java/com/netflix/zuul/StartServer.java
@@ -16,19 +16,16 @@
package com.netflix.zuul;
-import java.io.File;
-
-import javax.servlet.ServletContextEvent;
-import javax.servlet.ServletContextListener;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.filters.FilterRegistry;
import com.netflix.zuul.groovy.GroovyCompiler;
import com.netflix.zuul.groovy.GroovyFileFilter;
import com.netflix.zuul.monitoring.MonitoringHelper;
+import java.io.File;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class StartServer implements ServletContextListener {