diff --git a/.gitignore b/.gitignore index 3cde4d575d..b7c6beee06 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ target +.flattened-pom.xml work # IntelliJ project files diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml new file mode 100644 index 0000000000..b2d9947894 --- /dev/null +++ b/.mvn/extensions.xml @@ -0,0 +1,7 @@ + + + io.jenkins.tools + git-changelist-maven-extension + 1.0-alpha-3 + + diff --git a/.mvn/maven.config b/.mvn/maven.config new file mode 100644 index 0000000000..e54fdacfe6 --- /dev/null +++ b/.mvn/maven.config @@ -0,0 +1 @@ +-Pmight-produce-incrementals diff --git a/Jenkinsfile b/Jenkinsfile index 20ac0b0b63..031633d05e 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -30,6 +30,9 @@ for(i = 0; i < buildTypes.size(); i++) { checkout scm } + def changelistF = "${pwd tmp: true}/changelist" + def m2repo = "${pwd tmp: true}/m2repo" + // Now run the actual build. stage("${buildType} Build / Test") { timeout(time: 180, unit: 'MINUTES') { @@ -39,7 +42,7 @@ for(i = 0; i < buildTypes.size(); i++) { "MAVEN_OPTS=-Xmx1536m -Xms512m"]) { // Actually run Maven! // -Dmaven.repo.local=… tells Maven to create a subdir in the temporary directory for the local Maven repository - def mvnCmd = "mvn -Pdebug -U javadoc:javadoc clean install ${runTests ? '-Dmaven.test.failure.ignore' : '-DskipTests'} -V -B -Dmaven.repo.local=${pwd tmp: true}/m2repo -s settings-azure.xml -e" + def mvnCmd = "mvn -Pdebug -U -Dset.changelist help:evaluate -Dexpression=changelist -Doutput=$changelistF clean install ${runTests ? '-Dmaven.test.failure.ignore' : '-DskipTests'} -V -B -Dmaven.repo.local=$m2repo -s settings-azure.xml -e" if(isUnix()) { sh mvnCmd sh 'test `git status --short | tee /dev/stderr | wc --bytes` -eq 0' @@ -52,14 +55,17 @@ for(i = 0; i < buildTypes.size(); i++) { // Once we've built, archive the artifacts and the test results. stage("${buildType} Publishing") { - def files = findFiles(glob: '**/target/*.jar, **/target/*.war, **/target/*.hpi') - renameFiles(files, buildType.toLowerCase()) - - archiveArtifacts artifacts: '**/target/*.jar, **/target/*.war, **/target/*.hpi', - fingerprint: true if (runTests) { junit healthScaleFactor: 20.0, testResults: '*/target/surefire-reports/*.xml' } + if (buildType == 'Linux') { + def changelist = readFile(changelistF) + dir(m2repo) { + archiveArtifacts artifacts: "**/*$changelist/*$changelist*", + excludes: '**/*.lastUpdated,**/jenkins-test/', + fingerprint: true + } + } } } } @@ -76,7 +82,7 @@ builds.ath = { checkout scm withMavenEnv(["JAVA_OPTS=-Xmx1536m -Xms512m", "MAVEN_OPTS=-Xmx1536m -Xms512m"]) { - sh "mvn -DskipTests -am -pl war package -Dmaven.repo.local=${pwd tmp: true}/m2repo -s settings-azure.xml" + sh "mvn --batch-mode --show-version -DskipTests -am -pl war package -Dmaven.repo.local=${pwd tmp: true}/m2repo -s settings-azure.xml" } dir("war/target") { fileUri = "file://" + pwd() + "/jenkins.war" @@ -91,6 +97,7 @@ builds.ath = { builds.failFast = failFast parallel builds +infra.maybePublishIncrementals() // This method sets up the Maven and JDK tools, puts them in the environment along // with whatever other arbitrary environment variables we passed in, and runs the @@ -115,15 +122,3 @@ void withMavenEnv(List envVars = [], def body) { body.call() } } - -void renameFiles(def files, String prefix) { - for(i = 0; i < files.length; i++) { - def newPath = files[i].path.replace(files[i].name, "${prefix}-${files[i].name}") - def rename = "${files[i].path} ${newPath}" - if(isUnix()) { - sh "mv ${rename}" - } else { - bat "move ${rename}" - } - } -} diff --git a/cli/pom.xml b/cli/pom.xml index 41214c492d..98eef9c363 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.main jenkins-parent - 2.119-SNAPSHOT + 2.121-SNAPSHOT cli diff --git a/core/pom.xml b/core/pom.xml index f2744c8e2c..f4ba140c9f 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -29,7 +29,7 @@ THE SOFTWARE. org.jenkins-ci.main jenkins-parent - 2.119-SNAPSHOT + 2.121-SNAPSHOT jenkins-core diff --git a/core/src/main/java/hudson/ExtensionList.java b/core/src/main/java/hudson/ExtensionList.java index 9a4c77d2f5..566e3de404 100644 --- a/core/src/main/java/hudson/ExtensionList.java +++ b/core/src/main/java/hudson/ExtensionList.java @@ -145,15 +145,29 @@ public class ExtensionList extends AbstractList implements OnMaster { * Looks for the extension instance of the given type (subclasses excluded), * or return null. */ - public @CheckForNull U get(Class type) { + public @CheckForNull U get(@Nonnull Class type) { for (T ext : this) if(ext.getClass()==type) return type.cast(ext); return null; } + /** + * Looks for the extension instance of the given type (subclasses excluded), + * or throws an IllegalStateException. + * + * Meant to simplify call inside @Extension annotated class to retrieve their own instance. + */ + public @Nonnull U getInstance(@Nonnull Class type) throws IllegalStateException { + for (T ext : this) + if(ext.getClass()==type) + return type.cast(ext); + + throw new IllegalStateException("The class " + type.getName() + " was not found, potentially not yet loaded"); + } + @Override - public Iterator iterator() { + public @Nonnull Iterator iterator() { // we need to intercept mutation, so for now don't allow Iterator.remove return new AdaptedIterator,T>(Iterators.readOnly(ensureLoaded().iterator())) { protected T adapt(ExtensionComponent item) { diff --git a/core/src/main/java/hudson/FilePath.java b/core/src/main/java/hudson/FilePath.java index 3f8fccd6ea..790f290e4c 100644 --- a/core/src/main/java/hudson/FilePath.java +++ b/core/src/main/java/hudson/FilePath.java @@ -609,6 +609,10 @@ public final class FilePath implements Serializable { while (entries.hasMoreElements()) { ZipEntry e = entries.nextElement(); File f = new File(dir, e.getName()); + if (!f.toPath().normalize().startsWith(dir.toPath())) { + throw new IOException( + "Zip " + zipFile.getPath() + " contains illegal file name that breaks out of the target directory: " + e.getName()); + } if (e.isDirectory()) { mkdirs(f); } else { @@ -918,7 +922,7 @@ public final class FilePath implements Serializable { /** * Copies the content of a URL to a remote file. * Unlike {@link #copyFrom} this will not transfer content over a Remoting channel. - * @since FIXME + * @since 2.119 */ @Restricted(Beta.class) public void copyFromRemotely(URL url) throws IOException, InterruptedException { @@ -2294,7 +2298,8 @@ public final class FilePath implements Serializable { if (f.isFile()) { File target = new File(dest, relativePath); mkdirsE(target.getParentFile()); - Util.copyFile(f, writing(target)); + Files.copy(fileToPath(f), fileToPath(writing(target)), + StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING); count.incrementAndGet(); } } diff --git a/core/src/main/java/hudson/model/AbstractItem.java b/core/src/main/java/hudson/model/AbstractItem.java index ffc627405d..9740880c0d 100644 --- a/core/src/main/java/hudson/model/AbstractItem.java +++ b/core/src/main/java/hudson/model/AbstractItem.java @@ -240,7 +240,7 @@ public abstract class AbstractItem extends Actionable implements Item, HttpDelet * @return whether {@link #name} can be modified by a user * @see #checkRename * @see #renameTo - * @since FIXME + * @since 2.110 */ public boolean isNameEditable() { return false; @@ -335,7 +335,7 @@ public abstract class AbstractItem extends Actionable implements Item, HttpDelet * * @param newName the new name for the item * @throws Failure if the rename should be blocked - * @since FIXME + * @since 2.110 * @see Job#checkRename */ protected void checkRename(@Nonnull String newName) throws Failure { diff --git a/core/src/main/java/hudson/model/ChoiceParameterDefinition.java b/core/src/main/java/hudson/model/ChoiceParameterDefinition.java index d5b6000591..9ea1415362 100644 --- a/core/src/main/java/hudson/model/ChoiceParameterDefinition.java +++ b/core/src/main/java/hudson/model/ChoiceParameterDefinition.java @@ -61,7 +61,7 @@ public class ChoiceParameterDefinition extends SimpleParameterDefinition { * @param name parameter name * @param description parameter description * - * @since TODO + * @since 2.112 */ @DataBoundConstructor @Restricted(NoExternalUse.class) // there are specific constructors with String and List arguments for 'choices' @@ -82,7 +82,7 @@ public class ChoiceParameterDefinition extends SimpleParameterDefinition { * * @param choices String or Collection representing this parameter definition's possible values. * - * @since TODO + * @since 2.112 * */ @DataBoundSetter diff --git a/core/src/main/java/hudson/model/Descriptor.java b/core/src/main/java/hudson/model/Descriptor.java index fa3511a5f6..aef728d373 100644 --- a/core/src/main/java/hudson/model/Descriptor.java +++ b/core/src/main/java/hudson/model/Descriptor.java @@ -821,7 +821,7 @@ public abstract class Descriptor> implements Saveable, * * @since 2.0, used to be in {@link GlobalConfiguration} before that. */ - public GlobalConfigurationCategory getCategory() { + public @Nonnull GlobalConfigurationCategory getCategory() { return GlobalConfigurationCategory.get(GlobalConfigurationCategory.Unclassified.class); } diff --git a/core/src/main/java/hudson/model/FingerprintCleanupThread.java b/core/src/main/java/hudson/model/FingerprintCleanupThread.java index 59187a3a40..292248ed52 100644 --- a/core/src/main/java/hudson/model/FingerprintCleanupThread.java +++ b/core/src/main/java/hudson/model/FingerprintCleanupThread.java @@ -28,9 +28,10 @@ import hudson.ExtensionList; import hudson.Functions; import jenkins.model.Jenkins; import org.jenkinsci.Symbol; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; import java.io.File; -import java.io.FileFilter; import java.io.IOException; import java.util.regex.Pattern; @@ -45,7 +46,11 @@ import java.util.regex.Pattern; * @author Kohsuke Kawaguchi */ @Extension @Symbol("fingerprintCleanup") -public final class FingerprintCleanupThread extends AsyncPeriodicWork { +@Restricted(NoExternalUse.class) +public class FingerprintCleanupThread extends AsyncPeriodicWork { + + static final String FINGERPRINTS_DIR_NAME = "fingerprints"; + private static final Pattern FINGERPRINT_FILE_PATTERN = Pattern.compile("[0-9a-f]{28}\\.xml"); public FingerprintCleanupThread() { super("Fingerprint cleanup"); @@ -66,13 +71,13 @@ public final class FingerprintCleanupThread extends AsyncPeriodicWork { public void execute(TaskListener listener) { int numFiles = 0; - File root = new File(Jenkins.getInstance().getRootDir(),"fingerprints"); - File[] files1 = root.listFiles(LENGTH2DIR_FILTER); + File root = new File(getRootDir(), FINGERPRINTS_DIR_NAME); + File[] files1 = root.listFiles(f -> f.isDirectory() && f.getName().length()==2); if(files1!=null) { for (File file1 : files1) { - File[] files2 = file1.listFiles(LENGTH2DIR_FILTER); + File[] files2 = file1.listFiles(f -> f.isDirectory() && f.getName().length()==2); for(File file2 : files2) { - File[] files3 = file2.listFiles(FINGERPRINTFILE_FILTER); + File[] files3 = file2.listFiles(f -> f.isFile() && FINGERPRINT_FILE_PATTERN.matcher(f.getName()).matches()); for(File file3 : files3) { if(check(file3, listener)) numFiles++; @@ -101,7 +106,7 @@ public final class FingerprintCleanupThread extends AsyncPeriodicWork { */ private boolean check(File fingerprintFile, TaskListener listener) { try { - Fingerprint fp = Fingerprint.load(fingerprintFile); + Fingerprint fp = loadFingerprint(fingerprintFile); if (fp == null || !fp.isAlive()) { listener.getLogger().println("deleting obsolete " + fingerprintFile); fingerprintFile.delete(); @@ -109,8 +114,7 @@ public final class FingerprintCleanupThread extends AsyncPeriodicWork { } else { // get the fingerprint in the official map so have the changes visible to Jenkins // otherwise the mutation made in FingerprintMap can override our trimming. - listener.getLogger().println("possibly trimming " + fingerprintFile); - fp = Jenkins.getInstance()._getFingerprint(fp.getHashString()); + fp = getFingerprint(fp); return fp.trim(); } } catch (IOException e) { @@ -119,17 +123,16 @@ public final class FingerprintCleanupThread extends AsyncPeriodicWork { } } - private static final FileFilter LENGTH2DIR_FILTER = new FileFilter() { - public boolean accept(File f) { - return f.isDirectory() && f.getName().length()==2; - } - }; + protected Fingerprint loadFingerprint(File fingerprintFile) throws IOException { + return Fingerprint.load(fingerprintFile); + } - private static final FileFilter FINGERPRINTFILE_FILTER = new FileFilter() { - private final Pattern PATTERN = Pattern.compile("[0-9a-f]{28}\\.xml"); + protected Fingerprint getFingerprint(Fingerprint fp) throws IOException { + return Jenkins.get()._getFingerprint(fp.getHashString()); + } + + protected File getRootDir() { + return Jenkins.get().getRootDir(); + } - public boolean accept(File f) { - return f.isFile() && PATTERN.matcher(f.getName()).matches(); - } - }; } diff --git a/core/src/main/java/hudson/model/Item.java b/core/src/main/java/hudson/model/Item.java index 8187d608bd..be8a5495e1 100644 --- a/core/src/main/java/hudson/model/Item.java +++ b/core/src/main/java/hudson/model/Item.java @@ -266,5 +266,5 @@ public interface Item extends PersistenceRoot, SearchableModelObject, AccessCont Permission BUILD = new Permission(PERMISSIONS, "Build", Messages._AbstractProject_BuildPermission_Description(), Permission.UPDATE, PermissionScope.ITEM); Permission WORKSPACE = new Permission(PERMISSIONS, "Workspace", Messages._AbstractProject_WorkspacePermission_Description(), Permission.READ, PermissionScope.ITEM); Permission WIPEOUT = new Permission(PERMISSIONS, "WipeOut", Messages._AbstractProject_WipeOutPermission_Description(), null, Functions.isWipeOutPermissionEnabled(), new PermissionScope[]{PermissionScope.ITEM}); - Permission CANCEL = new Permission(PERMISSIONS, "Cancel", Messages._AbstractProject_CancelPermission_Description(), BUILD, PermissionScope.ITEM); + Permission CANCEL = new Permission(PERMISSIONS, "Cancel", Messages._AbstractProject_CancelPermission_Description(), Permission.UPDATE, PermissionScope.ITEM); } diff --git a/core/src/main/java/hudson/model/ItemGroupMixIn.java b/core/src/main/java/hudson/model/ItemGroupMixIn.java index 13f72c3f07..195d4d8c0c 100644 --- a/core/src/main/java/hudson/model/ItemGroupMixIn.java +++ b/core/src/main/java/hudson/model/ItemGroupMixIn.java @@ -45,6 +45,8 @@ import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; @@ -239,7 +241,8 @@ public abstract class ItemGroupMixIn { T result = (T)createProject(src.getDescriptor(),name,false); // copy config - Util.copyFile(srcConfigFile.getFile(), Items.getConfigFile(result).getFile()); + Files.copy(Util.fileToPath(srcConfigFile.getFile()), Util.fileToPath(Items.getConfigFile(result).getFile()), + StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING); // reload from the new config final File rootDir = result.getRootDir(); diff --git a/core/src/main/java/hudson/model/Run.java b/core/src/main/java/hudson/model/Run.java index 879a5bd402..10ec9f6574 100644 --- a/core/src/main/java/hudson/model/Run.java +++ b/core/src/main/java/hudson/model/Run.java @@ -1133,7 +1133,7 @@ public abstract class Run ,RunT extends Run impl) { return new ACL() { diff --git a/core/src/main/java/hudson/security/csrf/GlobalCrumbIssuerConfiguration.java b/core/src/main/java/hudson/security/csrf/GlobalCrumbIssuerConfiguration.java index a93c70cc23..914fba876d 100644 --- a/core/src/main/java/hudson/security/csrf/GlobalCrumbIssuerConfiguration.java +++ b/core/src/main/java/hudson/security/csrf/GlobalCrumbIssuerConfiguration.java @@ -31,6 +31,8 @@ import net.sf.json.JSONObject; import org.jenkinsci.Symbol; import org.kohsuke.stapler.StaplerRequest; +import javax.annotation.Nonnull; + /** * Show the crumb configuration to the system config page. * @@ -39,14 +41,14 @@ import org.kohsuke.stapler.StaplerRequest; @Extension(ordinal=195) @Symbol("crumb") // immediately after the security setting public class GlobalCrumbIssuerConfiguration extends GlobalConfiguration { @Override - public GlobalConfigurationCategory getCategory() { + public @Nonnull GlobalConfigurationCategory getCategory() { return GlobalConfigurationCategory.get(GlobalConfigurationCategory.Security.class); } @Override public boolean configure(StaplerRequest req, JSONObject json) throws FormException { // for compatibility reasons, the actual value is stored in Jenkins - Jenkins j = Jenkins.getInstance(); + Jenkins j = Jenkins.get(); if (json.has("csrf")) { JSONObject csrf = json.getJSONObject("csrf"); j.setCrumbIssuer(CrumbIssuer.all().newInstanceFromRadioList(csrf, "issuer")); diff --git a/core/src/main/java/hudson/tools/ToolDescriptor.java b/core/src/main/java/hudson/tools/ToolDescriptor.java index ad4ac1734a..c39149ceeb 100644 --- a/core/src/main/java/hudson/tools/ToolDescriptor.java +++ b/core/src/main/java/hudson/tools/ToolDescriptor.java @@ -44,6 +44,8 @@ import org.jvnet.tiger_types.Types; import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.StaplerRequest; +import javax.annotation.Nonnull; + /** * {@link Descriptor} for {@link ToolInstallation}. * @@ -57,7 +59,7 @@ public abstract class ToolDescriptor extends Descrip protected ToolDescriptor() { } /** - * @since FIXME + * @since 2.102 */ protected ToolDescriptor(Class clazz) { super(clazz); @@ -109,12 +111,12 @@ public abstract class ToolDescriptor extends Descrip * Lists up {@link ToolPropertyDescriptor}s that are applicable to this {@link ToolInstallation}. */ public List getPropertyDescriptors() { - return PropertyDescriptor.for_(ToolProperty.all(), clazz); + return PropertyDescriptor.for_(ToolProperty.all(), clazz); } @Override - public GlobalConfigurationCategory getCategory() { + public @Nonnull GlobalConfigurationCategory getCategory() { return GlobalConfigurationCategory.get(ToolConfigurationCategory.class); } diff --git a/core/src/main/java/hudson/triggers/SafeTimerTask.java b/core/src/main/java/hudson/triggers/SafeTimerTask.java index e2cc7eb8b0..7e6f89236c 100644 --- a/core/src/main/java/hudson/triggers/SafeTimerTask.java +++ b/core/src/main/java/hudson/triggers/SafeTimerTask.java @@ -86,7 +86,7 @@ public abstract class SafeTimerTask extends TimerTask { * @see AsyncAperiodicWork#getLogFile() * @see AsyncPeriodicWork#getLogFile() * @return the path where the logs should be put. - * @since TODO + * @since 2.114 */ public static File getLogsRoot() { String tagsLogsPath = SystemProperties.getString(LOGS_ROOT_PATH_PROPERTY); diff --git a/core/src/main/java/hudson/util/FormValidation.java b/core/src/main/java/hudson/util/FormValidation.java index b8964811a2..3009e16253 100644 --- a/core/src/main/java/hudson/util/FormValidation.java +++ b/core/src/main/java/hudson/util/FormValidation.java @@ -400,7 +400,7 @@ public abstract class FormValidation extends IOException implements HttpResponse * @param lower the lower bound (inclusive) * @param upper the upper bound (inclusive) * - * @since TODO + * @since 2.104 */ public static FormValidation validateIntegerInRange(String value, int lower, int upper) { try { diff --git a/core/src/main/java/hudson/util/HttpResponses.java b/core/src/main/java/hudson/util/HttpResponses.java index 8c4bdeda9a..ef731f3ff8 100644 --- a/core/src/main/java/hudson/util/HttpResponses.java +++ b/core/src/main/java/hudson/util/HttpResponses.java @@ -89,16 +89,28 @@ public class HttpResponses extends org.kohsuke.stapler.HttpResponses { return new JSONObjectResponse(data); } - /** - * Set the response as an error response. - * @param message The error "message" set on the response. - * @return {@code this} object. - * - * @since 2.0 - */ + /** + * Set the response as an error response. + * @param message The error "message" set on the response. + * @return {@code this} object. + * + * @since 2.0 + */ public static HttpResponse errorJSON(@Nonnull String message) { return new JSONObjectResponse().error(message); } + + /** + * Set the response as an error response plus some data. + * @param message The error "message" set on the response. + * @param data The data. + * @return {@code this} object. + * + * @since 2.119 + */ + public static HttpResponse errorJSON(@Nonnull String message, @Nonnull Map data) { + return new JSONObjectResponse(data).error(message); + } /** * Set the response as an error response plus some data. @@ -106,7 +118,7 @@ public class HttpResponses extends org.kohsuke.stapler.HttpResponses { * @param data The data. * @return {@code this} object. * - * @since TODO + * @since 2.115 */ public static HttpResponse errorJSON(@Nonnull String message, @Nonnull JSONObject data) { return new JSONObjectResponse(data).error(message); @@ -118,7 +130,7 @@ public class HttpResponses extends org.kohsuke.stapler.HttpResponses { * @param data The data. * @return {@code this} object. * - * @since TODO + * @since 2.115 */ public static HttpResponse errorJSON(@Nonnull String message, @Nonnull JSONArray data) { return new JSONObjectResponse(data).error(message); diff --git a/core/src/main/java/hudson/util/ProcessTree.java b/core/src/main/java/hudson/util/ProcessTree.java index f1503dd7ff..115e570bb0 100644 --- a/core/src/main/java/hudson/util/ProcessTree.java +++ b/core/src/main/java/hudson/util/ProcessTree.java @@ -94,9 +94,20 @@ public abstract class ProcessTree implements Iterable, IProcessTree, * Lazily obtained {@link ProcessKiller}s to be applied on this process tree. */ private transient volatile List killers; + + /** + * Flag to skip the veto check since there aren't any. + */ + private boolean skipVetoes; // instantiation only allowed for subtypes in this class - private ProcessTree() {} + private ProcessTree() { + skipVetoes = false; + } + + private ProcessTree(boolean vetoesExist) { + skipVetoes = !vetoesExist; + } /** * Gets the process given a specific ID, or null if no such process exists. @@ -241,14 +252,26 @@ public abstract class ProcessTree implements Iterable, IProcessTree, * null if no one objects killing the process. */ protected @CheckForNull VetoCause getVeto() { - for (ProcessKillingVeto vetoExtension : ProcessKillingVeto.all()) { - VetoCause cause = vetoExtension.vetoProcessKilling(this); - if (cause != null) { - if (LOGGER.isLoggable(FINEST)) - LOGGER.finest("Killing of pid " + getPid() + " vetoed by " + vetoExtension.getClass().getName() + ": " + cause.getMessage()); - return cause; + String causeMessage = null; + + // Quick check, does anything exist to check against + if (!skipVetoes) { + try { + VirtualChannel channelToMaster = SlaveComputer.getChannelToMaster(); + if (channelToMaster!=null) { + CheckVetoes vetoCheck = new CheckVetoes(this); + causeMessage = channelToMaster.call(vetoCheck); + } + } catch (IOException e) { + LOGGER.log(Level.WARNING, "I/O Exception while checking for vetoes", e); + } catch (InterruptedException e) { + LOGGER.log(Level.WARNING, "Interrupted Exception while checking for vetoes", e); } } + + if (causeMessage != null) { + return new VetoCause(causeMessage); + } return null; } @@ -300,6 +323,27 @@ public abstract class ProcessTree implements Iterable, IProcessTree, Object writeReplace() { return new SerializedProcess(pid); } + + private class CheckVetoes extends SlaveToMasterCallable { + private IOSProcess process; + + public CheckVetoes(IOSProcess processToCheck) { + process = processToCheck; + } + + @Override + public String call() throws IOException { + for (ProcessKillingVeto vetoExtension : ProcessKillingVeto.all()) { + VetoCause cause = vetoExtension.vetoProcessKilling(process); + if (cause != null) { + if (LOGGER.isLoggable(FINEST)) + LOGGER.info("Killing of pid " + getPid() + " vetoed by " + vetoExtension.getClass().getName() + ": " + cause.getMessage()); + return cause.getMessage(); + } + } + return null; + } + } } /** @@ -338,6 +382,8 @@ public abstract class ProcessTree implements Iterable, IProcessTree, } + /* package */ static Boolean vetoersExist; + /** * Gets the {@link ProcessTree} of the current system * that JVM runs in, or in the worst case return the default one @@ -347,17 +393,30 @@ public abstract class ProcessTree implements Iterable, IProcessTree, if(!enabled) return DEFAULT; + // Check for the existance of vetoers if I don't know already + if (vetoersExist == null) { + try { + vetoersExist = SlaveComputer.getChannelToMaster().call(new DoVetoersExist()); + } + catch (Exception e) { + LOGGER.log(Level.WARNING, "Error while determining if vetoers exist", e); + } + } + + // Null-check in case the previous call worked + boolean vetoes = (vetoersExist == null ? true : vetoersExist); + try { if(File.pathSeparatorChar==';') - return new Windows(); + return new Windows(vetoes); String os = Util.fixNull(System.getProperty("os.name")); if(os.equals("Linux")) - return new Linux(); + return new Linux(vetoes); if(os.equals("SunOS")) - return new Solaris(); + return new Solaris(vetoes); if(os.equals("Mac OS X")) - return new Darwin(); + return new Darwin(vetoes); } catch (LinkageError e) { LOGGER.log(Level.WARNING,"Failed to load winp. Reverting to the default",e); enabled = false; @@ -365,6 +424,13 @@ public abstract class ProcessTree implements Iterable, IProcessTree, return DEFAULT; } + + private static class DoVetoersExist extends SlaveToMasterCallable { + @Override + public Boolean call() throws IOException { + return ProcessKillingVeto.all().size() > 0; + } + } // // @@ -512,7 +578,9 @@ public abstract class ProcessTree implements Iterable, IProcessTree, } private static final class Windows extends Local { - Windows() { + Windows(boolean vetoesExist) { + super(vetoesExist); + for (final WinProcess p : WinProcess.all()) { int pid = p.getPid(); if(pid == 0 || pid == 4) continue; // skip the System Idle and System processes @@ -574,6 +642,10 @@ public abstract class ProcessTree implements Iterable, IProcessTree, } static abstract class Unix extends Local { + public Unix(boolean vetoersExist) { + super(vetoersExist); + } + @Override public OSProcess get(Process proc) { try { @@ -595,7 +667,9 @@ public abstract class ProcessTree implements Iterable, IProcessTree, * {@link ProcessTree} based on /proc. */ static abstract class ProcfsUnix extends Unix { - ProcfsUnix() { + ProcfsUnix(boolean vetoersExist) { + super(vetoersExist); + File[] processes = new File("/proc").listFiles(new FileFilter() { public boolean accept(File f) { return f.isDirectory(); @@ -739,6 +813,10 @@ public abstract class ProcessTree implements Iterable, IProcessTree, static class Linux extends ProcfsUnix { + public Linux(boolean vetoersExist) { + super(vetoersExist); + } + protected LinuxProcess createProcess(int pid) throws IOException { return new LinuxProcess(pid); } @@ -853,6 +931,10 @@ public abstract class ProcessTree implements Iterable, IProcessTree, * when accessing this file. */ static class Solaris extends ProcfsUnix { + public Solaris(boolean vetoersExist) { + super(vetoersExist); + } + protected OSProcess createProcess(final int pid) throws IOException { return new SolarisProcess(pid); } @@ -1093,7 +1175,9 @@ public abstract class ProcessTree implements Iterable, IProcessTree, * Implementation for Mac OS X based on sysctl(3). */ private static class Darwin extends Unix { - Darwin() { + Darwin(boolean vetoersExist) { + super(vetoersExist); + String arch = System.getProperty("sun.arch.data.model"); if ("64".equals(arch)) { sizeOf_kinfo_proc = sizeOf_kinfo_proc_64; @@ -1312,8 +1396,13 @@ public abstract class ProcessTree implements Iterable, IProcessTree, * (The opposite of {@link Remote}.) */ public static abstract class Local extends ProcessTree { + @Deprecated Local() { } + + Local(boolean vetoesExist) { + super(vetoesExist); + } } /** @@ -1322,11 +1411,20 @@ public abstract class ProcessTree implements Iterable, IProcessTree, public static class Remote extends ProcessTree implements Serializable { private final IProcessTree proxy; + @Deprecated public Remote(ProcessTree proxy, Channel ch) { this.proxy = ch.export(IProcessTree.class,proxy); for (Entry e : proxy.processes.entrySet()) processes.put(e.getKey(),new RemoteProcess(e.getValue(),ch)); } + + public Remote(ProcessTree proxy, Channel ch, boolean vetoersExist) { + super(vetoersExist); + + this.proxy = ch.export(IProcessTree.class,proxy); + for (Entry e : proxy.processes.entrySet()) + processes.put(e.getKey(),new RemoteProcess(e.getValue(),ch)); + } @Override public OSProcess get(Process proc) { diff --git a/core/src/main/java/hudson/util/TextFile.java b/core/src/main/java/hudson/util/TextFile.java index e9bb0c8b5a..bd6904add0 100644 --- a/core/src/main/java/hudson/util/TextFile.java +++ b/core/src/main/java/hudson/util/TextFile.java @@ -101,7 +101,7 @@ public class TextFile { * LinesStream. * @throws IOException if the file cannot be converted to a * {@link java.nio.file.Path} or if the file cannot be opened for reading - * @since TODO + * @since 2.111 */ @CreatesObligation public @Nonnull LinesStream linesStream() throws IOException { diff --git a/core/src/main/java/hudson/views/GlobalDefaultViewConfiguration.java b/core/src/main/java/hudson/views/GlobalDefaultViewConfiguration.java index c76ae404c3..36b8aea6a6 100644 --- a/core/src/main/java/hudson/views/GlobalDefaultViewConfiguration.java +++ b/core/src/main/java/hudson/views/GlobalDefaultViewConfiguration.java @@ -41,7 +41,7 @@ public class GlobalDefaultViewConfiguration extends GlobalConfiguration { @Override public boolean configure(StaplerRequest req, JSONObject json) throws FormException { // for compatibility reasons, the actual value is stored in Jenkins - Jenkins j = Jenkins.getInstance(); + Jenkins j = Jenkins.get(); if (json.has("primaryView")) { final String viewName = json.getString("primaryView"); final View newPrimaryView = j.getView(viewName); diff --git a/core/src/main/java/hudson/views/MyViewsTabBar.java b/core/src/main/java/hudson/views/MyViewsTabBar.java index 1d2fe44db1..6727cb050e 100644 --- a/core/src/main/java/hudson/views/MyViewsTabBar.java +++ b/core/src/main/java/hudson/views/MyViewsTabBar.java @@ -100,13 +100,13 @@ public abstract class MyViewsTabBar extends AbstractDescribableImpl i @Extension(ordinal=310) @Symbol("viewsTabBar") public static class GlobalConfigurationImpl extends GlobalConfiguration { public ViewsTabBar getViewsTabBar() { - return Jenkins.getInstance().getViewsTabBar(); + return Jenkins.get().getViewsTabBar(); } @Override public boolean configure(StaplerRequest req, JSONObject json) throws FormException { // for compatibility reasons, the actual value is stored in Jenkins - Jenkins j = Jenkins.getInstance(); + Jenkins j = Jenkins.get(); if (json.has("viewsTabBar")) { j.setViewsTabBar(req.bindJSON(ViewsTabBar.class,json.getJSONObject("viewsTabBar"))); diff --git a/core/src/main/java/jenkins/CLI.java b/core/src/main/java/jenkins/CLI.java index 2338e0fb4a..4d9f9af3df 100644 --- a/core/src/main/java/jenkins/CLI.java +++ b/core/src/main/java/jenkins/CLI.java @@ -34,12 +34,7 @@ public class CLI extends GlobalConfiguration { @Nonnull public static CLI get() { - CLI instance = GlobalConfiguration.all().get(CLI.class); - if (instance == null) { - // should not happen - return new CLI(); - } - return instance; + return GlobalConfiguration.all().getInstance(CLI.class); } private boolean enabled = true; // historical default, but overridden in SetupWizard @@ -49,7 +44,7 @@ public class CLI extends GlobalConfiguration { } @Override - public GlobalConfigurationCategory getCategory() { + public @Nonnull GlobalConfigurationCategory getCategory() { return GlobalConfigurationCategory.get(GlobalConfigurationCategory.Security.class); } diff --git a/core/src/main/java/jenkins/diagnostics/RootUrlNotSetMonitor.java b/core/src/main/java/jenkins/diagnostics/RootUrlNotSetMonitor.java new file mode 100644 index 0000000000..bb4a252409 --- /dev/null +++ b/core/src/main/java/jenkins/diagnostics/RootUrlNotSetMonitor.java @@ -0,0 +1,64 @@ +/* + * The MIT License + * + * Copyright (c) 2018, CloudBees, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package jenkins.diagnostics; + +import hudson.Extension; +import hudson.model.AdministrativeMonitor; +import jenkins.model.JenkinsLocationConfiguration; +import jenkins.util.UrlHelper; +import org.jenkinsci.Symbol; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; + +/** + * Jenkins root URL is required for a lot of operations in both core and plugins. + * There is a default behavior (infer the URL from the request object), but inaccurate in some scenarios. + * Normally this root URL is set during SetupWizard phase, this monitor is there to ensure that behavior. + * Potential exceptions are the dev environment, if someone disable the wizard or + * the administrator put an empty string on the configuration page. + * + * @since 2.119 + */ +@Extension +@Symbol("rootUrlNotSet") +@Restricted(NoExternalUse.class) +public class RootUrlNotSetMonitor extends AdministrativeMonitor { + @Override + public String getDisplayName() { + return Messages.RootUrlNotSetMonitor_DisplayName(); + } + + @Override + public boolean isActivated() { + JenkinsLocationConfiguration loc = JenkinsLocationConfiguration.get(); + return loc.getUrl() == null || !UrlHelper.isValidRootUrl(loc.getUrl()); + } + + // used by jelly to determined if it's a null url or invalid one + @Restricted(NoExternalUse.class) + public boolean isUrlNull(){ + JenkinsLocationConfiguration loc = JenkinsLocationConfiguration.get(); + return loc.getUrl() == null; + } +} diff --git a/core/src/main/java/jenkins/install/InstallState.java b/core/src/main/java/jenkins/install/InstallState.java index dc6f9dc534..df091a08ea 100644 --- a/core/src/main/java/jenkins/install/InstallState.java +++ b/core/src/main/java/jenkins/install/InstallState.java @@ -32,6 +32,7 @@ import hudson.ExtensionPoint; import java.util.logging.Level; import java.util.logging.Logger; import jenkins.model.Jenkins; +import jenkins.model.JenkinsLocationConfiguration; import org.apache.commons.lang.StringUtils; /** * Jenkins install state. @@ -47,7 +48,13 @@ import org.apache.commons.lang.StringUtils; public class InstallState implements ExtensionPoint { /** - * Only here for XStream compatibility. + * Only here for XStream compatibility.

+ * + * Please DO NOT ADD ITEM TO THIS LIST.

+ * If you add an item here, the deserialization process will break + * because it is used for serialized state like "jenkins.install.InstallState$4" + * before the change from anonymous class to named class. If you need to add a new InstallState, you can just add a new inner named class but nothing to change in this list. + * * @see #readResolve */ @Deprecated @@ -92,7 +99,7 @@ public class InstallState implements ExtensionPoint { super("INITIAL_SETUP_COMPLETED", true); } public void initializeState() { - Jenkins j = Jenkins.getInstance(); + Jenkins j = Jenkins.get(); try { j.getSetupWizard().completeSetup(); } catch (Exception e) { @@ -100,7 +107,7 @@ public class InstallState implements ExtensionPoint { } j.setInstallState(RUNNING); } - }; + } /** * Creating an admin user for an initial Jenkins install. @@ -112,14 +119,29 @@ public class InstallState implements ExtensionPoint { super("CREATE_ADMIN_USER", false); } public void initializeState() { - Jenkins j = Jenkins.getInstance(); + Jenkins j = Jenkins.get(); // Skip this state if not using the security defaults // e.g. in an init script set up security already if (!j.getSetupWizard().isUsingSecurityDefaults()) { InstallUtil.proceedToNextStateFrom(this); } } - }; + } + + @Extension + public static final InstallState CONFIGURE_INSTANCE = new ConfigureInstance(); + private static final class ConfigureInstance extends InstallState { + ConfigureInstance() { + super("CONFIGURE_INSTANCE", false); + } + public void initializeState() { + // Skip this state if a boot script already configured the root URL + // in case we add more fields in this page, this should be adapted + if (StringUtils.isNotBlank(JenkinsLocationConfiguration.getOrDie().getUrl())) { + InstallUtil.proceedToNextStateFrom(this); + } + } + } /** * New Jenkins install. The user has kicked off the process of installing an @@ -139,14 +161,14 @@ public class InstallState implements ExtensionPoint { } public void initializeState() { try { - Jenkins.getInstance().getSetupWizard().init(true); + Jenkins.get().getSetupWizard().init(true); } catch (Exception e) { throw new RuntimeException(e); } InstallUtil.proceedToNextStateFrom(INITIAL_SECURITY_SETUP); } - }; + } /** * New Jenkins install. @@ -166,7 +188,7 @@ public class InstallState implements ExtensionPoint { public void initializeState() { InstallUtil.saveLastExecVersion(); } - }; + } /** * Upgrade of an existing Jenkins install. @@ -186,7 +208,7 @@ public class InstallState implements ExtensionPoint { public void initializeState() { InstallUtil.saveLastExecVersion(); } - }; + } private static final Logger LOGGER = Logger.getLogger(InstallState.class.getName()); @@ -202,6 +224,10 @@ public class InstallState implements ExtensionPoint { public static final InstallState DEVELOPMENT = new InstallState("DEVELOPMENT", true); private final transient boolean isSetupComplete; + + /** + * Link with the pluginSetupWizardGui.js map: "statsHandlers" + */ private final String name; public InstallState(@Nonnull String name, boolean isSetupComplete) { @@ -220,7 +246,9 @@ public class InstallState implements ExtensionPoint { *

Creating a {@code writeReplace} does not help much since XStream then just saves: * {@code } * @see #UNUSED_INNER_CLASSES + * @deprecated Should no longer be used, as {@link Jenkins} now saves only {@link #name}. */ + @Deprecated protected Object readResolve() { // If we get invalid state from the configuration, fallback to unknown if (StringUtils.isBlank(name)) { diff --git a/core/src/main/java/jenkins/install/InstallUtil.java b/core/src/main/java/jenkins/install/InstallUtil.java index 48b8d33ab6..7552f9fa35 100644 --- a/core/src/main/java/jenkins/install/InstallUtil.java +++ b/core/src/main/java/jenkins/install/InstallUtil.java @@ -101,37 +101,30 @@ public class InstallUtil { /** * Returns the next state during a transition from the current install state */ - /*package*/ static InstallState getNextInstallState(final InstallState current) { + /*package*/ static InstallState getNextInstallState(InstallState current) { List,InstallState>> installStateFilterChain = new ArrayList<>(); - for (final InstallStateFilter setupExtension : InstallStateFilter.all()) { - installStateFilterChain.add(new Function, InstallState>() { - @Override - public InstallState apply(Provider next) { - return setupExtension.getNextInstallState(current, next); - } - }); + for (InstallStateFilter setupExtension : InstallStateFilter.all()) { + installStateFilterChain.add(next -> setupExtension.getNextInstallState(current, next)); } // Terminal condition: getNextState() on the current install state - installStateFilterChain.add(new Function, InstallState>() { - @Override - public InstallState apply(Provider input) { - // Initially, install state is unknown and - // needs to be determined - if (current == null || InstallState.UNKNOWN.equals(current)) { - return getDefaultInstallState(); - } - final Map states = new HashMap(); - { - states.put(InstallState.CREATE_ADMIN_USER, InstallState.INITIAL_SETUP_COMPLETED); - states.put(InstallState.INITIAL_PLUGINS_INSTALLING, InstallState.CREATE_ADMIN_USER); - states.put(InstallState.INITIAL_SECURITY_SETUP, InstallState.NEW); - states.put(InstallState.RESTART, InstallState.RUNNING); - states.put(InstallState.UPGRADE, InstallState.INITIAL_SETUP_COMPLETED); - states.put(InstallState.DOWNGRADE, InstallState.INITIAL_SETUP_COMPLETED); - states.put(InstallState.INITIAL_SETUP_COMPLETED, InstallState.RUNNING); - } - return states.get(current); + installStateFilterChain.add(input -> { + // Initially, install state is unknown and + // needs to be determined + if (current == null || InstallState.UNKNOWN.equals(current)) { + return getDefaultInstallState(); } + Map states = new HashMap<>(); + { + states.put(InstallState.CONFIGURE_INSTANCE, InstallState.INITIAL_SETUP_COMPLETED); + states.put(InstallState.CREATE_ADMIN_USER, InstallState.CONFIGURE_INSTANCE); + states.put(InstallState.INITIAL_PLUGINS_INSTALLING, InstallState.CREATE_ADMIN_USER); + states.put(InstallState.INITIAL_SECURITY_SETUP, InstallState.NEW); + states.put(InstallState.RESTART, InstallState.RUNNING); + states.put(InstallState.UPGRADE, InstallState.INITIAL_SETUP_COMPLETED); + states.put(InstallState.DOWNGRADE, InstallState.INITIAL_SETUP_COMPLETED); + states.put(InstallState.INITIAL_SETUP_COMPLETED, InstallState.RUNNING); + } + return states.get(current); }); ProviderChain chain = new ProviderChain<>(installStateFilterChain.iterator()); diff --git a/core/src/main/java/jenkins/install/SetupWizard.java b/core/src/main/java/jenkins/install/SetupWizard.java index 67f68606b2..b9cd417e83 100644 --- a/core/src/main/java/jenkins/install/SetupWizard.java +++ b/core/src/main/java/jenkins/install/SetupWizard.java @@ -4,7 +4,9 @@ import static org.apache.commons.io.FileUtils.readFileToString; import static org.apache.commons.lang.StringUtils.defaultIfBlank; import java.io.IOException; +import java.util.HashMap; import java.util.Locale; +import java.util.Map; import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; @@ -20,7 +22,9 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; +import jenkins.model.JenkinsLocationConfiguration; import jenkins.util.SystemProperties; +import jenkins.util.UrlHelper; import org.acegisecurity.Authentication; import org.acegisecurity.context.SecurityContextHolder; import org.acegisecurity.providers.UsernamePasswordAuthenticationToken; @@ -28,6 +32,7 @@ import org.acegisecurity.userdetails.UsernameNotFoundException; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; import org.kohsuke.stapler.HttpResponse; +import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; @@ -92,7 +97,7 @@ public class SetupWizard extends PageDecorator { * Initialize the setup wizard, this will process any current state initializations */ /*package*/ void init(boolean newInstall) throws IOException, InterruptedException { - Jenkins jenkins = Jenkins.getInstance(); + Jenkins jenkins = Jenkins.get(); if(newInstall) { // this was determined to be a new install, don't run the update wizard here @@ -137,7 +142,7 @@ public class SetupWizard extends PageDecorator { jenkins.setAgentProtocols(newProtocols); // require a crumb issuer - jenkins.setCrumbIssuer(new DefaultCrumbIssuer(false)); + jenkins.setCrumbIssuer(new DefaultCrumbIssuer(SystemProperties.getBoolean(Jenkins.class.getName() + ".crumbIssuerProxyCompatibility",false))); // set master -> slave security: jenkins.getInjector().getInstance(AdminWhitelistRule.class) @@ -196,14 +201,14 @@ public class SetupWizard extends PageDecorator { throw new RuntimeException("Unable to remove PluginServletFilter for the SetupWizard", e); } } - + /** * Indicates a generated password should be used - e.g. this is a new install, no security realm set up */ @SuppressWarnings("unused") // used by jelly public boolean isUsingSecurityToken() { try { - return !Jenkins.getInstance().getInstallState().isSetupComplete() + return !Jenkins.get().getInstallState().isSetupComplete() && isUsingSecurityDefaults(); } catch (Exception e) { // ignore @@ -217,7 +222,7 @@ public class SetupWizard extends PageDecorator { * Other settings are irrelevant. */ /*package*/ boolean isUsingSecurityDefaults() { - Jenkins j = Jenkins.getInstance(); + Jenkins j = Jenkins.get(); if (j.getSecurityRealm() instanceof HudsonPrivateSecurityRealm) { HudsonPrivateSecurityRealm securityRealm = (HudsonPrivateSecurityRealm)j.getSecurityRealm(); try { @@ -244,6 +249,7 @@ public class SetupWizard extends PageDecorator { @Restricted(NoExternalUse.class) public HttpResponse doCreateAdminUser(StaplerRequest req, StaplerResponse rsp) throws IOException { Jenkins j = Jenkins.getInstance(); + j.checkPermission(Jenkins.ADMINISTER); // This will be set up by default. if not, something changed, ok to fail @@ -293,6 +299,51 @@ public class SetupWizard extends PageDecorator { } } } + + @RequirePOST + @Restricted(NoExternalUse.class) + public HttpResponse doConfigureInstance(StaplerRequest req, @QueryParameter String rootUrl) { + Jenkins.get().checkPermission(Jenkins.ADMINISTER); + + Map errors = new HashMap<>(); + // pre-check data + checkRootUrl(errors, rootUrl); + + if(!errors.isEmpty()){ + return HttpResponses.errorJSON(Messages.SetupWizard_ConfigureInstance_ValidationErrors(), errors); + } + + // use the parameters to configure the instance + useRootUrl(errors, rootUrl); + + if(!errors.isEmpty()){ + return HttpResponses.errorJSON(Messages.SetupWizard_ConfigureInstance_ValidationErrors(), errors); + } + + InstallUtil.proceedToNextStateFrom(InstallState.CONFIGURE_INSTANCE); + + CrumbIssuer crumbIssuer = Jenkins.get().getCrumbIssuer(); + JSONObject data = new JSONObject(); + if (crumbIssuer != null) { + data.accumulate("crumbRequestField", crumbIssuer.getCrumbRequestField()).accumulate("crumb", crumbIssuer.getCrumb(req)); + } + return HttpResponses.okJSON(data); + } + + private void checkRootUrl(Map errors, @CheckForNull String rootUrl){ + if(rootUrl == null){ + errors.put("rootUrl", Messages.SetupWizard_ConfigureInstance_RootUrl_Empty()); + return; + } + if(!UrlHelper.isValidRootUrl(rootUrl)){ + errors.put("rootUrl", Messages.SetupWizard_ConfigureInstance_RootUrl_Invalid()); + } + } + + private void useRootUrl(Map errors, @CheckForNull String rootUrl){ + LOGGER.log(Level.FINE, "Root URL set during SetupWizard to {0}", new Object[]{ rootUrl }); + JenkinsLocationConfiguration.getOrDie().setUrl(rootUrl); + } /*package*/ void setCurrentLevel(VersionNumber v) throws IOException { FileUtils.writeStringToFile(getUpdateStateFile(), v.toString()); @@ -304,7 +355,7 @@ public class SetupWizard extends PageDecorator { * This file records the version number that the installation has upgraded to. */ /*package*/ static File getUpdateStateFile() { - return new File(Jenkins.getInstance().getRootDir(),"jenkins.install.UpgradeWizard.state"); + return new File(Jenkins.get().getRootDir(),"jenkins.install.UpgradeWizard.state"); } /** @@ -333,9 +384,9 @@ public class SetupWizard extends PageDecorator { */ @Restricted(DoNotUse.class) // WebOnly public HttpResponse doPlatformPluginList() throws IOException { - jenkins.install.SetupWizard setupWizard = Jenkins.getInstance().getSetupWizard(); + SetupWizard setupWizard = Jenkins.get().getSetupWizard(); if (setupWizard != null) { - if (InstallState.UPGRADE.equals(Jenkins.getInstance().getInstallState())) { + if (InstallState.UPGRADE.equals(Jenkins.get().getInstallState())) { JSONArray initialPluginData = getPlatformPluginUpdates(); if(initialPluginData != null) { return HttpResponses.okJSON(initialPluginData); @@ -357,7 +408,7 @@ public class SetupWizard extends PageDecorator { @Restricted(DoNotUse.class) // WebOnly public HttpResponse doRestartStatus() throws IOException { JSONObject response = new JSONObject(); - Jenkins jenkins = Jenkins.getInstance(); + Jenkins jenkins = Jenkins.get(); response.put("restartRequired", jenkins.getUpdateCenter().isRestartRequiredForCompletion()); response.put("restartSupported", jenkins.getLifecycle().canRestart()); return HttpResponses.okJSON(response); @@ -383,9 +434,9 @@ public class SetupWizard extends PageDecorator { */ @CheckForNull /*package*/ JSONArray getPlatformPluginList() { - Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER); + Jenkins.get().checkPermission(Jenkins.ADMINISTER); JSONArray initialPluginList = null; - updateSiteList: for (UpdateSite updateSite : Jenkins.getInstance().getUpdateCenter().getSiteList()) { + updateSiteList: for (UpdateSite updateSite : Jenkins.get().getUpdateCenter().getSiteList()) { String updateCenterJsonUrl = updateSite.getUrl(); String suggestedPluginUrl = updateCenterJsonUrl.replace("/update-center.json", "/platform-plugins.json"); try { @@ -429,7 +480,7 @@ public class SetupWizard extends PageDecorator { * Get the platform plugins added in the version range */ /*package*/ JSONArray getPlatformPluginsForUpdate(VersionNumber from, VersionNumber to) { - Jenkins jenkins = Jenkins.getInstance(); + Jenkins jenkins = Jenkins.get(); JSONArray pluginCategories = JSONArray.fromObject(getPlatformPluginList().toString()); for (Iterator categoryIterator = pluginCategories.iterator(); categoryIterator.hasNext();) { Object category = categoryIterator.next(); @@ -486,7 +537,7 @@ public class SetupWizard extends PageDecorator { * Gets the file used to store the initial admin password */ public FilePath getInitialAdminPasswordFile() { - return Jenkins.getInstance().getRootPath().child("secrets/initialAdminPassword"); + return Jenkins.get().getRootPath().child("secrets/initialAdminPassword"); } /** @@ -499,7 +550,7 @@ public class SetupWizard extends PageDecorator { } /*package*/ void completeSetup() throws IOException, ServletException { - Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER); + Jenkins.get().checkPermission(Jenkins.ADMINISTER); InstallUtil.saveLastExecVersion(); setCurrentLevel(Jenkins.getVersion()); InstallUtil.proceedToNextStateFrom(InstallState.INITIAL_SETUP_COMPLETED); @@ -561,7 +612,7 @@ public class SetupWizard extends PageDecorator { ((HttpServletResponse) response).sendRedirect(req.getContextPath() + "/"); return; } else if (req.getRequestURI().equals(req.getContextPath() + "/")) { - Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER); + Jenkins.get().checkPermission(Jenkins.ADMINISTER); chain.doFilter(new HttpServletRequestWrapper(req) { public String getRequestURI() { return getContextPath() + "/setupWizard/"; @@ -583,7 +634,7 @@ public class SetupWizard extends PageDecorator { * Sets up the Setup Wizard filter if the current state requires it. */ private void checkFilter() { - if (!Jenkins.getInstance().getInstallState().isSetupComplete()) { + if (!Jenkins.get().getInstallState().isSetupComplete()) { setUpFilter(); } } diff --git a/core/src/main/java/jenkins/model/ArtifactManagerConfiguration.java b/core/src/main/java/jenkins/model/ArtifactManagerConfiguration.java index 43f98aae8d..29d7439d03 100644 --- a/core/src/main/java/jenkins/model/ArtifactManagerConfiguration.java +++ b/core/src/main/java/jenkins/model/ArtifactManagerConfiguration.java @@ -31,6 +31,8 @@ import net.sf.json.JSONObject; import org.jenkinsci.Symbol; import org.kohsuke.stapler.StaplerRequest; +import javax.annotation.Nonnull; + /** * List of configured {@link ArtifactManagerFactory}s. * @since 1.532 @@ -38,8 +40,8 @@ import org.kohsuke.stapler.StaplerRequest; @Extension @Symbol("artifactManager") public class ArtifactManagerConfiguration extends GlobalConfiguration { - public static ArtifactManagerConfiguration get() { - return Jenkins.getInstance().getInjector().getInstance(ArtifactManagerConfiguration.class); + public static @Nonnull ArtifactManagerConfiguration get() { + return GlobalConfiguration.all().getInstance(ArtifactManagerConfiguration.class); } private final DescribableList artifactManagerFactories = new DescribableList(this); diff --git a/core/src/main/java/jenkins/model/DownloadSettings.java b/core/src/main/java/jenkins/model/DownloadSettings.java index e4c78c2ef3..8c8b75b90b 100644 --- a/core/src/main/java/jenkins/model/DownloadSettings.java +++ b/core/src/main/java/jenkins/model/DownloadSettings.java @@ -42,6 +42,8 @@ import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; import org.kohsuke.stapler.HttpResponse; +import javax.annotation.Nonnull; + /** * Lets user configure how metadata files should be downloaded. * @see UpdateSite @@ -51,8 +53,8 @@ import org.kohsuke.stapler.HttpResponse; @Extension @Symbol("downloadSettings") public final class DownloadSettings extends GlobalConfiguration { - public static DownloadSettings get() { - return Jenkins.getInstance().getInjector().getInstance(DownloadSettings.class); + public static @Nonnull DownloadSettings get() { + return GlobalConfiguration.all().getInstance(DownloadSettings.class); } private boolean useBrowser = false; @@ -70,19 +72,19 @@ public final class DownloadSettings extends GlobalConfiguration { save(); } - @Override public GlobalConfigurationCategory getCategory() { + @Override public @Nonnull GlobalConfigurationCategory getCategory() { return GlobalConfigurationCategory.get(GlobalConfigurationCategory.Security.class); } public static boolean usePostBack() { - return get().isUseBrowser() && Jenkins.getInstance().hasPermission(Jenkins.ADMINISTER); + return get().isUseBrowser() && Jenkins.get().hasPermission(Jenkins.ADMINISTER); } public static void checkPostBackAccess() throws AccessDeniedException { if (!get().isUseBrowser()) { throw new AccessDeniedException("browser-based download disabled"); } - Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER); + Jenkins.get().checkPermission(Jenkins.ADMINISTER); } @Extension @Symbol("updateCenterCheck") @@ -106,7 +108,7 @@ public final class DownloadSettings extends GlobalConfiguration { return; } boolean due = false; - for (UpdateSite site : Jenkins.getInstance().getUpdateCenter().getSites()) { + for (UpdateSite site : Jenkins.get().getUpdateCenter().getSites()) { if (site.isDue()) { due = true; break; @@ -128,7 +130,7 @@ public final class DownloadSettings extends GlobalConfiguration { return; } // This checks updates of the update sites and downloadables. - HttpResponse rsp = Jenkins.getInstance().getPluginManager().doCheckUpdatesServer(); + HttpResponse rsp = Jenkins.get().getPluginManager().doCheckUpdatesServer(); if (rsp instanceof FormValidation) { listener.error(((FormValidation) rsp).renderHtml()); } diff --git a/core/src/main/java/jenkins/model/GlobalCloudConfiguration.java b/core/src/main/java/jenkins/model/GlobalCloudConfiguration.java index a4aa432e20..9c6635ab05 100644 --- a/core/src/main/java/jenkins/model/GlobalCloudConfiguration.java +++ b/core/src/main/java/jenkins/model/GlobalCloudConfiguration.java @@ -21,7 +21,7 @@ public class GlobalCloudConfiguration extends GlobalConfiguration { @Override public boolean configure(StaplerRequest req, JSONObject json) throws FormException { try { - Jenkins.getInstance().clouds.rebuildHetero(req,json, Cloud.all(), "cloud"); + Jenkins.get().clouds.rebuildHetero(req,json, Cloud.all(), "cloud"); return true; } catch (IOException e) { throw new FormException(e,"clouds"); diff --git a/core/src/main/java/jenkins/model/GlobalConfiguration.java b/core/src/main/java/jenkins/model/GlobalConfiguration.java index f751404bed..76320768b0 100644 --- a/core/src/main/java/jenkins/model/GlobalConfiguration.java +++ b/core/src/main/java/jenkins/model/GlobalConfiguration.java @@ -7,6 +7,8 @@ import hudson.model.Descriptor; import net.sf.json.JSONObject; import org.kohsuke.stapler.StaplerRequest; +import javax.annotation.Nonnull; + /** * Convenient base class for extensions that contributes to the system configuration page but nothing * else, or to manage the global configuration of a plugin implementing several extension points. @@ -69,8 +71,8 @@ public abstract class GlobalConfiguration extends Descriptor all() { - return Jenkins.getInstance().getDescriptorList(GlobalConfiguration.class); + public static @Nonnull ExtensionList all() { + return Jenkins.get().getDescriptorList(GlobalConfiguration.class); // pointless type parameters help work around bugs in javac in earlier versions http://codepad.org/m1bbFRrH } } diff --git a/core/src/main/java/jenkins/model/GlobalConfigurationCategory.java b/core/src/main/java/jenkins/model/GlobalConfigurationCategory.java index d46329a404..5164f171e4 100644 --- a/core/src/main/java/jenkins/model/GlobalConfigurationCategory.java +++ b/core/src/main/java/jenkins/model/GlobalConfigurationCategory.java @@ -4,10 +4,10 @@ import hudson.Extension; import hudson.ExtensionList; import hudson.ExtensionPoint; import hudson.model.ModelObject; -import hudson.security.*; -import hudson.security.Messages; import org.jenkinsci.Symbol; +import javax.annotation.Nonnull; + /** * Grouping of related {@link GlobalConfiguration}s. * @@ -41,8 +41,12 @@ public abstract class GlobalConfigurationCategory implements ExtensionPoint, Mod return ExtensionList.lookup(GlobalConfigurationCategory.class); } - public static T get(Class type) { - return all().get(type); + public static @Nonnull T get(Class type) { + T category = all().get(type); + if(category == null){ + throw new AssertionError("Category not found. It seems the " + type + " is not annotated with @Extension and so not registered"); + } + return category; } /** diff --git a/core/src/main/java/jenkins/model/GlobalNodePropertiesConfiguration.java b/core/src/main/java/jenkins/model/GlobalNodePropertiesConfiguration.java index 68bfc2bf01..b4cd78f46a 100644 --- a/core/src/main/java/jenkins/model/GlobalNodePropertiesConfiguration.java +++ b/core/src/main/java/jenkins/model/GlobalNodePropertiesConfiguration.java @@ -19,7 +19,7 @@ public class GlobalNodePropertiesConfiguration extends GlobalConfiguration { @Override public boolean configure(StaplerRequest req, JSONObject json) throws FormException { try { - Jenkins j = Jenkins.getInstance(); + Jenkins j = Jenkins.get(); JSONObject np = json.getJSONObject("globalNodeProperties"); if (!np.isNullObject()) { j.getGlobalNodeProperties().rebuild(req, np, NodeProperty.for_(j)); diff --git a/core/src/main/java/jenkins/model/GlobalPluginConfiguration.java b/core/src/main/java/jenkins/model/GlobalPluginConfiguration.java index a706573c07..0454001f2a 100644 --- a/core/src/main/java/jenkins/model/GlobalPluginConfiguration.java +++ b/core/src/main/java/jenkins/model/GlobalPluginConfiguration.java @@ -24,7 +24,7 @@ public class GlobalPluginConfiguration extends GlobalConfiguration { public boolean configure(StaplerRequest req, JSONObject json) throws FormException { try { for( JSONObject o : StructuredForm.toList(json, "plugin")) - Jenkins.getInstance().pluginManager.getPlugin(o.getString("name")).getPlugin().configure(req, o); + Jenkins.get().pluginManager.getPlugin(o.getString("name")).getPlugin().configure(req, o); return true; } catch (IOException | ServletException e) { throw new FormException(e,"plugin"); diff --git a/core/src/main/java/jenkins/model/GlobalProjectNamingStrategyConfiguration.java b/core/src/main/java/jenkins/model/GlobalProjectNamingStrategyConfiguration.java index ca07798af1..2502df1b6e 100644 --- a/core/src/main/java/jenkins/model/GlobalProjectNamingStrategyConfiguration.java +++ b/core/src/main/java/jenkins/model/GlobalProjectNamingStrategyConfiguration.java @@ -41,13 +41,13 @@ public class GlobalProjectNamingStrategyConfiguration extends GlobalConfiguratio @Override public boolean configure(StaplerRequest req, JSONObject json) throws hudson.model.Descriptor.FormException { // for compatibility reasons, the actual value is stored in Jenkins - Jenkins j = Jenkins.getInstance(); + Jenkins j = Jenkins.get(); final JSONObject optJSONObject = json.optJSONObject("useProjectNamingStrategy"); if (optJSONObject != null) { final JSONObject strategyObject = optJSONObject.getJSONObject("namingStrategy"); final String className = strategyObject.getString("$class"); try { - Class clazz = Class.forName(className, true, Jenkins.getInstance().getPluginManager().uberClassLoader); + Class clazz = Class.forName(className, true, j.getPluginManager().uberClassLoader); final ProjectNamingStrategy strategy = (ProjectNamingStrategy) req.bindJSON(clazz, strategyObject); j.setProjectNamingStrategy(strategy); } catch (ClassNotFoundException e) { diff --git a/core/src/main/java/jenkins/model/GlobalQuietPeriodConfiguration.java b/core/src/main/java/jenkins/model/GlobalQuietPeriodConfiguration.java index cf1001793a..b0cdd84d3d 100644 --- a/core/src/main/java/jenkins/model/GlobalQuietPeriodConfiguration.java +++ b/core/src/main/java/jenkins/model/GlobalQuietPeriodConfiguration.java @@ -38,7 +38,7 @@ import java.io.IOException; @Extension(ordinal=400) @Symbol("quietPeriod") public class GlobalQuietPeriodConfiguration extends GlobalConfiguration { public int getQuietPeriod() { - return Jenkins.getInstance().getQuietPeriod(); + return Jenkins.get().getQuietPeriod(); } @Override @@ -51,7 +51,7 @@ public class GlobalQuietPeriodConfiguration extends GlobalConfiguration { } try { // for compatibility reasons, this value is stored in Jenkins - Jenkins.getInstance().setQuietPeriod(i); + Jenkins.get().setQuietPeriod(i); return true; } catch (IOException e) { throw new FormException(e,"quietPeriod"); diff --git a/core/src/main/java/jenkins/model/GlobalSCMRetryCountConfiguration.java b/core/src/main/java/jenkins/model/GlobalSCMRetryCountConfiguration.java index 3e4d3afafa..32d0c155c6 100644 --- a/core/src/main/java/jenkins/model/GlobalSCMRetryCountConfiguration.java +++ b/core/src/main/java/jenkins/model/GlobalSCMRetryCountConfiguration.java @@ -39,14 +39,14 @@ import java.io.IOException; @Extension(ordinal=395) @Symbol("scmRetryCount") public class GlobalSCMRetryCountConfiguration extends GlobalConfiguration { public int getScmCheckoutRetryCount() { - return Jenkins.getInstance().getScmCheckoutRetryCount(); + return Jenkins.get().getScmCheckoutRetryCount(); } @Override public boolean configure(StaplerRequest req, JSONObject json) throws FormException { try { // for compatibility reasons, this value is stored in Jenkins - Jenkins.getInstance().setScmCheckoutRetryCount(json.getInt("scmCheckoutRetryCount")); + Jenkins.get().setScmCheckoutRetryCount(json.getInt("scmCheckoutRetryCount")); return true; } catch (IOException e) { throw new FormException(e,"quietPeriod"); diff --git a/core/src/main/java/jenkins/model/InvalidBuildsDir.java b/core/src/main/java/jenkins/model/InvalidBuildsDir.java new file mode 100644 index 0000000000..7e9b8f348d --- /dev/null +++ b/core/src/main/java/jenkins/model/InvalidBuildsDir.java @@ -0,0 +1,16 @@ +package jenkins.model; + +import hudson.util.BootFailure; + +public class InvalidBuildsDir extends BootFailure { + private String message; + + public InvalidBuildsDir(String message) { + this.message = message; + } + + @Override + public String getMessage() { + return message; + } +} diff --git a/core/src/main/java/jenkins/model/Jenkins.java b/core/src/main/java/jenkins/model/Jenkins.java index 4d7611e9f7..9042877ccd 100644 --- a/core/src/main/java/jenkins/model/Jenkins.java +++ b/core/src/main/java/jenkins/model/Jenkins.java @@ -27,6 +27,7 @@ package jenkins.model; import antlr.ANTLRException; +import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; @@ -327,6 +328,9 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve /** * The Jenkins instance startup type i.e. NEW, UPGRADE etc */ + private String installStateName; + + @Deprecated private InstallState installState; /** @@ -399,7 +403,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve * This value will be variable-expanded as per {@link #expandVariablesForDirectory}. * @see #getWorkspaceFor(TopLevelItem) */ - private String workspaceDir = "${ITEM_ROOTDIR}/"+WORKSPACE_DIRNAME; + private String workspaceDir = OLD_DEFAULT_WORKSPACES_DIR; /** * Root directory for the builds. @@ -846,7 +850,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve if (!new File(root,"jobs").exists()) { // if this is a fresh install, use more modern default layout that's consistent with agents - workspaceDir = "${JENKINS_HOME}/workspace/${ITEM_FULL_NAME}"; + workspaceDir = DEFAULT_WORKSPACES_DIR; } // doing this early allows InitStrategy to set environment upfront @@ -1013,10 +1017,12 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve @Nonnull @Restricted(NoExternalUse.class) public InstallState getInstallState() { - if (installState == null || installState.name() == null) { - return InstallState.UNKNOWN; + if (installState != null) { + installStateName = installState.name(); + installState = null; } - return installState; + InstallState is = installStateName != null ? InstallState.valueOf(installStateName) : InstallState.UNKNOWN; + return is != null ? is : InstallState.UNKNOWN; } /** @@ -1025,10 +1031,10 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve */ @Restricted(NoExternalUse.class) public void setInstallState(@Nonnull InstallState newState) { - InstallState prior = installState; - installState = newState; - LOGGER.log(Main.isDevelopmentMode ? Level.INFO : Level.FINE, "Install state transitioning from: {0} to : {1}", new Object[] { prior, installState }); - if (!newState.equals(prior)) { + String prior = installStateName; + installStateName = newState.name(); + LOGGER.log(Main.isDevelopmentMode ? Level.INFO : Level.FINE, "Install state transitioning from: {0} to : {1}", new Object[] { prior, installStateName }); + if (!installStateName.equals(prior)) { getSetupWizard().onInstallStateUpdate(newState); newState.initializeState(); } @@ -2135,46 +2141,6 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve return FormValidation.validateNonNegativeInteger(value); } - public FormValidation doCheckRawBuildsDir(@QueryParameter String value) { - // do essentially what expandVariablesForDirectory does, without an Item - String replacedValue = expandVariablesForDirectory(value, - "doCheckRawBuildsDir-Marker:foo", - Jenkins.getInstance().getRootDir().getPath() + "/jobs/doCheckRawBuildsDir-Marker$foo"); - - File replacedFile = new File(replacedValue); - if (!replacedFile.isAbsolute()) { - return FormValidation.error(value + " does not resolve to an absolute path"); - } - - if (!replacedValue.contains("doCheckRawBuildsDir-Marker")) { - return FormValidation.error(value + " does not contain ${ITEM_FULL_NAME} or ${ITEM_ROOTDIR}, cannot distinguish between projects"); - } - - if (replacedValue.contains("doCheckRawBuildsDir-Marker:foo")) { - // make sure platform can handle colon - try { - File tmp = File.createTempFile("Jenkins-doCheckRawBuildsDir", "foo:bar"); - tmp.delete(); - } catch (IOException e) { - return FormValidation.error(value + " contains ${ITEM_FULLNAME} but your system does not support it (JENKINS-12251). Use ${ITEM_FULL_NAME} instead"); - } - } - - File d = new File(replacedValue); - if (!d.isDirectory()) { - // if dir does not exist (almost guaranteed) need to make sure nearest existing ancestor can be written to - d = d.getParentFile(); - while (!d.exists()) { - d = d.getParentFile(); - } - if (!d.canWrite()) { - return FormValidation.error(value + " does not exist and probably cannot be created"); - } - } - - return FormValidation.ok(); - } - // to route /descriptor/FQCN/xxx to getDescriptor(FQCN).xxx public Object getDynamic(String token) { return Jenkins.getInstance().getDescriptor(token); @@ -2402,6 +2368,11 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve return DEFAULT_BUILDS_DIR.equals(buildsDir); } + @Restricted(NoExternalUse.class) + boolean isDefaultWorkspaceDir() { + return OLD_DEFAULT_WORKSPACES_DIR.equals(workspaceDir) || DEFAULT_WORKSPACES_DIR.equals(workspaceDir); + } + private File expandVariablesForDirectory(String base, Item item) { return new File(expandVariablesForDirectory(base, item.getFullName(), item.getRootDir().getPath())); } @@ -2573,7 +2544,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve * * @since 1.433 */ - public Injector getInjector() { + public @CheckForNull Injector getInjector() { return lookup(Injector.class); } @@ -2610,7 +2581,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve * Can be an empty list but never null. */ @SuppressWarnings({"unchecked"}) - public ,D extends Descriptor> DescriptorExtensionList getDescriptorList(Class type) { + public @Nonnull ,D extends Descriptor> DescriptorExtensionList getDescriptorList(Class type) { return descriptorLists.computeIfAbsent(type, key -> DescriptorExtensionList.createDescriptorList(this, key)); } @@ -3033,6 +3004,87 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve // load from disk cfg.unmarshal(Jenkins.this); } + + try { + checkRawBuildsDir(buildsDir); + setBuildsAndWorkspacesDir(); + } catch (InvalidBuildsDir invalidBuildsDir) { + throw new IOException(invalidBuildsDir); + } + + } + + private void setBuildsAndWorkspacesDir() throws IOException, InvalidBuildsDir { + boolean mustSave = false; + String newBuildsDir = SystemProperties.getString(BUILDS_DIR_PROP); + if (newBuildsDir != null && !buildsDir.equals(newBuildsDir)) { + + checkRawBuildsDir(newBuildsDir); + LOGGER.log(Level.WARNING, "Changing builds directories from {0} to {1}. Beware that no automated data migration will occur.", + new String[]{buildsDir, newBuildsDir}); + buildsDir = newBuildsDir; + mustSave = true; + } else if (!isDefaultBuildDir()) { + LOGGER.log(Level.INFO, "Using non default builds directories: {0}.", buildsDir); + } + + String newWorkspacesDir = SystemProperties.getString(WORKSPACES_DIR_PROP); + if (newWorkspacesDir != null && !workspaceDir.equals(newWorkspacesDir)) { + LOGGER.log(Level.WARNING, "Changing workspaces directories from {0} to {1}. Beware that no automated data migration will occur.", + new String[]{workspaceDir, newWorkspacesDir}); + workspaceDir = newWorkspacesDir; + mustSave = true; + } else if (!isDefaultWorkspaceDir()) { + LOGGER.log(Level.INFO, "Using non default workspaces directories: {0}.", workspaceDir); + } + + if (mustSave) { + save(); + } + } + + /** + * Checks the correctness of the newBuildsDirValue for use as {@link #buildsDir}. + * @param newBuildsDirValue the candidate newBuildsDirValue for updating {@link #buildsDir}. + */ + @VisibleForTesting + /*private*/ static void checkRawBuildsDir(String newBuildsDirValue) throws InvalidBuildsDir { + + // do essentially what expandVariablesForDirectory does, without an Item + String replacedValue = expandVariablesForDirectory(newBuildsDirValue, + "doCheckRawBuildsDir-Marker:foo", + Jenkins.getInstance().getRootDir().getPath() + "/jobs/doCheckRawBuildsDir-Marker$foo"); + + File replacedFile = new File(replacedValue); + if (!replacedFile.isAbsolute()) { + throw new InvalidBuildsDir(newBuildsDirValue + " does not resolve to an absolute path"); + } + + if (!replacedValue.contains("doCheckRawBuildsDir-Marker")) { + throw new InvalidBuildsDir(newBuildsDirValue + " does not contain ${ITEM_FULL_NAME} or ${ITEM_ROOTDIR}, cannot distinguish between projects"); + } + + if (replacedValue.contains("doCheckRawBuildsDir-Marker:foo")) { + // make sure platform can handle colon + try { + File tmp = File.createTempFile("Jenkins-doCheckRawBuildsDir", "foo:bar"); + tmp.delete(); + } catch (IOException e) { + throw new InvalidBuildsDir(newBuildsDirValue + " contains ${ITEM_FULLNAME} but your system does not support it (JENKINS-12251). Use ${ITEM_FULL_NAME} instead"); + } + } + + File d = new File(replacedValue); + if (!d.isDirectory()) { + // if dir does not exist (almost guaranteed) need to make sure nearest existing ancestor can be written to + d = d.getParentFile(); + while (!d.exists()) { + d = d.getParentFile(); + } + if (!d.canWrite()) { + throw new InvalidBuildsDir(newBuildsDirValue + " does not exist and probably cannot be created"); + } + } } private synchronized TaskBuilder loadTasks() throws IOException { @@ -3636,9 +3688,6 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve JSONObject json = req.getSubmittedForm(); - workspaceDir = json.getString("rawWorkspaceDir"); - buildsDir = json.getString("rawBuildsDir"); - systemMessage = Util.nullify(req.getParameter("system_message")); boolean result = true; @@ -5055,6 +5104,29 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve * @see #getRawBuildsDir() */ private static final String DEFAULT_BUILDS_DIR = "${ITEM_ROOTDIR}/builds"; + /** + * Old layout for workspaces. + * @see #DEFAULT_WORKSPACES_DIR + */ + private static final String OLD_DEFAULT_WORKSPACES_DIR = "${ITEM_ROOTDIR}/" + WORKSPACE_DIRNAME; + + /** + * Default value for the workspace's directories layout. + * @see #workspaceDir + */ + private static final String DEFAULT_WORKSPACES_DIR = "${JENKINS_HOME}/workspace/${ITEM_FULL_NAME}"; + + /** + * System property name to set {@link #buildsDir}. + * @see #getRawBuildsDir() + */ + static final String BUILDS_DIR_PROP = Jenkins.class.getName() + ".buildsDir"; + + /** + * System property name to set {@link #workspaceDir}. + * @see #getRawWorkspaceDir() + */ + static final String WORKSPACES_DIR_PROP = Jenkins.class.getName() + ".workspacesDir"; /** * Automatically try to launch an agent when Jenkins is initialized or a new agent computer is created. diff --git a/core/src/main/java/jenkins/model/JenkinsLocationConfiguration.java b/core/src/main/java/jenkins/model/JenkinsLocationConfiguration.java index b7390ad3d3..ed402938b4 100644 --- a/core/src/main/java/jenkins/model/JenkinsLocationConfiguration.java +++ b/core/src/main/java/jenkins/model/JenkinsLocationConfiguration.java @@ -6,6 +6,8 @@ import hudson.XmlFile; import hudson.util.FormValidation; import hudson.util.XStream2; import org.jenkinsci.Symbol; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; import org.kohsuke.stapler.QueryParameter; import javax.mail.internet.AddressException; @@ -41,14 +43,20 @@ public class JenkinsLocationConfiguration extends GlobalConfiguration { // just to suppress warnings private transient String charset,useSsl; + public static @Nonnull JenkinsLocationConfiguration get() { + return GlobalConfiguration.all().getInstance(JenkinsLocationConfiguration.class); + } + /** - * Gets local configuration. - * - * @return {@code null} if the {@link GlobalConfiguration#all()} list does not contain this extension. - * Most likely it means that the Jenkins instance has not been fully loaded yet. + * Gets local configuration. For explanation when it could die, see {@link #get()} */ - public static @CheckForNull JenkinsLocationConfiguration get() { - return GlobalConfiguration.all().get(JenkinsLocationConfiguration.class); + @Restricted(NoExternalUse.class) + public static @Nonnull JenkinsLocationConfiguration getOrDie(){ + JenkinsLocationConfiguration config = JenkinsLocationConfiguration.get(); + if (config == null) { + throw new IllegalStateException("JenkinsLocationConfiguration instance is missing. Probably the Jenkins instance is not fully loaded at this time."); + } + return config; } public JenkinsLocationConfiguration() { @@ -63,7 +71,7 @@ public class JenkinsLocationConfiguration extends GlobalConfiguration { if(!file.exists()) { XStream2 xs = new XStream2(); xs.addCompatibilityAlias("hudson.tasks.Mailer$DescriptorImpl",JenkinsLocationConfiguration.class); - file = new XmlFile(xs,new File(Jenkins.getInstance().getRootDir(),"hudson.tasks.Mailer.xml")); + file = new XmlFile(xs,new File(Jenkins.get().getRootDir(),"hudson.tasks.Mailer.xml")); if (file.exists()) { try { file.unmarshal(this); @@ -125,7 +133,7 @@ public class JenkinsLocationConfiguration extends GlobalConfiguration { */ private void updateSecureSessionFlag() { try { - ServletContext context = Jenkins.getInstance().servletContext; + ServletContext context = Jenkins.get().servletContext; Method m; try { m = context.getClass().getMethod("getSessionCookieConfig"); diff --git a/core/src/main/java/jenkins/model/MasterBuildConfiguration.java b/core/src/main/java/jenkins/model/MasterBuildConfiguration.java index 3bc348419c..e656a6d9bf 100644 --- a/core/src/main/java/jenkins/model/MasterBuildConfiguration.java +++ b/core/src/main/java/jenkins/model/MasterBuildConfiguration.java @@ -39,16 +39,16 @@ import java.io.IOException; @Extension(ordinal=500) @Symbol("masterBuild") public class MasterBuildConfiguration extends GlobalConfiguration { public int getNumExecutors() { - return Jenkins.getInstance().getNumExecutors(); + return Jenkins.get().getNumExecutors(); } public String getLabelString() { - return Jenkins.getInstance().getLabelString(); + return Jenkins.get().getLabelString(); } @Override public boolean configure(StaplerRequest req, JSONObject json) throws FormException { - Jenkins j = Jenkins.getInstance(); + Jenkins j = Jenkins.get(); try { // for compatibility reasons, this value is stored in Jenkins String num = json.getString("numExecutors"); diff --git a/core/src/main/java/jenkins/mvn/GlobalMavenConfig.java b/core/src/main/java/jenkins/mvn/GlobalMavenConfig.java index b8d0ebe4a5..24cdb171e2 100644 --- a/core/src/main/java/jenkins/mvn/GlobalMavenConfig.java +++ b/core/src/main/java/jenkins/mvn/GlobalMavenConfig.java @@ -7,6 +7,8 @@ import jenkins.tools.ToolConfigurationCategory; import org.jenkinsci.Symbol; +import javax.annotation.Nonnull; + //as close as it gets to the global Maven Project configuration @Extension(ordinal = 50) @Symbol("maven") public class GlobalMavenConfig extends GlobalConfiguration { @@ -18,7 +20,7 @@ public class GlobalMavenConfig extends GlobalConfiguration { } @Override - public ToolConfigurationCategory getCategory() { + public @Nonnull ToolConfigurationCategory getCategory() { return GlobalConfigurationCategory.get(ToolConfigurationCategory.class); } @@ -40,8 +42,8 @@ public class GlobalMavenConfig extends GlobalConfiguration { return settingsProvider != null ? settingsProvider : new DefaultSettingsProvider(); } - public static GlobalMavenConfig get() { - return GlobalConfiguration.all().get(GlobalMavenConfig.class); + public static @Nonnull GlobalMavenConfig get() { + return GlobalConfiguration.all().getInstance(GlobalMavenConfig.class); } } diff --git a/core/src/main/java/jenkins/org/apache/commons/validator/routines/DomainValidator.java b/core/src/main/java/jenkins/org/apache/commons/validator/routines/DomainValidator.java new file mode 100644 index 0000000000..10edf8c4f7 --- /dev/null +++ b/core/src/main/java/jenkins/org/apache/commons/validator/routines/DomainValidator.java @@ -0,0 +1,2075 @@ +/* + * 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. + */ +/* Copied from commons-validator:commons-validator:1.6, with [PATCH] modifications */ +package jenkins.org.apache.commons.validator.routines; + +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; + +import java.io.Serializable; +import java.net.IDN; +import java.util.Arrays; +import java.util.Locale; + +/** + *

Domain name validation routines.

+ * + *

+ * This validator provides methods for validating Internet domain names + * and top-level domains. + *

+ * + *

Domain names are evaluated according + * to the standards RFC1034, + * section 3, and RFC1123, + * section 2.1. No accommodation is provided for the specialized needs of + * other applications; if the domain name has been URL-encoded, for example, + * validation will fail even though the equivalent plaintext version of the + * same name would have passed. + *

+ * + *

+ * Validation is also provided for top-level domains (TLDs) as defined and + * maintained by the Internet Assigned Numbers Authority (IANA): + *

+ * + *
    + *
  • {@link #isValidInfrastructureTld} - validates infrastructure TLDs + * (.arpa, etc.)
  • + *
  • {@link #isValidGenericTld} - validates generic TLDs + * (.com, .org, etc.)
  • + *
  • {@link #isValidCountryCodeTld} - validates country code TLDs + * (.us, .uk, .cn, etc.)
  • + *
+ * + *

+ * (NOTE: This class does not provide IP address lookup for domain names or + * methods to ensure that a given domain name matches a specific IP; see + * {@link java.net.InetAddress} for that functionality.) + *

+ * + * @version $Revision: 1781829 $ + * @since Validator 1.4 + */ +//[PATCH] +@Restricted(NoExternalUse.class) +// end of [PATCH] +public class DomainValidator implements Serializable { + + private static final int MAX_DOMAIN_LENGTH = 253; + + private static final String[] EMPTY_STRING_ARRAY = new String[0]; + + private static final long serialVersionUID = -4407125112880174009L; + + // Regular expression strings for hostnames (derived from RFC2396 and RFC 1123) + + // RFC2396: domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum + // Max 63 characters + private static final String DOMAIN_LABEL_REGEX = "\\p{Alnum}(?>[\\p{Alnum}-]{0,61}\\p{Alnum})?"; + + // RFC2396 toplabel = alpha | alpha *( alphanum | "-" ) alphanum + // Max 63 characters + private static final String TOP_LABEL_REGEX = "\\p{Alpha}(?>[\\p{Alnum}-]{0,61}\\p{Alnum})?"; + + // RFC2396 hostname = *( domainlabel "." ) toplabel [ "." ] + // Note that the regex currently requires both a domain label and a top level label, whereas + // the RFC does not. This is because the regex is used to detect if a TLD is present. + // If the match fails, input is checked against DOMAIN_LABEL_REGEX (hostnameRegex) + // RFC1123 sec 2.1 allows hostnames to start with a digit + private static final String DOMAIN_NAME_REGEX = + "^(?:" + DOMAIN_LABEL_REGEX + "\\.)+" + "(" + TOP_LABEL_REGEX + ")\\.?$"; + + private final boolean allowLocal; + + /** + * Singleton instance of this validator, which + * doesn't consider local addresses as valid. + */ + private static final DomainValidator DOMAIN_VALIDATOR = new DomainValidator(false); + + /** + * Singleton instance of this validator, which does + * consider local addresses valid. + */ + private static final DomainValidator DOMAIN_VALIDATOR_WITH_LOCAL = new DomainValidator(true); + + /** + * RegexValidator for matching domains. + */ + private final RegexValidator domainRegex = + new RegexValidator(DOMAIN_NAME_REGEX); + /** + * RegexValidator for matching a local hostname + */ + // RFC1123 sec 2.1 allows hostnames to start with a digit + private final RegexValidator hostnameRegex = + new RegexValidator(DOMAIN_LABEL_REGEX); + + /** + * Returns the singleton instance of this validator. It + * will not consider local addresses as valid. + * @return the singleton instance of this validator + */ + public static synchronized DomainValidator getInstance() { + inUse = true; + return DOMAIN_VALIDATOR; + } + + /** + * Returns the singleton instance of this validator, + * with local validation as required. + * @param allowLocal Should local addresses be considered valid? + * @return the singleton instance of this validator + */ + public static synchronized DomainValidator getInstance(boolean allowLocal) { + inUse = true; + if(allowLocal) { + return DOMAIN_VALIDATOR_WITH_LOCAL; + } + return DOMAIN_VALIDATOR; + } + + /** Private constructor. */ + private DomainValidator(boolean allowLocal) { + this.allowLocal = allowLocal; + } + + /** + * Returns true if the specified String parses + * as a valid domain name with a recognized top-level domain. + * The parsing is case-insensitive. + * @param domain the parameter to check for domain name syntax + * @return true if the parameter is a valid domain name + */ + public boolean isValid(String domain) { + if (domain == null) { + return false; + } + domain = unicodeToASCII(domain); + // hosts must be equally reachable via punycode and Unicode; + // Unicode is never shorter than punycode, so check punycode + // if domain did not convert, then it will be caught by ASCII + // checks in the regexes below + if (domain.length() > MAX_DOMAIN_LENGTH) { + return false; + } + String[] groups = domainRegex.match(domain); + if (groups != null && groups.length > 0) { + return isValidTld(groups[0]); + } + return allowLocal && hostnameRegex.isValid(domain); + } + + // package protected for unit test access + // must agree with isValidRootUrl() above + final boolean isValidDomainSyntax(String domain) { + if (domain == null) { + return false; + } + domain = unicodeToASCII(domain); + // hosts must be equally reachable via punycode and Unicode; + // Unicode is never shorter than punycode, so check punycode + // if domain did not convert, then it will be caught by ASCII + // checks in the regexes below + if (domain.length() > MAX_DOMAIN_LENGTH) { + return false; + } + String[] groups = domainRegex.match(domain); + return (groups != null && groups.length > 0) + || hostnameRegex.isValid(domain); + } + + /** + * Returns true if the specified String matches any + * IANA-defined top-level domain. Leading dots are ignored if present. + * The search is case-insensitive. + * @param tld the parameter to check for TLD status, not null + * @return true if the parameter is a TLD + */ + public boolean isValidTld(String tld) { + tld = unicodeToASCII(tld); + if(allowLocal && isValidLocalTld(tld)) { + return true; + } + return isValidInfrastructureTld(tld) + || isValidGenericTld(tld) + || isValidCountryCodeTld(tld); + } + + /** + * Returns true if the specified String matches any + * IANA-defined infrastructure top-level domain. Leading dots are + * ignored if present. The search is case-insensitive. + * @param iTld the parameter to check for infrastructure TLD status, not null + * @return true if the parameter is an infrastructure TLD + */ + public boolean isValidInfrastructureTld(String iTld) { + final String key = chompLeadingDot(unicodeToASCII(iTld).toLowerCase(Locale.ENGLISH)); + return arrayContains(INFRASTRUCTURE_TLDS, key); + } + + /** + * Returns true if the specified String matches any + * IANA-defined generic top-level domain. Leading dots are ignored + * if present. The search is case-insensitive. + * @param gTld the parameter to check for generic TLD status, not null + * @return true if the parameter is a generic TLD + */ + public boolean isValidGenericTld(String gTld) { + final String key = chompLeadingDot(unicodeToASCII(gTld).toLowerCase(Locale.ENGLISH)); + return (arrayContains(GENERIC_TLDS, key) || arrayContains(genericTLDsPlus, key)) + && !arrayContains(genericTLDsMinus, key); + } + + /** + * Returns true if the specified String matches any + * IANA-defined country code top-level domain. Leading dots are + * ignored if present. The search is case-insensitive. + * @param ccTld the parameter to check for country code TLD status, not null + * @return true if the parameter is a country code TLD + */ + public boolean isValidCountryCodeTld(String ccTld) { + final String key = chompLeadingDot(unicodeToASCII(ccTld).toLowerCase(Locale.ENGLISH)); + return (arrayContains(COUNTRY_CODE_TLDS, key) || arrayContains(countryCodeTLDsPlus, key)) + && !arrayContains(countryCodeTLDsMinus, key); + } + + /** + * Returns true if the specified String matches any + * widely used "local" domains (localhost or localdomain). Leading dots are + * ignored if present. The search is case-insensitive. + * @param lTld the parameter to check for local TLD status, not null + * @return true if the parameter is an local TLD + */ + public boolean isValidLocalTld(String lTld) { + final String key = chompLeadingDot(unicodeToASCII(lTld).toLowerCase(Locale.ENGLISH)); + return arrayContains(LOCAL_TLDS, key); + } + + private String chompLeadingDot(String str) { + if (str.startsWith(".")) { + return str.substring(1); + } + return str; + } + + // --------------------------------------------- + // ----- TLDs defined by IANA + // ----- Authoritative and comprehensive list at: + // ----- http://data.iana.org/TLD/tlds-alpha-by-domain.txt + + // Note that the above list is in UPPER case. + // The code currently converts strings to lower case (as per the tables below) + + // IANA also provide an HTML list at http://www.iana.org/domains/root/db + // Note that this contains several country code entries which are NOT in + // the text file. These all have the "Not assigned" in the "Sponsoring Organisation" column + // For example (as of 2015-01-02): + // .bl country-code Not assigned + // .um country-code Not assigned + + // WARNING: this array MUST be sorted, otherwise it cannot be searched reliably using binary search + private static final String[] INFRASTRUCTURE_TLDS = new String[] { + "arpa", // internet infrastructure + }; + + // WARNING: this array MUST be sorted, otherwise it cannot be searched reliably using binary search + private static final String[] GENERIC_TLDS = new String[] { + // Taken from Version 2017020400, Last Updated Sat Feb 4 07:07:01 2017 UTC + "aaa", // aaa American Automobile Association, Inc. + "aarp", // aarp AARP + "abarth", // abarth Fiat Chrysler Automobiles N.V. + "abb", // abb ABB Ltd + "abbott", // abbott Abbott Laboratories, Inc. + "abbvie", // abbvie AbbVie Inc. + "abc", // abc Disney Enterprises, Inc. + "able", // able Able Inc. + "abogado", // abogado Top Level Domain Holdings Limited + "abudhabi", // abudhabi Abu Dhabi Systems and Information Centre + "academy", // academy Half Oaks, LLC + "accenture", // accenture Accenture plc + "accountant", // accountant dot Accountant Limited + "accountants", // accountants Knob Town, LLC + "aco", // aco ACO Severin Ahlmann GmbH & Co. KG + "active", // active The Active Network, Inc + "actor", // actor United TLD Holdco Ltd. + "adac", // adac Allgemeiner Deutscher Automobil-Club e.V. (ADAC) + "ads", // ads Charleston Road Registry Inc. + "adult", // adult ICM Registry AD LLC + "aeg", // aeg Aktiebolaget Electrolux + "aero", // aero Societe Internationale de Telecommunications Aeronautique (SITA INC USA) + "aetna", // aetna Aetna Life Insurance Company + "afamilycompany", // afamilycompany Johnson Shareholdings, Inc. + "afl", // afl Australian Football League + "agakhan", // agakhan Fondation Aga Khan (Aga Khan Foundation) + "agency", // agency Steel Falls, LLC + "aig", // aig American International Group, Inc. + "aigo", // aigo aigo Digital Technology Co,Ltd. + "airbus", // airbus Airbus S.A.S. + "airforce", // airforce United TLD Holdco Ltd. + "airtel", // airtel Bharti Airtel Limited + "akdn", // akdn Fondation Aga Khan (Aga Khan Foundation) + "alfaromeo", // alfaromeo Fiat Chrysler Automobiles N.V. + "alibaba", // alibaba Alibaba Group Holding Limited + "alipay", // alipay Alibaba Group Holding Limited + "allfinanz", // allfinanz Allfinanz Deutsche Vermögensberatung Aktiengesellschaft + "allstate", // allstate Allstate Fire and Casualty Insurance Company + "ally", // ally Ally Financial Inc. + "alsace", // alsace REGION D ALSACE + "alstom", // alstom ALSTOM + "americanexpress", // americanexpress American Express Travel Related Services Company, Inc. + "americanfamily", // americanfamily AmFam, Inc. + "amex", // amex American Express Travel Related Services Company, Inc. + "amfam", // amfam AmFam, Inc. + "amica", // amica Amica Mutual Insurance Company + "amsterdam", // amsterdam Gemeente Amsterdam + "analytics", // analytics Campus IP LLC + "android", // android Charleston Road Registry Inc. + "anquan", // anquan QIHOO 360 TECHNOLOGY CO. LTD. + "anz", // anz Australia and New Zealand Banking Group Limited + "aol", // aol AOL Inc. + "apartments", // apartments June Maple, LLC + "app", // app Charleston Road Registry Inc. + "apple", // apple Apple Inc. + "aquarelle", // aquarelle Aquarelle.com + "aramco", // aramco Aramco Services Company + "archi", // archi STARTING DOT LIMITED + "army", // army United TLD Holdco Ltd. + "art", // art UK Creative Ideas Limited + "arte", // arte Association Relative à la Télévision Européenne G.E.I.E. + "asda", // asda Wal-Mart Stores, Inc. + "asia", // asia DotAsia Organisation Ltd. + "associates", // associates Baxter Hill, LLC + "athleta", // athleta The Gap, Inc. + "attorney", // attorney United TLD Holdco, Ltd + "auction", // auction United TLD HoldCo, Ltd. + "audi", // audi AUDI Aktiengesellschaft + "audible", // audible Amazon Registry Services, Inc. + "audio", // audio Uniregistry, Corp. + "auspost", // auspost Australian Postal Corporation + "author", // author Amazon Registry Services, Inc. + "auto", // auto Uniregistry, Corp. + "autos", // autos DERAutos, LLC + "avianca", // avianca Aerovias del Continente Americano S.A. Avianca + "aws", // aws Amazon Registry Services, Inc. + "axa", // axa AXA SA + "azure", // azure Microsoft Corporation + "baby", // baby Johnson & Johnson Services, Inc. + "baidu", // baidu Baidu, Inc. + "banamex", // banamex Citigroup Inc. + "bananarepublic", // bananarepublic The Gap, Inc. + "band", // band United TLD Holdco, Ltd + "bank", // bank fTLD Registry Services, LLC + "bar", // bar Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable + "barcelona", // barcelona Municipi de Barcelona + "barclaycard", // barclaycard Barclays Bank PLC + "barclays", // barclays Barclays Bank PLC + "barefoot", // barefoot Gallo Vineyards, Inc. + "bargains", // bargains Half Hallow, LLC + "baseball", // baseball MLB Advanced Media DH, LLC + "basketball", // basketball Fédération Internationale de Basketball (FIBA) + "bauhaus", // bauhaus Werkhaus GmbH + "bayern", // bayern Bayern Connect GmbH + "bbc", // bbc British Broadcasting Corporation + "bbt", // bbt BB&T Corporation + "bbva", // bbva BANCO BILBAO VIZCAYA ARGENTARIA, S.A. + "bcg", // bcg The Boston Consulting Group, Inc. + "bcn", // bcn Municipi de Barcelona + "beats", // beats Beats Electronics, LLC + "beauty", // beauty L'Oréal + "beer", // beer Top Level Domain Holdings Limited + "bentley", // bentley Bentley Motors Limited + "berlin", // berlin dotBERLIN GmbH & Co. KG + "best", // best BestTLD Pty Ltd + "bestbuy", // bestbuy BBY Solutions, Inc. + "bet", // bet Afilias plc + "bharti", // bharti Bharti Enterprises (Holding) Private Limited + "bible", // bible American Bible Society + "bid", // bid dot Bid Limited + "bike", // bike Grand Hollow, LLC + "bing", // bing Microsoft Corporation + "bingo", // bingo Sand Cedar, LLC + "bio", // bio STARTING DOT LIMITED + "biz", // biz Neustar, Inc. + "black", // black Afilias Limited + "blackfriday", // blackfriday Uniregistry, Corp. + "blanco", // blanco BLANCO GmbH + Co KG + "blockbuster", // blockbuster Dish DBS Corporation + "blog", // blog Knock Knock WHOIS There, LLC + "bloomberg", // bloomberg Bloomberg IP Holdings LLC + "blue", // blue Afilias Limited + "bms", // bms Bristol-Myers Squibb Company + "bmw", // bmw Bayerische Motoren Werke Aktiengesellschaft + "bnl", // bnl Banca Nazionale del Lavoro + "bnpparibas", // bnpparibas BNP Paribas + "boats", // boats DERBoats, LLC + "boehringer", // boehringer Boehringer Ingelheim International GmbH + "bofa", // bofa NMS Services, Inc. + "bom", // bom Núcleo de Informação e Coordenação do Ponto BR - NIC.br + "bond", // bond Bond University Limited + "boo", // boo Charleston Road Registry Inc. + "book", // book Amazon Registry Services, Inc. + "booking", // booking Booking.com B.V. + "boots", // boots THE BOOTS COMPANY PLC + "bosch", // bosch Robert Bosch GMBH + "bostik", // bostik Bostik SA + "boston", // boston Boston TLD Management, LLC + "bot", // bot Amazon Registry Services, Inc. + "boutique", // boutique Over Galley, LLC + "box", // box NS1 Limited + "bradesco", // bradesco Banco Bradesco S.A. + "bridgestone", // bridgestone Bridgestone Corporation + "broadway", // broadway Celebrate Broadway, Inc. + "broker", // broker DOTBROKER REGISTRY LTD + "brother", // brother Brother Industries, Ltd. + "brussels", // brussels DNS.be vzw + "budapest", // budapest Top Level Domain Holdings Limited + "bugatti", // bugatti Bugatti International SA + "build", // build Plan Bee LLC + "builders", // builders Atomic Madison, LLC + "business", // business Spring Cross, LLC + "buy", // buy Amazon Registry Services, INC + "buzz", // buzz DOTSTRATEGY CO. + "bzh", // bzh Association www.bzh + "cab", // cab Half Sunset, LLC + "cafe", // cafe Pioneer Canyon, LLC + "cal", // cal Charleston Road Registry Inc. + "call", // call Amazon Registry Services, Inc. + "calvinklein", // calvinklein PVH gTLD Holdings LLC + "cam", // cam AC Webconnecting Holding B.V. + "camera", // camera Atomic Maple, LLC + "camp", // camp Delta Dynamite, LLC + "cancerresearch", // cancerresearch Australian Cancer Research Foundation + "canon", // canon Canon Inc. + "capetown", // capetown ZA Central Registry NPC trading as ZA Central Registry + "capital", // capital Delta Mill, LLC + "capitalone", // capitalone Capital One Financial Corporation + "car", // car Cars Registry Limited + "caravan", // caravan Caravan International, Inc. + "cards", // cards Foggy Hollow, LLC + "care", // care Goose Cross, LLC + "career", // career dotCareer LLC + "careers", // careers Wild Corner, LLC + "cars", // cars Uniregistry, Corp. + "cartier", // cartier Richemont DNS Inc. + "casa", // casa Top Level Domain Holdings Limited + "case", // case CNH Industrial N.V. + "caseih", // caseih CNH Industrial N.V. + "cash", // cash Delta Lake, LLC + "casino", // casino Binky Sky, LLC + "cat", // cat Fundacio puntCAT + "catering", // catering New Falls. LLC + "catholic", // catholic Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) + "cba", // cba COMMONWEALTH BANK OF AUSTRALIA + "cbn", // cbn The Christian Broadcasting Network, Inc. + "cbre", // cbre CBRE, Inc. + "cbs", // cbs CBS Domains Inc. + "ceb", // ceb The Corporate Executive Board Company + "center", // center Tin Mill, LLC + "ceo", // ceo CEOTLD Pty Ltd + "cern", // cern European Organization for Nuclear Research ("CERN") + "cfa", // cfa CFA Institute + "cfd", // cfd DOTCFD REGISTRY LTD + "chanel", // chanel Chanel International B.V. + "channel", // channel Charleston Road Registry Inc. + "chase", // chase JPMorgan Chase & Co. + "chat", // chat Sand Fields, LLC + "cheap", // cheap Sand Cover, LLC + "chintai", // chintai CHINTAI Corporation + "chloe", // chloe Richemont DNS Inc. + "christmas", // christmas Uniregistry, Corp. + "chrome", // chrome Charleston Road Registry Inc. + "chrysler", // chrysler FCA US LLC. + "church", // church Holly Fileds, LLC + "cipriani", // cipriani Hotel Cipriani Srl + "circle", // circle Amazon Registry Services, Inc. + "cisco", // cisco Cisco Technology, Inc. + "citadel", // citadel Citadel Domain LLC + "citi", // citi Citigroup Inc. + "citic", // citic CITIC Group Corporation + "city", // city Snow Sky, LLC + "cityeats", // cityeats Lifestyle Domain Holdings, Inc. + "claims", // claims Black Corner, LLC + "cleaning", // cleaning Fox Shadow, LLC + "click", // click Uniregistry, Corp. + "clinic", // clinic Goose Park, LLC + "clinique", // clinique The Estée Lauder Companies Inc. + "clothing", // clothing Steel Lake, LLC + "cloud", // cloud ARUBA S.p.A. + "club", // club .CLUB DOMAINS, LLC + "clubmed", // clubmed Club Méditerranée S.A. + "coach", // coach Koko Island, LLC + "codes", // codes Puff Willow, LLC + "coffee", // coffee Trixy Cover, LLC + "college", // college XYZ.COM LLC + "cologne", // cologne NetCologne Gesellschaft für Telekommunikation mbH + "com", // com VeriSign Global Registry Services + "comcast", // comcast Comcast IP Holdings I, LLC + "commbank", // commbank COMMONWEALTH BANK OF AUSTRALIA + "community", // community Fox Orchard, LLC + "company", // company Silver Avenue, LLC + "compare", // compare iSelect Ltd + "computer", // computer Pine Mill, LLC + "comsec", // comsec VeriSign, Inc. + "condos", // condos Pine House, LLC + "construction", // construction Fox Dynamite, LLC + "consulting", // consulting United TLD Holdco, LTD. + "contact", // contact Top Level Spectrum, Inc. + "contractors", // contractors Magic Woods, LLC + "cooking", // cooking Top Level Domain Holdings Limited + "cookingchannel", // cookingchannel Lifestyle Domain Holdings, Inc. + "cool", // cool Koko Lake, LLC + "coop", // coop DotCooperation LLC + "corsica", // corsica Collectivité Territoriale de Corse + "country", // country Top Level Domain Holdings Limited + "coupon", // coupon Amazon Registry Services, Inc. + "coupons", // coupons Black Island, LLC + "courses", // courses OPEN UNIVERSITIES AUSTRALIA PTY LTD + "credit", // credit Snow Shadow, LLC + "creditcard", // creditcard Binky Frostbite, LLC + "creditunion", // creditunion CUNA Performance Resources, LLC + "cricket", // cricket dot Cricket Limited + "crown", // crown Crown Equipment Corporation + "crs", // crs Federated Co-operatives Limited + "cruise", // cruise Viking River Cruises (Bermuda) Ltd. + "cruises", // cruises Spring Way, LLC + "csc", // csc Alliance-One Services, Inc. + "cuisinella", // cuisinella SALM S.A.S. + "cymru", // cymru Nominet UK + "cyou", // cyou Beijing Gamease Age Digital Technology Co., Ltd. + "dabur", // dabur Dabur India Limited + "dad", // dad Charleston Road Registry Inc. + "dance", // dance United TLD Holdco Ltd. + "data", // data Dish DBS Corporation + "date", // date dot Date Limited + "dating", // dating Pine Fest, LLC + "datsun", // datsun NISSAN MOTOR CO., LTD. + "day", // day Charleston Road Registry Inc. + "dclk", // dclk Charleston Road Registry Inc. + "dds", // dds Minds + Machines Group Limited + "deal", // deal Amazon Registry Services, Inc. + "dealer", // dealer Dealer Dot Com, Inc. + "deals", // deals Sand Sunset, LLC + "degree", // degree United TLD Holdco, Ltd + "delivery", // delivery Steel Station, LLC + "dell", // dell Dell Inc. + "deloitte", // deloitte Deloitte Touche Tohmatsu + "delta", // delta Delta Air Lines, Inc. + "democrat", // democrat United TLD Holdco Ltd. + "dental", // dental Tin Birch, LLC + "dentist", // dentist United TLD Holdco, Ltd + "desi", // desi Desi Networks LLC + "design", // design Top Level Design, LLC + "dev", // dev Charleston Road Registry Inc. + "dhl", // dhl Deutsche Post AG + "diamonds", // diamonds John Edge, LLC + "diet", // diet Uniregistry, Corp. + "digital", // digital Dash Park, LLC + "direct", // direct Half Trail, LLC + "directory", // directory Extra Madison, LLC + "discount", // discount Holly Hill, LLC + "discover", // discover Discover Financial Services + "dish", // dish Dish DBS Corporation + "diy", // diy Lifestyle Domain Holdings, Inc. + "dnp", // dnp Dai Nippon Printing Co., Ltd. + "docs", // docs Charleston Road Registry Inc. + "doctor", // doctor Brice Trail, LLC + "dodge", // dodge FCA US LLC. + "dog", // dog Koko Mill, LLC + "doha", // doha Communications Regulatory Authority (CRA) + "domains", // domains Sugar Cross, LLC +// "doosan", // doosan Doosan Corporation (retired) + "dot", // dot Dish DBS Corporation + "download", // download dot Support Limited + "drive", // drive Charleston Road Registry Inc. + "dtv", // dtv Dish DBS Corporation + "dubai", // dubai Dubai Smart Government Department + "duck", // duck Johnson Shareholdings, Inc. + "dunlop", // dunlop The Goodyear Tire & Rubber Company + "duns", // duns The Dun & Bradstreet Corporation + "dupont", // dupont E. I. du Pont de Nemours and Company + "durban", // durban ZA Central Registry NPC trading as ZA Central Registry + "dvag", // dvag Deutsche Vermögensberatung Aktiengesellschaft DVAG + "dvr", // dvr Hughes Satellite Systems Corporation + "earth", // earth Interlink Co., Ltd. + "eat", // eat Charleston Road Registry Inc. + "eco", // eco Big Room Inc. + "edeka", // edeka EDEKA Verband kaufmännischer Genossenschaften e.V. + "edu", // edu EDUCAUSE + "education", // education Brice Way, LLC + "email", // email Spring Madison, LLC + "emerck", // emerck Merck KGaA + "energy", // energy Binky Birch, LLC + "engineer", // engineer United TLD Holdco Ltd. + "engineering", // engineering Romeo Canyon + "enterprises", // enterprises Snow Oaks, LLC + "epost", // epost Deutsche Post AG + "epson", // epson Seiko Epson Corporation + "equipment", // equipment Corn Station, LLC + "ericsson", // ericsson Telefonaktiebolaget L M Ericsson + "erni", // erni ERNI Group Holding AG + "esq", // esq Charleston Road Registry Inc. + "estate", // estate Trixy Park, LLC + "esurance", // esurance Esurance Insurance Company + "eurovision", // eurovision European Broadcasting Union (EBU) + "eus", // eus Puntueus Fundazioa + "events", // events Pioneer Maple, LLC + "everbank", // everbank EverBank + "exchange", // exchange Spring Falls, LLC + "expert", // expert Magic Pass, LLC + "exposed", // exposed Victor Beach, LLC + "express", // express Sea Sunset, LLC + "extraspace", // extraspace Extra Space Storage LLC + "fage", // fage Fage International S.A. + "fail", // fail Atomic Pipe, LLC + "fairwinds", // fairwinds FairWinds Partners, LLC + "faith", // faith dot Faith Limited + "family", // family United TLD Holdco Ltd. + "fan", // fan Asiamix Digital Ltd + "fans", // fans Asiamix Digital Limited + "farm", // farm Just Maple, LLC + "farmers", // farmers Farmers Insurance Exchange + "fashion", // fashion Top Level Domain Holdings Limited + "fast", // fast Amazon Registry Services, Inc. + "fedex", // fedex Federal Express Corporation + "feedback", // feedback Top Level Spectrum, Inc. + "ferrari", // ferrari Fiat Chrysler Automobiles N.V. + "ferrero", // ferrero Ferrero Trading Lux S.A. + "fiat", // fiat Fiat Chrysler Automobiles N.V. + "fidelity", // fidelity Fidelity Brokerage Services LLC + "fido", // fido Rogers Communications Canada Inc. + "film", // film Motion Picture Domain Registry Pty Ltd + "final", // final Núcleo de Informação e Coordenação do Ponto BR - NIC.br + "finance", // finance Cotton Cypress, LLC + "financial", // financial Just Cover, LLC + "fire", // fire Amazon Registry Services, Inc. + "firestone", // firestone Bridgestone Corporation + "firmdale", // firmdale Firmdale Holdings Limited + "fish", // fish Fox Woods, LLC + "fishing", // fishing Top Level Domain Holdings Limited + "fit", // fit Minds + Machines Group Limited + "fitness", // fitness Brice Orchard, LLC + "flickr", // flickr Yahoo! Domain Services Inc. + "flights", // flights Fox Station, LLC + "flir", // flir FLIR Systems, Inc. + "florist", // florist Half Cypress, LLC + "flowers", // flowers Uniregistry, Corp. +// "flsmidth", // flsmidth FLSmidth A/S retired 2016-07-22 + "fly", // fly Charleston Road Registry Inc. + "foo", // foo Charleston Road Registry Inc. + "food", // food Lifestyle Domain Holdings, Inc. + "foodnetwork", // foodnetwork Lifestyle Domain Holdings, Inc. + "football", // football Foggy Farms, LLC + "ford", // ford Ford Motor Company + "forex", // forex DOTFOREX REGISTRY LTD + "forsale", // forsale United TLD Holdco, LLC + "forum", // forum Fegistry, LLC + "foundation", // foundation John Dale, LLC + "fox", // fox FOX Registry, LLC + "free", // free Amazon Registry Services, Inc. + "fresenius", // fresenius Fresenius Immobilien-Verwaltungs-GmbH + "frl", // frl FRLregistry B.V. + "frogans", // frogans OP3FT + "frontdoor", // frontdoor Lifestyle Domain Holdings, Inc. + "frontier", // frontier Frontier Communications Corporation + "ftr", // ftr Frontier Communications Corporation + "fujitsu", // fujitsu Fujitsu Limited + "fujixerox", // fujixerox Xerox DNHC LLC + "fun", // fun DotSpace, Inc. + "fund", // fund John Castle, LLC + "furniture", // furniture Lone Fields, LLC + "futbol", // futbol United TLD Holdco, Ltd. + "fyi", // fyi Silver Tigers, LLC + "gal", // gal Asociación puntoGAL + "gallery", // gallery Sugar House, LLC + "gallo", // gallo Gallo Vineyards, Inc. + "gallup", // gallup Gallup, Inc. + "game", // game Uniregistry, Corp. + "games", // games United TLD Holdco Ltd. + "gap", // gap The Gap, Inc. + "garden", // garden Top Level Domain Holdings Limited + "gbiz", // gbiz Charleston Road Registry Inc. + "gdn", // gdn Joint Stock Company "Navigation-information systems" + "gea", // gea GEA Group Aktiengesellschaft + "gent", // gent COMBELL GROUP NV/SA + "genting", // genting Resorts World Inc. Pte. Ltd. + "george", // george Wal-Mart Stores, Inc. + "ggee", // ggee GMO Internet, Inc. + "gift", // gift Uniregistry, Corp. + "gifts", // gifts Goose Sky, LLC + "gives", // gives United TLD Holdco Ltd. + "giving", // giving Giving Limited + "glade", // glade Johnson Shareholdings, Inc. + "glass", // glass Black Cover, LLC + "gle", // gle Charleston Road Registry Inc. + "global", // global Dot Global Domain Registry Limited + "globo", // globo Globo Comunicação e Participações S.A + "gmail", // gmail Charleston Road Registry Inc. + "gmbh", // gmbh Extra Dynamite, LLC + "gmo", // gmo GMO Internet, Inc. + "gmx", // gmx 1&1 Mail & Media GmbH + "godaddy", // godaddy Go Daddy East, LLC + "gold", // gold June Edge, LLC + "goldpoint", // goldpoint YODOBASHI CAMERA CO.,LTD. + "golf", // golf Lone Falls, LLC + "goo", // goo NTT Resonant Inc. + "goodhands", // goodhands Allstate Fire and Casualty Insurance Company + "goodyear", // goodyear The Goodyear Tire & Rubber Company + "goog", // goog Charleston Road Registry Inc. + "google", // google Charleston Road Registry Inc. + "gop", // gop Republican State Leadership Committee, Inc. + "got", // got Amazon Registry Services, Inc. + "gov", // gov General Services Administration Attn: QTDC, 2E08 (.gov Domain Registration) + "grainger", // grainger Grainger Registry Services, LLC + "graphics", // graphics Over Madison, LLC + "gratis", // gratis Pioneer Tigers, LLC + "green", // green Afilias Limited + "gripe", // gripe Corn Sunset, LLC + "group", // group Romeo Town, LLC + "guardian", // guardian The Guardian Life Insurance Company of America + "gucci", // gucci Guccio Gucci S.p.a. + "guge", // guge Charleston Road Registry Inc. + "guide", // guide Snow Moon, LLC + "guitars", // guitars Uniregistry, Corp. + "guru", // guru Pioneer Cypress, LLC + "hair", // hair L'Oreal + "hamburg", // hamburg Hamburg Top-Level-Domain GmbH + "hangout", // hangout Charleston Road Registry Inc. + "haus", // haus United TLD Holdco, LTD. + "hbo", // hbo HBO Registry Services, Inc. + "hdfc", // hdfc HOUSING DEVELOPMENT FINANCE CORPORATION LIMITED + "hdfcbank", // hdfcbank HDFC Bank Limited + "health", // health DotHealth, LLC + "healthcare", // healthcare Silver Glen, LLC + "help", // help Uniregistry, Corp. + "helsinki", // helsinki City of Helsinki + "here", // here Charleston Road Registry Inc. + "hermes", // hermes Hermes International + "hgtv", // hgtv Lifestyle Domain Holdings, Inc. + "hiphop", // hiphop Uniregistry, Corp. + "hisamitsu", // hisamitsu Hisamitsu Pharmaceutical Co.,Inc. + "hitachi", // hitachi Hitachi, Ltd. + "hiv", // hiv dotHIV gemeinnuetziger e.V. + "hkt", // hkt PCCW-HKT DataCom Services Limited + "hockey", // hockey Half Willow, LLC + "holdings", // holdings John Madison, LLC + "holiday", // holiday Goose Woods, LLC + "homedepot", // homedepot Homer TLC, Inc. + "homegoods", // homegoods The TJX Companies, Inc. + "homes", // homes DERHomes, LLC + "homesense", // homesense The TJX Companies, Inc. + "honda", // honda Honda Motor Co., Ltd. + "honeywell", // honeywell Honeywell GTLD LLC + "horse", // horse Top Level Domain Holdings Limited + "hospital", // hospital Ruby Pike, LLC + "host", // host DotHost Inc. + "hosting", // hosting Uniregistry, Corp. + "hot", // hot Amazon Registry Services, Inc. + "hoteles", // hoteles Travel Reservations SRL + "hotmail", // hotmail Microsoft Corporation + "house", // house Sugar Park, LLC + "how", // how Charleston Road Registry Inc. + "hsbc", // hsbc HSBC Holdings PLC + "htc", // htc HTC corporation + "hughes", // hughes Hughes Satellite Systems Corporation + "hyatt", // hyatt Hyatt GTLD, L.L.C. + "hyundai", // hyundai Hyundai Motor Company + "ibm", // ibm International Business Machines Corporation + "icbc", // icbc Industrial and Commercial Bank of China Limited + "ice", // ice IntercontinentalExchange, Inc. + "icu", // icu One.com A/S + "ieee", // ieee IEEE Global LLC + "ifm", // ifm ifm electronic gmbh +// "iinet", // iinet Connect West Pty. Ltd. (Retired) + "ikano", // ikano Ikano S.A. + "imamat", // imamat Fondation Aga Khan (Aga Khan Foundation) + "imdb", // imdb Amazon Registry Services, Inc. + "immo", // immo Auburn Bloom, LLC + "immobilien", // immobilien United TLD Holdco Ltd. + "industries", // industries Outer House, LLC + "infiniti", // infiniti NISSAN MOTOR CO., LTD. + "info", // info Afilias Limited + "ing", // ing Charleston Road Registry Inc. + "ink", // ink Top Level Design, LLC + "institute", // institute Outer Maple, LLC + "insurance", // insurance fTLD Registry Services LLC + "insure", // insure Pioneer Willow, LLC + "int", // int Internet Assigned Numbers Authority + "intel", // intel Intel Corporation + "international", // international Wild Way, LLC + "intuit", // intuit Intuit Administrative Services, Inc. + "investments", // investments Holly Glen, LLC + "ipiranga", // ipiranga Ipiranga Produtos de Petroleo S.A. + "irish", // irish Dot-Irish LLC + "iselect", // iselect iSelect Ltd + "ismaili", // ismaili Fondation Aga Khan (Aga Khan Foundation) + "ist", // ist Istanbul Metropolitan Municipality + "istanbul", // istanbul Istanbul Metropolitan Municipality / Medya A.S. + "itau", // itau Itau Unibanco Holding S.A. + "itv", // itv ITV Services Limited + "iveco", // iveco CNH Industrial N.V. + "iwc", // iwc Richemont DNS Inc. + "jaguar", // jaguar Jaguar Land Rover Ltd + "java", // java Oracle Corporation + "jcb", // jcb JCB Co., Ltd. + "jcp", // jcp JCP Media, Inc. + "jeep", // jeep FCA US LLC. + "jetzt", // jetzt New TLD Company AB + "jewelry", // jewelry Wild Bloom, LLC + "jio", // jio Affinity Names, Inc. + "jlc", // jlc Richemont DNS Inc. + "jll", // jll Jones Lang LaSalle Incorporated + "jmp", // jmp Matrix IP LLC + "jnj", // jnj Johnson & Johnson Services, Inc. + "jobs", // jobs Employ Media LLC + "joburg", // joburg ZA Central Registry NPC trading as ZA Central Registry + "jot", // jot Amazon Registry Services, Inc. + "joy", // joy Amazon Registry Services, Inc. + "jpmorgan", // jpmorgan JPMorgan Chase & Co. + "jprs", // jprs Japan Registry Services Co., Ltd. + "juegos", // juegos Uniregistry, Corp. + "juniper", // juniper JUNIPER NETWORKS, INC. + "kaufen", // kaufen United TLD Holdco Ltd. + "kddi", // kddi KDDI CORPORATION + "kerryhotels", // kerryhotels Kerry Trading Co. Limited + "kerrylogistics", // kerrylogistics Kerry Trading Co. Limited + "kerryproperties", // kerryproperties Kerry Trading Co. Limited + "kfh", // kfh Kuwait Finance House + "kia", // kia KIA MOTORS CORPORATION + "kim", // kim Afilias Limited + "kinder", // kinder Ferrero Trading Lux S.A. + "kindle", // kindle Amazon Registry Services, Inc. + "kitchen", // kitchen Just Goodbye, LLC + "kiwi", // kiwi DOT KIWI LIMITED + "koeln", // koeln NetCologne Gesellschaft für Telekommunikation mbH + "komatsu", // komatsu Komatsu Ltd. + "kosher", // kosher Kosher Marketing Assets LLC + "kpmg", // kpmg KPMG International Cooperative (KPMG International Genossenschaft) + "kpn", // kpn Koninklijke KPN N.V. + "krd", // krd KRG Department of Information Technology + "kred", // kred KredTLD Pty Ltd + "kuokgroup", // kuokgroup Kerry Trading Co. Limited + "kyoto", // kyoto Academic Institution: Kyoto Jyoho Gakuen + "lacaixa", // lacaixa CAIXA D'ESTALVIS I PENSIONS DE BARCELONA + "ladbrokes", // ladbrokes LADBROKES INTERNATIONAL PLC + "lamborghini", // lamborghini Automobili Lamborghini S.p.A. + "lamer", // lamer The Estée Lauder Companies Inc. + "lancaster", // lancaster LANCASTER + "lancia", // lancia Fiat Chrysler Automobiles N.V. + "lancome", // lancome L'Oréal + "land", // land Pine Moon, LLC + "landrover", // landrover Jaguar Land Rover Ltd + "lanxess", // lanxess LANXESS Corporation + "lasalle", // lasalle Jones Lang LaSalle Incorporated + "lat", // lat ECOM-LAC Federación de Latinoamérica y el Caribe para Internet y el Comercio Electrónico + "latino", // latino Dish DBS Corporation + "latrobe", // latrobe La Trobe University + "law", // law Minds + Machines Group Limited + "lawyer", // lawyer United TLD Holdco, Ltd + "lds", // lds IRI Domain Management, LLC + "lease", // lease Victor Trail, LLC + "leclerc", // leclerc A.C.D. LEC Association des Centres Distributeurs Edouard Leclerc + "lefrak", // lefrak LeFrak Organization, Inc. + "legal", // legal Blue Falls, LLC + "lego", // lego LEGO Juris A/S + "lexus", // lexus TOYOTA MOTOR CORPORATION + "lgbt", // lgbt Afilias Limited + "liaison", // liaison Liaison Technologies, Incorporated + "lidl", // lidl Schwarz Domains und Services GmbH & Co. KG + "life", // life Trixy Oaks, LLC + "lifeinsurance", // lifeinsurance American Council of Life Insurers + "lifestyle", // lifestyle Lifestyle Domain Holdings, Inc. + "lighting", // lighting John McCook, LLC + "like", // like Amazon Registry Services, Inc. + "lilly", // lilly Eli Lilly and Company + "limited", // limited Big Fest, LLC + "limo", // limo Hidden Frostbite, LLC + "lincoln", // lincoln Ford Motor Company + "linde", // linde Linde Aktiengesellschaft + "link", // link Uniregistry, Corp. + "lipsy", // lipsy Lipsy Ltd + "live", // live United TLD Holdco Ltd. + "living", // living Lifestyle Domain Holdings, Inc. + "lixil", // lixil LIXIL Group Corporation + "loan", // loan dot Loan Limited + "loans", // loans June Woods, LLC + "locker", // locker Dish DBS Corporation + "locus", // locus Locus Analytics LLC + "loft", // loft Annco, Inc. + "lol", // lol Uniregistry, Corp. + "london", // london Dot London Domains Limited + "lotte", // lotte Lotte Holdings Co., Ltd. + "lotto", // lotto Afilias Limited + "love", // love Merchant Law Group LLP + "lpl", // lpl LPL Holdings, Inc. + "lplfinancial", // lplfinancial LPL Holdings, Inc. + "ltd", // ltd Over Corner, LLC + "ltda", // ltda InterNetX Corp. + "lundbeck", // lundbeck H. Lundbeck A/S + "lupin", // lupin LUPIN LIMITED + "luxe", // luxe Top Level Domain Holdings Limited + "luxury", // luxury Luxury Partners LLC + "macys", // macys Macys, Inc. + "madrid", // madrid Comunidad de Madrid + "maif", // maif Mutuelle Assurance Instituteur France (MAIF) + "maison", // maison Victor Frostbite, LLC + "makeup", // makeup L'Oréal + "man", // man MAN SE + "management", // management John Goodbye, LLC + "mango", // mango PUNTO FA S.L. + "market", // market Unitied TLD Holdco, Ltd + "marketing", // marketing Fern Pass, LLC + "markets", // markets DOTMARKETS REGISTRY LTD + "marriott", // marriott Marriott Worldwide Corporation + "marshalls", // marshalls The TJX Companies, Inc. + "maserati", // maserati Fiat Chrysler Automobiles N.V. + "mattel", // mattel Mattel Sites, Inc. + "mba", // mba Lone Hollow, LLC + "mcd", // mcd McDonald’s Corporation + "mcdonalds", // mcdonalds McDonald’s Corporation + "mckinsey", // mckinsey McKinsey Holdings, Inc. + "med", // med Medistry LLC + "media", // media Grand Glen, LLC + "meet", // meet Afilias Limited + "melbourne", // melbourne The Crown in right of the State of Victoria, represented by its Department of State Development, Business and Innovation + "meme", // meme Charleston Road Registry Inc. + "memorial", // memorial Dog Beach, LLC + "men", // men Exclusive Registry Limited + "menu", // menu Wedding TLD2, LLC + "meo", // meo PT Comunicacoes S.A. + "metlife", // metlife MetLife Services and Solutions, LLC + "miami", // miami Top Level Domain Holdings Limited + "microsoft", // microsoft Microsoft Corporation + "mil", // mil DoD Network Information Center + "mini", // mini Bayerische Motoren Werke Aktiengesellschaft + "mint", // mint Intuit Administrative Services, Inc. + "mit", // mit Massachusetts Institute of Technology + "mitsubishi", // mitsubishi Mitsubishi Corporation + "mlb", // mlb MLB Advanced Media DH, LLC + "mls", // mls The Canadian Real Estate Association + "mma", // mma MMA IARD + "mobi", // mobi Afilias Technologies Limited dba dotMobi + "mobile", // mobile Dish DBS Corporation + "mobily", // mobily GreenTech Consultancy Company W.L.L. + "moda", // moda United TLD Holdco Ltd. + "moe", // moe Interlink Co., Ltd. + "moi", // moi Amazon Registry Services, Inc. + "mom", // mom Uniregistry, Corp. + "monash", // monash Monash University + "money", // money Outer McCook, LLC + "monster", // monster Monster Worldwide, Inc. + "montblanc", // montblanc Richemont DNS Inc. + "mopar", // mopar FCA US LLC. + "mormon", // mormon IRI Domain Management, LLC ("Applicant") + "mortgage", // mortgage United TLD Holdco, Ltd + "moscow", // moscow Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID) + "moto", // moto Motorola Trademark Holdings, LLC + "motorcycles", // motorcycles DERMotorcycles, LLC + "mov", // mov Charleston Road Registry Inc. + "movie", // movie New Frostbite, LLC + "movistar", // movistar Telefónica S.A. + "msd", // msd MSD Registry Holdings, Inc. + "mtn", // mtn MTN Dubai Limited + "mtpc", // mtpc Mitsubishi Tanabe Pharma Corporation + "mtr", // mtr MTR Corporation Limited + "museum", // museum Museum Domain Management Association + "mutual", // mutual Northwestern Mutual MU TLD Registry, LLC +// "mutuelle", // mutuelle Fédération Nationale de la Mutualité Française (Retired) + "nab", // nab National Australia Bank Limited + "nadex", // nadex Nadex Domains, Inc + "nagoya", // nagoya GMO Registry, Inc. + "name", // name VeriSign Information Services, Inc. + "nationwide", // nationwide Nationwide Mutual Insurance Company + "natura", // natura NATURA COSMÉTICOS S.A. + "navy", // navy United TLD Holdco Ltd. + "nba", // nba NBA REGISTRY, LLC + "nec", // nec NEC Corporation + "net", // net VeriSign Global Registry Services + "netbank", // netbank COMMONWEALTH BANK OF AUSTRALIA + "netflix", // netflix Netflix, Inc. + "network", // network Trixy Manor, LLC + "neustar", // neustar NeuStar, Inc. + "new", // new Charleston Road Registry Inc. + "newholland", // newholland CNH Industrial N.V. + "news", // news United TLD Holdco Ltd. + "next", // next Next plc + "nextdirect", // nextdirect Next plc + "nexus", // nexus Charleston Road Registry Inc. + "nfl", // nfl NFL Reg Ops LLC + "ngo", // ngo Public Interest Registry + "nhk", // nhk Japan Broadcasting Corporation (NHK) + "nico", // nico DWANGO Co., Ltd. + "nike", // nike NIKE, Inc. + "nikon", // nikon NIKON CORPORATION + "ninja", // ninja United TLD Holdco Ltd. + "nissan", // nissan NISSAN MOTOR CO., LTD. + "nissay", // nissay Nippon Life Insurance Company + "nokia", // nokia Nokia Corporation + "northwesternmutual", // northwesternmutual Northwestern Mutual Registry, LLC + "norton", // norton Symantec Corporation + "now", // now Amazon Registry Services, Inc. + "nowruz", // nowruz Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. + "nowtv", // nowtv Starbucks (HK) Limited + "nra", // nra NRA Holdings Company, INC. + "nrw", // nrw Minds + Machines GmbH + "ntt", // ntt NIPPON TELEGRAPH AND TELEPHONE CORPORATION + "nyc", // nyc The City of New York by and through the New York City Department of Information Technology & Telecommunications + "obi", // obi OBI Group Holding SE & Co. KGaA + "observer", // observer Top Level Spectrum, Inc. + "off", // off Johnson Shareholdings, Inc. + "office", // office Microsoft Corporation + "okinawa", // okinawa BusinessRalliart inc. + "olayan", // olayan Crescent Holding GmbH + "olayangroup", // olayangroup Crescent Holding GmbH + "oldnavy", // oldnavy The Gap, Inc. + "ollo", // ollo Dish DBS Corporation + "omega", // omega The Swatch Group Ltd + "one", // one One.com A/S + "ong", // ong Public Interest Registry + "onl", // onl I-REGISTRY Ltd., Niederlassung Deutschland + "online", // online DotOnline Inc. + "onyourside", // onyourside Nationwide Mutual Insurance Company + "ooo", // ooo INFIBEAM INCORPORATION LIMITED + "open", // open American Express Travel Related Services Company, Inc. + "oracle", // oracle Oracle Corporation + "orange", // orange Orange Brand Services Limited + "org", // org Public Interest Registry (PIR) + "organic", // organic Afilias Limited + "orientexpress", // orientexpress Orient Express + "origins", // origins The Estée Lauder Companies Inc. + "osaka", // osaka Interlink Co., Ltd. + "otsuka", // otsuka Otsuka Holdings Co., Ltd. + "ott", // ott Dish DBS Corporation + "ovh", // ovh OVH SAS + "page", // page Charleston Road Registry Inc. + "pamperedchef", // pamperedchef The Pampered Chef, Ltd. + "panasonic", // panasonic Panasonic Corporation + "panerai", // panerai Richemont DNS Inc. + "paris", // paris City of Paris + "pars", // pars Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. + "partners", // partners Magic Glen, LLC + "parts", // parts Sea Goodbye, LLC + "party", // party Blue Sky Registry Limited + "passagens", // passagens Travel Reservations SRL + "pay", // pay Amazon Registry Services, Inc. + "pccw", // pccw PCCW Enterprises Limited + "pet", // pet Afilias plc + "pfizer", // pfizer Pfizer Inc. + "pharmacy", // pharmacy National Association of Boards of Pharmacy + "philips", // philips Koninklijke Philips N.V. + "phone", // phone Dish DBS Corporation + "photo", // photo Uniregistry, Corp. + "photography", // photography Sugar Glen, LLC + "photos", // photos Sea Corner, LLC + "physio", // physio PhysBiz Pty Ltd + "piaget", // piaget Richemont DNS Inc. + "pics", // pics Uniregistry, Corp. + "pictet", // pictet Pictet Europe S.A. + "pictures", // pictures Foggy Sky, LLC + "pid", // pid Top Level Spectrum, Inc. + "pin", // pin Amazon Registry Services, Inc. + "ping", // ping Ping Registry Provider, Inc. + "pink", // pink Afilias Limited + "pioneer", // pioneer Pioneer Corporation + "pizza", // pizza Foggy Moon, LLC + "place", // place Snow Galley, LLC + "play", // play Charleston Road Registry Inc. + "playstation", // playstation Sony Computer Entertainment Inc. + "plumbing", // plumbing Spring Tigers, LLC + "plus", // plus Sugar Mill, LLC + "pnc", // pnc PNC Domain Co., LLC + "pohl", // pohl Deutsche Vermögensberatung Aktiengesellschaft DVAG + "poker", // poker Afilias Domains No. 5 Limited + "politie", // politie Politie Nederland + "porn", // porn ICM Registry PN LLC + "post", // post Universal Postal Union + "pramerica", // pramerica Prudential Financial, Inc. + "praxi", // praxi Praxi S.p.A. + "press", // press DotPress Inc. + "prime", // prime Amazon Registry Services, Inc. + "pro", // pro Registry Services Corporation dba RegistryPro + "prod", // prod Charleston Road Registry Inc. + "productions", // productions Magic Birch, LLC + "prof", // prof Charleston Road Registry Inc. + "progressive", // progressive Progressive Casualty Insurance Company + "promo", // promo Afilias plc + "properties", // properties Big Pass, LLC + "property", // property Uniregistry, Corp. + "protection", // protection XYZ.COM LLC + "pru", // pru Prudential Financial, Inc. + "prudential", // prudential Prudential Financial, Inc. + "pub", // pub United TLD Holdco Ltd. + "pwc", // pwc PricewaterhouseCoopers LLP + "qpon", // qpon dotCOOL, Inc. + "quebec", // quebec PointQuébec Inc + "quest", // quest Quest ION Limited + "qvc", // qvc QVC, Inc. + "racing", // racing Premier Registry Limited + "radio", // radio European Broadcasting Union (EBU) + "raid", // raid Johnson Shareholdings, Inc. + "read", // read Amazon Registry Services, Inc. + "realestate", // realestate dotRealEstate LLC + "realtor", // realtor Real Estate Domains LLC + "realty", // realty Fegistry, LLC + "recipes", // recipes Grand Island, LLC + "red", // red Afilias Limited + "redstone", // redstone Redstone Haute Couture Co., Ltd. + "redumbrella", // redumbrella Travelers TLD, LLC + "rehab", // rehab United TLD Holdco Ltd. + "reise", // reise Foggy Way, LLC + "reisen", // reisen New Cypress, LLC + "reit", // reit National Association of Real Estate Investment Trusts, Inc. + "reliance", // reliance Reliance Industries Limited + "ren", // ren Beijing Qianxiang Wangjing Technology Development Co., Ltd. + "rent", // rent XYZ.COM LLC + "rentals", // rentals Big Hollow,LLC + "repair", // repair Lone Sunset, LLC + "report", // report Binky Glen, LLC + "republican", // republican United TLD Holdco Ltd. + "rest", // rest Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable + "restaurant", // restaurant Snow Avenue, LLC + "review", // review dot Review Limited + "reviews", // reviews United TLD Holdco, Ltd. + "rexroth", // rexroth Robert Bosch GMBH + "rich", // rich I-REGISTRY Ltd., Niederlassung Deutschland + "richardli", // richardli Pacific Century Asset Management (HK) Limited + "ricoh", // ricoh Ricoh Company, Ltd. + "rightathome", // rightathome Johnson Shareholdings, Inc. + "ril", // ril Reliance Industries Limited + "rio", // rio Empresa Municipal de Informática SA - IPLANRIO + "rip", // rip United TLD Holdco Ltd. + "rmit", // rmit Royal Melbourne Institute of Technology + "rocher", // rocher Ferrero Trading Lux S.A. + "rocks", // rocks United TLD Holdco, LTD. + "rodeo", // rodeo Top Level Domain Holdings Limited + "rogers", // rogers Rogers Communications Canada Inc. + "room", // room Amazon Registry Services, Inc. + "rsvp", // rsvp Charleston Road Registry Inc. + "ruhr", // ruhr regiodot GmbH & Co. KG + "run", // run Snow Park, LLC + "rwe", // rwe RWE AG + "ryukyu", // ryukyu BusinessRalliart inc. + "saarland", // saarland dotSaarland GmbH + "safe", // safe Amazon Registry Services, Inc. + "safety", // safety Safety Registry Services, LLC. + "sakura", // sakura SAKURA Internet Inc. + "sale", // sale United TLD Holdco, Ltd + "salon", // salon Outer Orchard, LLC + "samsclub", // samsclub Wal-Mart Stores, Inc. + "samsung", // samsung SAMSUNG SDS CO., LTD + "sandvik", // sandvik Sandvik AB + "sandvikcoromant", // sandvikcoromant Sandvik AB + "sanofi", // sanofi Sanofi + "sap", // sap SAP AG + "sapo", // sapo PT Comunicacoes S.A. + "sarl", // sarl Delta Orchard, LLC + "sas", // sas Research IP LLC + "save", // save Amazon Registry Services, Inc. + "saxo", // saxo Saxo Bank A/S + "sbi", // sbi STATE BANK OF INDIA + "sbs", // sbs SPECIAL BROADCASTING SERVICE CORPORATION + "sca", // sca SVENSKA CELLULOSA AKTIEBOLAGET SCA (publ) + "scb", // scb The Siam Commercial Bank Public Company Limited ("SCB") + "schaeffler", // schaeffler Schaeffler Technologies AG & Co. KG + "schmidt", // schmidt SALM S.A.S. + "scholarships", // scholarships Scholarships.com, LLC + "school", // school Little Galley, LLC + "schule", // schule Outer Moon, LLC + "schwarz", // schwarz Schwarz Domains und Services GmbH & Co. KG + "science", // science dot Science Limited + "scjohnson", // scjohnson Johnson Shareholdings, Inc. + "scor", // scor SCOR SE + "scot", // scot Dot Scot Registry Limited + "seat", // seat SEAT, S.A. (Sociedad Unipersonal) + "secure", // secure Amazon Registry Services, Inc. + "security", // security XYZ.COM LLC + "seek", // seek Seek Limited + "select", // select iSelect Ltd + "sener", // sener Sener Ingeniería y Sistemas, S.A. + "services", // services Fox Castle, LLC + "ses", // ses SES + "seven", // seven Seven West Media Ltd + "sew", // sew SEW-EURODRIVE GmbH & Co KG + "sex", // sex ICM Registry SX LLC + "sexy", // sexy Uniregistry, Corp. + "sfr", // sfr Societe Francaise du Radiotelephone - SFR + "shangrila", // shangrila Shangri‐La International Hotel Management Limited + "sharp", // sharp Sharp Corporation + "shaw", // shaw Shaw Cablesystems G.P. + "shell", // shell Shell Information Technology International Inc + "shia", // shia Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. + "shiksha", // shiksha Afilias Limited + "shoes", // shoes Binky Galley, LLC + "shop", // shop GMO Registry, Inc. + "shopping", // shopping Over Keep, LLC + "shouji", // shouji QIHOO 360 TECHNOLOGY CO. LTD. + "show", // show Snow Beach, LLC + "showtime", // showtime CBS Domains Inc. + "shriram", // shriram Shriram Capital Ltd. + "silk", // silk Amazon Registry Services, Inc. + "sina", // sina Sina Corporation + "singles", // singles Fern Madison, LLC + "site", // site DotSite Inc. + "ski", // ski STARTING DOT LIMITED + "skin", // skin L'Oréal + "sky", // sky Sky International AG + "skype", // skype Microsoft Corporation + "sling", // sling Hughes Satellite Systems Corporation + "smart", // smart Smart Communications, Inc. (SMART) + "smile", // smile Amazon Registry Services, Inc. + "sncf", // sncf SNCF (Société Nationale des Chemins de fer Francais) + "soccer", // soccer Foggy Shadow, LLC + "social", // social United TLD Holdco Ltd. + "softbank", // softbank SoftBank Group Corp. + "software", // software United TLD Holdco, Ltd + "sohu", // sohu Sohu.com Limited + "solar", // solar Ruby Town, LLC + "solutions", // solutions Silver Cover, LLC + "song", // song Amazon Registry Services, Inc. + "sony", // sony Sony Corporation + "soy", // soy Charleston Road Registry Inc. + "space", // space DotSpace Inc. + "spiegel", // spiegel SPIEGEL-Verlag Rudolf Augstein GmbH & Co. KG + "spot", // spot Amazon Registry Services, Inc. + "spreadbetting", // spreadbetting DOTSPREADBETTING REGISTRY LTD + "srl", // srl InterNetX Corp. + "srt", // srt FCA US LLC. + "stada", // stada STADA Arzneimittel AG + "staples", // staples Staples, Inc. + "star", // star Star India Private Limited + "starhub", // starhub StarHub Limited + "statebank", // statebank STATE BANK OF INDIA + "statefarm", // statefarm State Farm Mutual Automobile Insurance Company + "statoil", // statoil Statoil ASA + "stc", // stc Saudi Telecom Company + "stcgroup", // stcgroup Saudi Telecom Company + "stockholm", // stockholm Stockholms kommun + "storage", // storage Self Storage Company LLC + "store", // store DotStore Inc. + "stream", // stream dot Stream Limited + "studio", // studio United TLD Holdco Ltd. + "study", // study OPEN UNIVERSITIES AUSTRALIA PTY LTD + "style", // style Binky Moon, LLC + "sucks", // sucks Vox Populi Registry Ltd. + "supplies", // supplies Atomic Fields, LLC + "supply", // supply Half Falls, LLC + "support", // support Grand Orchard, LLC + "surf", // surf Top Level Domain Holdings Limited + "surgery", // surgery Tin Avenue, LLC + "suzuki", // suzuki SUZUKI MOTOR CORPORATION + "swatch", // swatch The Swatch Group Ltd + "swiftcover", // swiftcover Swiftcover Insurance Services Limited + "swiss", // swiss Swiss Confederation + "sydney", // sydney State of New South Wales, Department of Premier and Cabinet + "symantec", // symantec Symantec Corporation + "systems", // systems Dash Cypress, LLC + "tab", // tab Tabcorp Holdings Limited + "taipei", // taipei Taipei City Government + "talk", // talk Amazon Registry Services, Inc. + "taobao", // taobao Alibaba Group Holding Limited + "target", // target Target Domain Holdings, LLC + "tatamotors", // tatamotors Tata Motors Ltd + "tatar", // tatar Limited Liability Company "Coordination Center of Regional Domain of Tatarstan Republic" + "tattoo", // tattoo Uniregistry, Corp. + "tax", // tax Storm Orchard, LLC + "taxi", // taxi Pine Falls, LLC + "tci", // tci Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. + "tdk", // tdk TDK Corporation + "team", // team Atomic Lake, LLC + "tech", // tech Dot Tech LLC + "technology", // technology Auburn Falls, LLC + "tel", // tel Telnic Ltd. + "telecity", // telecity TelecityGroup International Limited + "telefonica", // telefonica Telefónica S.A. + "temasek", // temasek Temasek Holdings (Private) Limited + "tennis", // tennis Cotton Bloom, LLC + "teva", // teva Teva Pharmaceutical Industries Limited + "thd", // thd Homer TLC, Inc. + "theater", // theater Blue Tigers, LLC + "theatre", // theatre XYZ.COM LLC + "tiaa", // tiaa Teachers Insurance and Annuity Association of America + "tickets", // tickets Accent Media Limited + "tienda", // tienda Victor Manor, LLC + "tiffany", // tiffany Tiffany and Company + "tips", // tips Corn Willow, LLC + "tires", // tires Dog Edge, LLC + "tirol", // tirol punkt Tirol GmbH + "tjmaxx", // tjmaxx The TJX Companies, Inc. + "tjx", // tjx The TJX Companies, Inc. + "tkmaxx", // tkmaxx The TJX Companies, Inc. + "tmall", // tmall Alibaba Group Holding Limited + "today", // today Pearl Woods, LLC + "tokyo", // tokyo GMO Registry, Inc. + "tools", // tools Pioneer North, LLC + "top", // top Jiangsu Bangning Science & Technology Co.,Ltd. + "toray", // toray Toray Industries, Inc. + "toshiba", // toshiba TOSHIBA Corporation + "total", // total Total SA + "tours", // tours Sugar Station, LLC + "town", // town Koko Moon, LLC + "toyota", // toyota TOYOTA MOTOR CORPORATION + "toys", // toys Pioneer Orchard, LLC + "trade", // trade Elite Registry Limited + "trading", // trading DOTTRADING REGISTRY LTD + "training", // training Wild Willow, LLC + "travel", // travel Tralliance Registry Management Company, LLC. + "travelchannel", // travelchannel Lifestyle Domain Holdings, Inc. + "travelers", // travelers Travelers TLD, LLC + "travelersinsurance", // travelersinsurance Travelers TLD, LLC + "trust", // trust Artemis Internet Inc + "trv", // trv Travelers TLD, LLC + "tube", // tube Latin American Telecom LLC + "tui", // tui TUI AG + "tunes", // tunes Amazon Registry Services, Inc. + "tushu", // tushu Amazon Registry Services, Inc. + "tvs", // tvs T V SUNDRAM IYENGAR & SONS PRIVATE LIMITED + "ubank", // ubank National Australia Bank Limited + "ubs", // ubs UBS AG + "uconnect", // uconnect FCA US LLC. + "unicom", // unicom China United Network Communications Corporation Limited + "university", // university Little Station, LLC + "uno", // uno Dot Latin LLC + "uol", // uol UBN INTERNET LTDA. + "ups", // ups UPS Market Driver, Inc. + "vacations", // vacations Atomic Tigers, LLC + "vana", // vana Lifestyle Domain Holdings, Inc. + "vanguard", // vanguard The Vanguard Group, Inc. + "vegas", // vegas Dot Vegas, Inc. + "ventures", // ventures Binky Lake, LLC + "verisign", // verisign VeriSign, Inc. + "versicherung", // versicherung dotversicherung-registry GmbH + "vet", // vet United TLD Holdco, Ltd + "viajes", // viajes Black Madison, LLC + "video", // video United TLD Holdco, Ltd + "vig", // vig VIENNA INSURANCE GROUP AG Wiener Versicherung Gruppe + "viking", // viking Viking River Cruises (Bermuda) Ltd. + "villas", // villas New Sky, LLC + "vin", // vin Holly Shadow, LLC + "vip", // vip Minds + Machines Group Limited + "virgin", // virgin Virgin Enterprises Limited + "visa", // visa Visa Worldwide Pte. Limited + "vision", // vision Koko Station, LLC + "vista", // vista Vistaprint Limited + "vistaprint", // vistaprint Vistaprint Limited + "viva", // viva Saudi Telecom Company + "vivo", // vivo Telefonica Brasil S.A. + "vlaanderen", // vlaanderen DNS.be vzw + "vodka", // vodka Top Level Domain Holdings Limited + "volkswagen", // volkswagen Volkswagen Group of America Inc. + "volvo", // volvo Volvo Holding Sverige Aktiebolag + "vote", // vote Monolith Registry LLC + "voting", // voting Valuetainment Corp. + "voto", // voto Monolith Registry LLC + "voyage", // voyage Ruby House, LLC + "vuelos", // vuelos Travel Reservations SRL + "wales", // wales Nominet UK + "walmart", // walmart Wal-Mart Stores, Inc. + "walter", // walter Sandvik AB + "wang", // wang Zodiac Registry Limited + "wanggou", // wanggou Amazon Registry Services, Inc. + "warman", // warman Weir Group IP Limited + "watch", // watch Sand Shadow, LLC + "watches", // watches Richemont DNS Inc. + "weather", // weather The Weather Channel, LLC + "weatherchannel", // weatherchannel The Weather Channel, LLC + "webcam", // webcam dot Webcam Limited + "weber", // weber Saint-Gobain Weber SA + "website", // website DotWebsite Inc. + "wed", // wed Atgron, Inc. + "wedding", // wedding Top Level Domain Holdings Limited + "weibo", // weibo Sina Corporation + "weir", // weir Weir Group IP Limited + "whoswho", // whoswho Who's Who Registry + "wien", // wien punkt.wien GmbH + "wiki", // wiki Top Level Design, LLC + "williamhill", // williamhill William Hill Organization Limited + "win", // win First Registry Limited + "windows", // windows Microsoft Corporation + "wine", // wine June Station, LLC + "winners", // winners The TJX Companies, Inc. + "wme", // wme William Morris Endeavor Entertainment, LLC + "wolterskluwer", // wolterskluwer Wolters Kluwer N.V. + "woodside", // woodside Woodside Petroleum Limited + "work", // work Top Level Domain Holdings Limited + "works", // works Little Dynamite, LLC + "world", // world Bitter Fields, LLC + "wow", // wow Amazon Registry Services, Inc. + "wtc", // wtc World Trade Centers Association, Inc. + "wtf", // wtf Hidden Way, LLC + "xbox", // xbox Microsoft Corporation + "xerox", // xerox Xerox DNHC LLC + "xfinity", // xfinity Comcast IP Holdings I, LLC + "xihuan", // xihuan QIHOO 360 TECHNOLOGY CO. LTD. + "xin", // xin Elegant Leader Limited + "xn--11b4c3d", // कॉम VeriSign Sarl + "xn--1ck2e1b", // セール Amazon Registry Services, Inc. + "xn--1qqw23a", // 佛山 Guangzhou YU Wei Information Technology Co., Ltd. + "xn--30rr7y", // 慈善 Excellent First Limited + "xn--3bst00m", // 集团 Eagle Horizon Limited + "xn--3ds443g", // 在线 TLD REGISTRY LIMITED + "xn--3oq18vl8pn36a", // 大众汽车 Volkswagen (China) Investment Co., Ltd. + "xn--3pxu8k", // 点看 VeriSign Sarl + "xn--42c2d9a", // คอม VeriSign Sarl + "xn--45q11c", // 八卦 Zodiac Scorpio Limited + "xn--4gbrim", // موقع Suhub Electronic Establishment + "xn--55qw42g", // 公益 China Organizational Name Administration Center + "xn--55qx5d", // 公司 Computer Network Information Center of Chinese Academy of Sciences (China Internet Network Information Center) + "xn--5su34j936bgsg", // 香格里拉 Shangri‐La International Hotel Management Limited + "xn--5tzm5g", // 网站 Global Website TLD Asia Limited + "xn--6frz82g", // 移动 Afilias Limited + "xn--6qq986b3xl", // 我爱你 Tycoon Treasure Limited + "xn--80adxhks", // москва Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID) + "xn--80aqecdr1a", // католик Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) + "xn--80asehdb", // онлайн CORE Association + "xn--80aswg", // сайт CORE Association + "xn--8y0a063a", // 联通 China United Network Communications Corporation Limited + "xn--90ae", // бг Imena.BG Plc (NAMES.BG Plc) + "xn--9dbq2a", // קום VeriSign Sarl + "xn--9et52u", // 时尚 RISE VICTORY LIMITED + "xn--9krt00a", // 微博 Sina Corporation + "xn--b4w605ferd", // 淡马锡 Temasek Holdings (Private) Limited + "xn--bck1b9a5dre4c", // ファッション Amazon Registry Services, Inc. + "xn--c1avg", // орг Public Interest Registry + "xn--c2br7g", // नेट VeriSign Sarl + "xn--cck2b3b", // ストア Amazon Registry Services, Inc. + "xn--cg4bki", // 삼성 SAMSUNG SDS CO., LTD + "xn--czr694b", // 商标 HU YI GLOBAL INFORMATION RESOURCES(HOLDING) COMPANY.HONGKONG LIMITED + "xn--czrs0t", // 商店 Wild Island, LLC + "xn--czru2d", // 商城 Zodiac Aquarius Limited + "xn--d1acj3b", // дети The Foundation for Network Initiatives “The Smart Internet” + "xn--eckvdtc9d", // ポイント Amazon Registry Services, Inc. + "xn--efvy88h", // 新闻 Xinhua News Agency Guangdong Branch 新华通讯社广东分社 + "xn--estv75g", // 工行 Industrial and Commercial Bank of China Limited + "xn--fct429k", // 家電 Amazon Registry Services, Inc. + "xn--fhbei", // كوم VeriSign Sarl + "xn--fiq228c5hs", // 中文网 TLD REGISTRY LIMITED + "xn--fiq64b", // 中信 CITIC Group Corporation + "xn--fjq720a", // 娱乐 Will Bloom, LLC + "xn--flw351e", // 谷歌 Charleston Road Registry Inc. + "xn--fzys8d69uvgm", // 電訊盈科 PCCW Enterprises Limited + "xn--g2xx48c", // 购物 Minds + Machines Group Limited + "xn--gckr3f0f", // クラウド Amazon Registry Services, Inc. + "xn--gk3at1e", // 通販 Amazon Registry Services, Inc. + "xn--hxt814e", // 网店 Zodiac Libra Limited + "xn--i1b6b1a6a2e", // संगठन Public Interest Registry + "xn--imr513n", // 餐厅 HU YI GLOBAL INFORMATION RESOURCES (HOLDING) COMPANY. HONGKONG LIMITED + "xn--io0a7i", // 网络 Computer Network Information Center of Chinese Academy of Sciences (China Internet Network Information Center) + "xn--j1aef", // ком VeriSign Sarl + "xn--jlq61u9w7b", // 诺基亚 Nokia Corporation + "xn--jvr189m", // 食品 Amazon Registry Services, Inc. + "xn--kcrx77d1x4a", // 飞利浦 Koninklijke Philips N.V. + "xn--kpu716f", // 手表 Richemont DNS Inc. + "xn--kput3i", // 手机 Beijing RITT-Net Technology Development Co., Ltd + "xn--mgba3a3ejt", // ارامكو Aramco Services Company + "xn--mgba7c0bbn0a", // العليان Crescent Holding GmbH + "xn--mgbab2bd", // بازار CORE Association + "xn--mgbb9fbpob", // موبايلي GreenTech Consultancy Company W.L.L. + "xn--mgbca7dzdo", // ابوظبي Abu Dhabi Systems and Information Centre + "xn--mgbi4ecexp", // كاثوليك Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) + "xn--mgbt3dhd", // همراه Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. + "xn--mk1bu44c", // 닷컴 VeriSign Sarl + "xn--mxtq1m", // 政府 Net-Chinese Co., Ltd. + "xn--ngbc5azd", // شبكة International Domain Registry Pty. Ltd. + "xn--ngbe9e0a", // بيتك Kuwait Finance House + "xn--nqv7f", // 机构 Public Interest Registry + "xn--nqv7fs00ema", // 组织机构 Public Interest Registry + "xn--nyqy26a", // 健康 Stable Tone Limited + "xn--p1acf", // рус Rusnames Limited + "xn--pbt977c", // 珠宝 Richemont DNS Inc. + "xn--pssy2u", // 大拿 VeriSign Sarl + "xn--q9jyb4c", // みんな Charleston Road Registry Inc. + "xn--qcka1pmc", // グーグル Charleston Road Registry Inc. + "xn--rhqv96g", // 世界 Stable Tone Limited + "xn--rovu88b", // 書籍 Amazon EU S.à r.l. + "xn--ses554g", // 网址 KNET Co., Ltd + "xn--t60b56a", // 닷넷 VeriSign Sarl + "xn--tckwe", // コム VeriSign Sarl + "xn--tiq49xqyj", // 天主教 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) + "xn--unup4y", // 游戏 Spring Fields, LLC + "xn--vermgensberater-ctb", // VERMöGENSBERATER Deutsche Vermögensberatung Aktiengesellschaft DVAG + "xn--vermgensberatung-pwb", // VERMöGENSBERATUNG Deutsche Vermögensberatung Aktiengesellschaft DVAG + "xn--vhquv", // 企业 Dash McCook, LLC + "xn--vuq861b", // 信息 Beijing Tele-info Network Technology Co., Ltd. + "xn--w4r85el8fhu5dnra", // 嘉里大酒店 Kerry Trading Co. Limited + "xn--w4rs40l", // 嘉里 Kerry Trading Co. Limited + "xn--xhq521b", // 广东 Guangzhou YU Wei Information Technology Co., Ltd. + "xn--zfr164b", // 政务 China Organizational Name Administration Center + "xperia", // xperia Sony Mobile Communications AB + "xxx", // xxx ICM Registry LLC + "xyz", // xyz XYZ.COM LLC + "yachts", // yachts DERYachts, LLC + "yahoo", // yahoo Yahoo! Domain Services Inc. + "yamaxun", // yamaxun Amazon Registry Services, Inc. + "yandex", // yandex YANDEX, LLC + "yodobashi", // yodobashi YODOBASHI CAMERA CO.,LTD. + "yoga", // yoga Top Level Domain Holdings Limited + "yokohama", // yokohama GMO Registry, Inc. + "you", // you Amazon Registry Services, Inc. + "youtube", // youtube Charleston Road Registry Inc. + "yun", // yun QIHOO 360 TECHNOLOGY CO. LTD. + "zappos", // zappos Amazon Registry Services, Inc. + "zara", // zara Industria de Diseño Textil, S.A. (INDITEX, S.A.) + "zero", // zero Amazon Registry Services, Inc. + "zip", // zip Charleston Road Registry Inc. + "zippo", // zippo Zadco Company + "zone", // zone Outer Falls, LLC + "zuerich", // zuerich Kanton Zürich (Canton of Zurich) + }; + + // WARNING: this array MUST be sorted, otherwise it cannot be searched reliably using binary search + private static final String[] COUNTRY_CODE_TLDS = new String[] { + "ac", // Ascension Island + "ad", // Andorra + "ae", // United Arab Emirates + "af", // Afghanistan + "ag", // Antigua and Barbuda + "ai", // Anguilla + "al", // Albania + "am", // Armenia +// "an", // Netherlands Antilles (retired) + "ao", // Angola + "aq", // Antarctica + "ar", // Argentina + "as", // American Samoa + "at", // Austria + "au", // Australia (includes Ashmore and Cartier Islands and Coral Sea Islands) + "aw", // Aruba + "ax", // Åland + "az", // Azerbaijan + "ba", // Bosnia and Herzegovina + "bb", // Barbados + "bd", // Bangladesh + "be", // Belgium + "bf", // Burkina Faso + "bg", // Bulgaria + "bh", // Bahrain + "bi", // Burundi + "bj", // Benin + "bm", // Bermuda + "bn", // Brunei Darussalam + "bo", // Bolivia + "br", // Brazil + "bs", // Bahamas + "bt", // Bhutan + "bv", // Bouvet Island + "bw", // Botswana + "by", // Belarus + "bz", // Belize + "ca", // Canada + "cc", // Cocos (Keeling) Islands + "cd", // Democratic Republic of the Congo (formerly Zaire) + "cf", // Central African Republic + "cg", // Republic of the Congo + "ch", // Switzerland + "ci", // Côte d'Ivoire + "ck", // Cook Islands + "cl", // Chile + "cm", // Cameroon + "cn", // China, mainland + "co", // Colombia + "cr", // Costa Rica + "cu", // Cuba + "cv", // Cape Verde + "cw", // Curaçao + "cx", // Christmas Island + "cy", // Cyprus + "cz", // Czech Republic + "de", // Germany + "dj", // Djibouti + "dk", // Denmark + "dm", // Dominica + "do", // Dominican Republic + "dz", // Algeria + "ec", // Ecuador + "ee", // Estonia + "eg", // Egypt + "er", // Eritrea + "es", // Spain + "et", // Ethiopia + "eu", // European Union + "fi", // Finland + "fj", // Fiji + "fk", // Falkland Islands + "fm", // Federated States of Micronesia + "fo", // Faroe Islands + "fr", // France + "ga", // Gabon + "gb", // Great Britain (United Kingdom) + "gd", // Grenada + "ge", // Georgia + "gf", // French Guiana + "gg", // Guernsey + "gh", // Ghana + "gi", // Gibraltar + "gl", // Greenland + "gm", // The Gambia + "gn", // Guinea + "gp", // Guadeloupe + "gq", // Equatorial Guinea + "gr", // Greece + "gs", // South Georgia and the South Sandwich Islands + "gt", // Guatemala + "gu", // Guam + "gw", // Guinea-Bissau + "gy", // Guyana + "hk", // Hong Kong + "hm", // Heard Island and McDonald Islands + "hn", // Honduras + "hr", // Croatia (Hrvatska) + "ht", // Haiti + "hu", // Hungary + "id", // Indonesia + "ie", // Ireland (Éire) + "il", // Israel + "im", // Isle of Man + "in", // India + "io", // British Indian Ocean Territory + "iq", // Iraq + "ir", // Iran + "is", // Iceland + "it", // Italy + "je", // Jersey + "jm", // Jamaica + "jo", // Jordan + "jp", // Japan + "ke", // Kenya + "kg", // Kyrgyzstan + "kh", // Cambodia (Khmer) + "ki", // Kiribati + "km", // Comoros + "kn", // Saint Kitts and Nevis + "kp", // North Korea + "kr", // South Korea + "kw", // Kuwait + "ky", // Cayman Islands + "kz", // Kazakhstan + "la", // Laos (currently being marketed as the official domain for Los Angeles) + "lb", // Lebanon + "lc", // Saint Lucia + "li", // Liechtenstein + "lk", // Sri Lanka + "lr", // Liberia + "ls", // Lesotho + "lt", // Lithuania + "lu", // Luxembourg + "lv", // Latvia + "ly", // Libya + "ma", // Morocco + "mc", // Monaco + "md", // Moldova + "me", // Montenegro + "mg", // Madagascar + "mh", // Marshall Islands + "mk", // Republic of Macedonia + "ml", // Mali + "mm", // Myanmar + "mn", // Mongolia + "mo", // Macau + "mp", // Northern Mariana Islands + "mq", // Martinique + "mr", // Mauritania + "ms", // Montserrat + "mt", // Malta + "mu", // Mauritius + "mv", // Maldives + "mw", // Malawi + "mx", // Mexico + "my", // Malaysia + "mz", // Mozambique + "na", // Namibia + "nc", // New Caledonia + "ne", // Niger + "nf", // Norfolk Island + "ng", // Nigeria + "ni", // Nicaragua + "nl", // Netherlands + "no", // Norway + "np", // Nepal + "nr", // Nauru + "nu", // Niue + "nz", // New Zealand + "om", // Oman + "pa", // Panama + "pe", // Peru + "pf", // French Polynesia With Clipperton Island + "pg", // Papua New Guinea + "ph", // Philippines + "pk", // Pakistan + "pl", // Poland + "pm", // Saint-Pierre and Miquelon + "pn", // Pitcairn Islands + "pr", // Puerto Rico + "ps", // Palestinian territories (PA-controlled West Bank and Gaza Strip) + "pt", // Portugal + "pw", // Palau + "py", // Paraguay + "qa", // Qatar + "re", // Réunion + "ro", // Romania + "rs", // Serbia + "ru", // Russia + "rw", // Rwanda + "sa", // Saudi Arabia + "sb", // Solomon Islands + "sc", // Seychelles + "sd", // Sudan + "se", // Sweden + "sg", // Singapore + "sh", // Saint Helena + "si", // Slovenia + "sj", // Svalbard and Jan Mayen Islands Not in use (Norwegian dependencies; see .no) + "sk", // Slovakia + "sl", // Sierra Leone + "sm", // San Marino + "sn", // Senegal + "so", // Somalia + "sr", // Suriname + "st", // São Tomé and Príncipe + "su", // Soviet Union (deprecated) + "sv", // El Salvador + "sx", // Sint Maarten + "sy", // Syria + "sz", // Swaziland + "tc", // Turks and Caicos Islands + "td", // Chad + "tf", // French Southern and Antarctic Lands + "tg", // Togo + "th", // Thailand + "tj", // Tajikistan + "tk", // Tokelau + "tl", // East Timor (deprecated old code) + "tm", // Turkmenistan + "tn", // Tunisia + "to", // Tonga +// "tp", // East Timor (Retired) + "tr", // Turkey + "tt", // Trinidad and Tobago + "tv", // Tuvalu + "tw", // Taiwan, Republic of China + "tz", // Tanzania + "ua", // Ukraine + "ug", // Uganda + "uk", // United Kingdom + "us", // United States of America + "uy", // Uruguay + "uz", // Uzbekistan + "va", // Vatican City State + "vc", // Saint Vincent and the Grenadines + "ve", // Venezuela + "vg", // British Virgin Islands + "vi", // U.S. Virgin Islands + "vn", // Vietnam + "vu", // Vanuatu + "wf", // Wallis and Futuna + "ws", // Samoa (formerly Western Samoa) + "xn--3e0b707e", // 한국 KISA (Korea Internet & Security Agency) + "xn--45brj9c", // ভারত National Internet Exchange of India + "xn--54b7fta0cc", // বাংলা Posts and Telecommunications Division + "xn--80ao21a", // қаз Association of IT Companies of Kazakhstan + "xn--90a3ac", // срб Serbian National Internet Domain Registry (RNIDS) + "xn--90ais", // ??? Reliable Software Inc. + "xn--clchc0ea0b2g2a9gcd", // சிங்கப்பூர் Singapore Network Information Centre (SGNIC) Pte Ltd + "xn--d1alf", // мкд Macedonian Academic Research Network Skopje + "xn--e1a4c", // ею EURid vzw/asbl + "xn--fiqs8s", // 中国 China Internet Network Information Center + "xn--fiqz9s", // 中國 China Internet Network Information Center + "xn--fpcrj9c3d", // భారత్ National Internet Exchange of India + "xn--fzc2c9e2c", // ලංකා LK Domain Registry + "xn--gecrj9c", // ભારત National Internet Exchange of India + "xn--h2brj9c", // भारत National Internet Exchange of India + "xn--j1amh", // укр Ukrainian Network Information Centre (UANIC), Inc. + "xn--j6w193g", // 香港 Hong Kong Internet Registration Corporation Ltd. + "xn--kprw13d", // 台湾 Taiwan Network Information Center (TWNIC) + "xn--kpry57d", // 台灣 Taiwan Network Information Center (TWNIC) + "xn--l1acc", // мон Datacom Co.,Ltd + "xn--lgbbat1ad8j", // الجزائر CERIST + "xn--mgb9awbf", // عمان Telecommunications Regulatory Authority (TRA) + "xn--mgba3a4f16a", // ایران Institute for Research in Fundamental Sciences (IPM) + "xn--mgbaam7a8h", // امارات Telecommunications Regulatory Authority (TRA) + "xn--mgbayh7gpa", // الاردن National Information Technology Center (NITC) + "xn--mgbbh1a71e", // بھارت National Internet Exchange of India + "xn--mgbc0a9azcg", // المغرب Agence Nationale de Réglementation des Télécommunications (ANRT) + "xn--mgberp4a5d4ar", // السعودية Communications and Information Technology Commission + "xn--mgbpl2fh", // ????? Sudan Internet Society + "xn--mgbtx2b", // عراق Communications and Media Commission (CMC) + "xn--mgbx4cd0ab", // مليسيا MYNIC Berhad + "xn--mix891f", // 澳門 Bureau of Telecommunications Regulation (DSRT) + "xn--node", // გე Information Technologies Development Center (ITDC) + "xn--o3cw4h", // ไทย Thai Network Information Center Foundation + "xn--ogbpf8fl", // سورية National Agency for Network Services (NANS) + "xn--p1ai", // рф Coordination Center for TLD RU + "xn--pgbs0dh", // تونس Agence Tunisienne d'Internet + "xn--qxam", // ελ ICS-FORTH GR + "xn--s9brj9c", // ਭਾਰਤ National Internet Exchange of India + "xn--wgbh1c", // مصر National Telecommunication Regulatory Authority - NTRA + "xn--wgbl6a", // قطر Communications Regulatory Authority + "xn--xkc2al3hye2a", // இலங்கை LK Domain Registry + "xn--xkc2dl3a5ee0h", // இந்தியா National Internet Exchange of India + "xn--y9a3aq", // ??? Internet Society + "xn--yfro4i67o", // 新加坡 Singapore Network Information Centre (SGNIC) Pte Ltd + "xn--ygbi2ammx", // فلسطين Ministry of Telecom & Information Technology (MTIT) + "ye", // Yemen + "yt", // Mayotte + "za", // South Africa + "zm", // Zambia + "zw", // Zimbabwe + }; + + // WARNING: this array MUST be sorted, otherwise it cannot be searched reliably using binary search + private static final String[] LOCAL_TLDS = new String[] { + "localdomain", // Also widely used as localhost.localdomain + "localhost", // RFC2606 defined + }; + + // Additional arrays to supplement or override the built in ones. + // The PLUS arrays are valid keys, the MINUS arrays are invalid keys + + /* + * This field is used to detect whether the getInstance has been called. + * After this, the method updateTLDOverride is not allowed to be called. + * This field does not need to be volatile since it is only accessed from + * synchronized methods. + */ + private static boolean inUse = false; + + /* + * These arrays are mutable, but they don't need to be volatile. + * They can only be updated by the updateTLDOverride method, and any readers must get an instance + * using the getInstance methods which are all (now) synchronised. + */ + // WARNING: this array MUST be sorted, otherwise it cannot be searched reliably using binary search + private static volatile String[] countryCodeTLDsPlus = EMPTY_STRING_ARRAY; + + // WARNING: this array MUST be sorted, otherwise it cannot be searched reliably using binary search + private static volatile String[] genericTLDsPlus = EMPTY_STRING_ARRAY; + + // WARNING: this array MUST be sorted, otherwise it cannot be searched reliably using binary search + private static volatile String[] countryCodeTLDsMinus = EMPTY_STRING_ARRAY; + + // WARNING: this array MUST be sorted, otherwise it cannot be searched reliably using binary search + private static volatile String[] genericTLDsMinus = EMPTY_STRING_ARRAY; + + /** + * enum used by {@link DomainValidator#updateTLDOverride(DomainValidator.ArrayType, String[])} + * to determine which override array to update / fetch + * @since 1.5.0 + * @since 1.5.1 made public and added read-only array references + */ + public enum ArrayType { + /** Update (or get a copy of) the GENERIC_TLDS_PLUS table containing additonal generic TLDs */ + GENERIC_PLUS, + /** Update (or get a copy of) the GENERIC_TLDS_MINUS table containing deleted generic TLDs */ + GENERIC_MINUS, + /** Update (or get a copy of) the COUNTRY_CODE_TLDS_PLUS table containing additonal country code TLDs */ + COUNTRY_CODE_PLUS, + /** Update (or get a copy of) the COUNTRY_CODE_TLDS_MINUS table containing deleted country code TLDs */ + COUNTRY_CODE_MINUS, + /** Get a copy of the generic TLDS table */ + GENERIC_RO, + /** Get a copy of the country code table */ + COUNTRY_CODE_RO, + /** Get a copy of the infrastructure table */ + INFRASTRUCTURE_RO, + /** Get a copy of the local table */ + LOCAL_RO + ; + }; + + // For use by unit test code only + static synchronized void clearTLDOverrides() { + inUse = false; + countryCodeTLDsPlus = EMPTY_STRING_ARRAY; + countryCodeTLDsMinus = EMPTY_STRING_ARRAY; + genericTLDsPlus = EMPTY_STRING_ARRAY; + genericTLDsMinus = EMPTY_STRING_ARRAY; + } + /** + * Update one of the TLD override arrays. + * This must only be done at program startup, before any instances are accessed using getInstance. + *

+ * For example: + *

+ * {@code DomainValidator.updateTLDOverride(ArrayType.GENERIC_PLUS, new String[]{"apache"})} + *

+ * To clear an override array, provide an empty array. + * + * @param table the table to update, see {@link DomainValidator.ArrayType} + * Must be one of the following + *

    + *
  • COUNTRY_CODE_MINUS
  • + *
  • COUNTRY_CODE_PLUS
  • + *
  • GENERIC_MINUS
  • + *
  • GENERIC_PLUS
  • + *
+ * @param tlds the array of TLDs, must not be null + * @throws IllegalStateException if the method is called after getInstance + * @throws IllegalArgumentException if one of the read-only tables is requested + * @since 1.5.0 + */ + public static synchronized void updateTLDOverride(DomainValidator.ArrayType table, String [] tlds) { + if (inUse) { + throw new IllegalStateException("Can only invoke this method before calling getInstance"); + } + String [] copy = new String[tlds.length]; + // Comparisons are always done with lower-case entries + for (int i = 0; i < tlds.length; i++) { + copy[i] = tlds[i].toLowerCase(Locale.ENGLISH); + } + Arrays.sort(copy); + switch(table) { + case COUNTRY_CODE_MINUS: + countryCodeTLDsMinus = copy; + break; + case COUNTRY_CODE_PLUS: + countryCodeTLDsPlus = copy; + break; + case GENERIC_MINUS: + genericTLDsMinus = copy; + break; + case GENERIC_PLUS: + genericTLDsPlus = copy; + break; + case COUNTRY_CODE_RO: + case GENERIC_RO: + case INFRASTRUCTURE_RO: + case LOCAL_RO: + throw new IllegalArgumentException("Cannot update the table: " + table); + default: + throw new IllegalArgumentException("Unexpected enum value: " + table); + } + } + + /** + * Get a copy of the internal array. + * @param table the array type (any of the enum values) + * @return a copy of the array + * @throws IllegalArgumentException if the table type is unexpected (should not happen) + * @since 1.5.1 + */ + public static String [] getTLDEntries(DomainValidator.ArrayType table) { + final String array[]; + switch(table) { + case COUNTRY_CODE_MINUS: + array = countryCodeTLDsMinus; + break; + case COUNTRY_CODE_PLUS: + array = countryCodeTLDsPlus; + break; + case GENERIC_MINUS: + array = genericTLDsMinus; + break; + case GENERIC_PLUS: + array = genericTLDsPlus; + break; + case GENERIC_RO: + array = GENERIC_TLDS; + break; + case COUNTRY_CODE_RO: + array = COUNTRY_CODE_TLDS; + break; + case INFRASTRUCTURE_RO: + array = INFRASTRUCTURE_TLDS; + break; + case LOCAL_RO: + array = LOCAL_TLDS; + break; + default: + throw new IllegalArgumentException("Unexpected enum value: " + table); + } + return Arrays.copyOf(array, array.length); // clone the array + } + + /** + * Converts potentially Unicode input to punycode. + * If conversion fails, returns the original input. + * + * @param input the string to convert, not null + * @return converted input, or original input if conversion fails + */ + // Needed by UrlValidator + //[PATCH] + public + // end of [PATCH] + static String unicodeToASCII(String input) { + if (isOnlyASCII(input)) { // skip possibly expensive processing + return input; + } + try { + final String ascii = IDN.toASCII(input); + if (DomainValidator.IDNBUGHOLDER.IDN_TOASCII_PRESERVES_TRAILING_DOTS) { + return ascii; + } + final int length = input.length(); + if (length == 0) {// check there is a last character + return input; + } + // RFC3490 3.1. 1) + // Whenever dots are used as label separators, the following + // characters MUST be recognized as dots: U+002E (full stop), U+3002 + // (ideographic full stop), U+FF0E (fullwidth full stop), U+FF61 + // (halfwidth ideographic full stop). + char lastChar = input.charAt(length-1);// fetch original last char + switch(lastChar) { + case '\u002E': // "." full stop + case '\u3002': // ideographic full stop + case '\uFF0E': // fullwidth full stop + case '\uFF61': // halfwidth ideographic full stop + return ascii + "."; // restore the missing stop + default: + return ascii; + } + } catch (IllegalArgumentException e) { // input is not valid + return input; + } + } + + private static class IDNBUGHOLDER { + private static boolean keepsTrailingDot() { + final String input = "a."; // must be a valid name + return input.equals(IDN.toASCII(input)); + } + private static final boolean IDN_TOASCII_PRESERVES_TRAILING_DOTS = keepsTrailingDot(); + } + + /* + * Check if input contains only ASCII + * Treats null as all ASCII + */ + private static boolean isOnlyASCII(String input) { + if (input == null) { + return true; + } + for(int i=0; i < input.length(); i++) { + if (input.charAt(i) > 0x7F) { // CHECKSTYLE IGNORE MagicNumber + return false; + } + } + return true; + } + + /** + * Check if a sorted array contains the specified key + * + * @param sortedArray the array to search + * @param key the key to find + * @return {@code true} if the array contains the key + */ + private static boolean arrayContains(String[] sortedArray, String key) { + return Arrays.binarySearch(sortedArray, key) >= 0; + } +} diff --git a/core/src/main/java/jenkins/org/apache/commons/validator/routines/InetAddressValidator.java b/core/src/main/java/jenkins/org/apache/commons/validator/routines/InetAddressValidator.java new file mode 100644 index 0000000000..59ac7ceb2b --- /dev/null +++ b/core/src/main/java/jenkins/org/apache/commons/validator/routines/InetAddressValidator.java @@ -0,0 +1,196 @@ +/* + * 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. + */ +/* Copied from commons-validator:commons-validator:1.6, with [PATCH] modifications */ +package jenkins.org.apache.commons.validator.routines; + +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + *

InetAddress validation and conversion routines (java.net.InetAddress).

+ * + *

This class provides methods to validate a candidate IP address. + * + *

+ * This class is a Singleton; you can retrieve the instance via the {@link #getInstance()} method. + *

+ * + * @version $Revision: 1783032 $ + * @since Validator 1.4 + */ +//[PATCH] +@Restricted(NoExternalUse.class) +// end of [PATCH] +public class InetAddressValidator implements Serializable { + + private static final int IPV4_MAX_OCTET_VALUE = 255; + + private static final int MAX_UNSIGNED_SHORT = 0xffff; + + private static final int BASE_16 = 16; + + private static final long serialVersionUID = -919201640201914789L; + + private static final String IPV4_REGEX = + "^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$"; + + // Max number of hex groups (separated by :) in an IPV6 address + private static final int IPV6_MAX_HEX_GROUPS = 8; + + // Max hex digits in each IPv6 group + private static final int IPV6_MAX_HEX_DIGITS_PER_GROUP = 4; + + /** + * Singleton instance of this class. + */ + private static final InetAddressValidator VALIDATOR = new InetAddressValidator(); + + /** IPv4 RegexValidator */ + private final RegexValidator ipv4Validator = new RegexValidator(IPV4_REGEX); + + /** + * Returns the singleton instance of this validator. + * @return the singleton instance of this validator + */ + public static InetAddressValidator getInstance() { + return VALIDATOR; + } + + /** + * Checks if the specified string is a valid IP address. + * @param inetAddress the string to validate + * @return true if the string validates as an IP address + */ + public boolean isValid(String inetAddress) { + return isValidInet4Address(inetAddress) || isValidInet6Address(inetAddress); + } + + /** + * Validates an IPv4 address. Returns true if valid. + * @param inet4Address the IPv4 address to validate + * @return true if the argument contains a valid IPv4 address + */ + public boolean isValidInet4Address(String inet4Address) { + // verify that address conforms to generic IPv4 format + String[] groups = ipv4Validator.match(inet4Address); + + if (groups == null) { + return false; + } + + // verify that address subgroups are legal + for (String ipSegment : groups) { + if (ipSegment == null || ipSegment.length() == 0) { + return false; + } + + int iIpSegment = 0; + + try { + iIpSegment = Integer.parseInt(ipSegment); + } catch(NumberFormatException e) { + return false; + } + + if (iIpSegment > IPV4_MAX_OCTET_VALUE) { + return false; + } + + if (ipSegment.length() > 1 && ipSegment.startsWith("0")) { + return false; + } + + } + + return true; + } + + /** + * Validates an IPv6 address. Returns true if valid. + * @param inet6Address the IPv6 address to validate + * @return true if the argument contains a valid IPv6 address + * + * @since 1.4.1 + */ + public boolean isValidInet6Address(String inet6Address) { + boolean containsCompressedZeroes = inet6Address.contains("::"); + if (containsCompressedZeroes && (inet6Address.indexOf("::") != inet6Address.lastIndexOf("::"))) { + return false; + } + if ((inet6Address.startsWith(":") && !inet6Address.startsWith("::")) + || (inet6Address.endsWith(":") && !inet6Address.endsWith("::"))) { + return false; + } + String[] octets = inet6Address.split(":"); + if (containsCompressedZeroes) { + List octetList = new ArrayList(Arrays.asList(octets)); + if (inet6Address.endsWith("::")) { + // String.split() drops ending empty segments + octetList.add(""); + } else if (inet6Address.startsWith("::") && !octetList.isEmpty()) { + octetList.remove(0); + } + octets = octetList.toArray(new String[octetList.size()]); + } + if (octets.length > IPV6_MAX_HEX_GROUPS) { + return false; + } + int validOctets = 0; + int emptyOctets = 0; // consecutive empty chunks + for (int index = 0; index < octets.length; index++) { + String octet = octets[index]; + if (octet.length() == 0) { + emptyOctets++; + if (emptyOctets > 1) { + return false; + } + } else { + emptyOctets = 0; + // Is last chunk an IPv4 address? + if (index == octets.length - 1 && octet.contains(".")) { + if (!isValidInet4Address(octet)) { + return false; + } + validOctets += 2; + continue; + } + if (octet.length() > IPV6_MAX_HEX_DIGITS_PER_GROUP) { + return false; + } + int octetInt = 0; + try { + octetInt = Integer.parseInt(octet, BASE_16); + } catch (NumberFormatException e) { + return false; + } + if (octetInt < 0 || octetInt > MAX_UNSIGNED_SHORT) { + return false; + } + } + validOctets++; + } + if (validOctets > IPV6_MAX_HEX_GROUPS || (validOctets < IPV6_MAX_HEX_GROUPS && !containsCompressedZeroes)) { + return false; + } + return true; + } +} diff --git a/core/src/main/java/jenkins/org/apache/commons/validator/routines/RegexValidator.java b/core/src/main/java/jenkins/org/apache/commons/validator/routines/RegexValidator.java new file mode 100644 index 0000000000..eebc3747d9 --- /dev/null +++ b/core/src/main/java/jenkins/org/apache/commons/validator/routines/RegexValidator.java @@ -0,0 +1,237 @@ +/* + * 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. + */ +/* Copied from commons-validator:commons-validator:1.6, with [PATCH] modifications */ +package jenkins.org.apache.commons.validator.routines; + +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; + +import java.io.Serializable; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Regular Expression validation (using JDK 1.4+ regex support). + *

+ * Construct the validator either for a single regular expression or a set (array) of + * regular expressions. By default validation is case sensitive but constructors + * are provided to allow case in-sensitive validation. For example to create + * a validator which does case in-sensitive validation for a set of regular + * expressions: + *

+ *
+ * 
+ * String[] regexs = new String[] {...};
+ * RegexValidator validator = new RegexValidator(regexs, false);
+ * 
+ * 
+ * + *
    + *
  • Validate true or false:
  • + *
  • + *
      + *
    • boolean valid = validator.isValidRootUrl(value);
    • + *
    + *
  • + *
  • Validate returning an aggregated String of the matched groups:
  • + *
  • + *
      + *
    • String result = validator.validate(value);
    • + *
    + *
  • + *
  • Validate returning the matched groups:
  • + *
  • + *
      + *
    • String[] result = validator.match(value);
    • + *
    + *
  • + *
+ * + * Note that patterns are matched against the entire input. + * + *

+ * Cached instances pre-compile and re-use {@link Pattern}(s) - which according + * to the {@link Pattern} API are safe to use in a multi-threaded environment. + *

+ * + * @version $Revision: 1739356 $ + * @since Validator 1.4 + */ +//[PATCH] +@Restricted(NoExternalUse.class) +// end of [PATCH] +public class RegexValidator implements Serializable { + + private static final long serialVersionUID = -8832409930574867162L; + + private final Pattern[] patterns; + + /** + * Construct a case sensitive validator for a single + * regular expression. + * + * @param regex The regular expression this validator will + * validate against + */ + public RegexValidator(String regex) { + this(regex, true); + } + + /** + * Construct a validator for a single regular expression + * with the specified case sensitivity. + * + * @param regex The regular expression this validator will + * validate against + * @param caseSensitive when true matching is case + * sensitive, otherwise matching is case in-sensitive + */ + public RegexValidator(String regex, boolean caseSensitive) { + this(new String[] {regex}, caseSensitive); + } + + /** + * Construct a case sensitive validator that matches any one + * of the set of regular expressions. + * + * @param regexs The set of regular expressions this validator will + * validate against + */ + public RegexValidator(String[] regexs) { + this(regexs, true); + } + + /** + * Construct a validator that matches any one of the set of regular + * expressions with the specified case sensitivity. + * + * @param regexs The set of regular expressions this validator will + * validate against + * @param caseSensitive when true matching is case + * sensitive, otherwise matching is case in-sensitive + */ + public RegexValidator(String[] regexs, boolean caseSensitive) { + if (regexs == null || regexs.length == 0) { + throw new IllegalArgumentException("Regular expressions are missing"); + } + patterns = new Pattern[regexs.length]; + int flags = (caseSensitive ? 0: Pattern.CASE_INSENSITIVE); + for (int i = 0; i < regexs.length; i++) { + if (regexs[i] == null || regexs[i].length() == 0) { + throw new IllegalArgumentException("Regular expression[" + i + "] is missing"); + } + patterns[i] = Pattern.compile(regexs[i], flags); + } + } + + /** + * Validate a value against the set of regular expressions. + * + * @param value The value to validate. + * @return true if the value is valid + * otherwise false. + */ + public boolean isValid(String value) { + if (value == null) { + return false; + } + for (int i = 0; i < patterns.length; i++) { + if (patterns[i].matcher(value).matches()) { + return true; + } + } + return false; + } + + /** + * Validate a value against the set of regular expressions + * returning the array of matched groups. + * + * @param value The value to validate. + * @return String array of the groups matched if + * valid or null if invalid + */ + public String[] match(String value) { + if (value == null) { + return null; + } + for (int i = 0; i < patterns.length; i++) { + Matcher matcher = patterns[i].matcher(value); + if (matcher.matches()) { + int count = matcher.groupCount(); + String[] groups = new String[count]; + for (int j = 0; j < count; j++) { + groups[j] = matcher.group(j+1); + } + return groups; + } + } + return null; + } + + + /** + * Validate a value against the set of regular expressions + * returning a String value of the aggregated groups. + * + * @param value The value to validate. + * @return Aggregated String value comprised of the + * groups matched if valid or null if invalid + */ + public String validate(String value) { + if (value == null) { + return null; + } + for (int i = 0; i < patterns.length; i++) { + Matcher matcher = patterns[i].matcher(value); + if (matcher.matches()) { + int count = matcher.groupCount(); + if (count == 1) { + return matcher.group(1); + } + StringBuilder buffer = new StringBuilder(); + for (int j = 0; j < count; j++) { + String component = matcher.group(j+1); + if (component != null) { + buffer.append(component); + } + } + return buffer.toString(); + } + } + return null; + } + + /** + * Provide a String representation of this validator. + * @return A String representation of this validator + */ + @Override + public String toString() { + StringBuilder buffer = new StringBuilder(); + buffer.append("RegexValidator{"); + for (int i = 0; i < patterns.length; i++) { + if (i > 0) { + buffer.append(","); + } + buffer.append(patterns[i].pattern()); + } + buffer.append("}"); + return buffer.toString(); + } + +} diff --git a/core/src/main/java/jenkins/org/apache/commons/validator/routines/UrlValidator.java b/core/src/main/java/jenkins/org/apache/commons/validator/routines/UrlValidator.java new file mode 100644 index 0000000000..f309b177e6 --- /dev/null +++ b/core/src/main/java/jenkins/org/apache/commons/validator/routines/UrlValidator.java @@ -0,0 +1,551 @@ +/* + * 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. + */ +/* Copied from commons-validator:commons-validator:1.6, with [PATCH] modifications */ +package jenkins.org.apache.commons.validator.routines; + +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; + +import java.io.Serializable; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Collections; +import java.util.HashSet; +import java.util.Locale; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + *

URL Validation routines.

+ * Behavior of validation is modified by passing in options: + *
    + *
  • ALLOW_2_SLASHES - [FALSE] Allows double '/' characters in the path + * component.
  • + *
  • NO_FRAGMENT- [FALSE] By default fragments are allowed, if this option is + * included then fragments are flagged as illegal.
  • + *
  • ALLOW_ALL_SCHEMES - [FALSE] By default only http, https, and ftp are + * considered valid schemes. Enabling this option will let any scheme pass validation.
  • + *
+ * + *

Originally based in on php script by Debbie Dyer, validation.php v1.2b, Date: 03/07/02, + * http://javascript.internet.com. However, this validation now bears little resemblance + * to the php original.

+ *
+ *   Example of usage:
+ *   Construct a UrlValidator with valid schemes of "http", and "https".
+ *
+ *    String[] schemes = {"http","https"}.
+ *    UrlValidator urlValidator = new UrlValidator(schemes);
+ *    if (urlValidator.isValidRootUrl("ftp://foo.bar.com/")) {
+ *       System.out.println("url is valid");
+ *    } else {
+ *       System.out.println("url is invalid");
+ *    }
+ *
+ *    prints "url is invalid"
+ *   If instead the default constructor is used.
+ *
+ *    UrlValidator urlValidator = new UrlValidator();
+ *    if (urlValidator.isValidRootUrl("ftp://foo.bar.com/")) {
+ *       System.out.println("url is valid");
+ *    } else {
+ *       System.out.println("url is invalid");
+ *    }
+ *
+ *   prints out "url is valid"
+ *  
+ * + * @see + * + * Uniform Resource Identifiers (URI): Generic Syntax + * + * + * @version $Revision: 1783203 $ + * @since Validator 1.4 + */ +//[PATCH] +@Restricted(NoExternalUse.class) +// end of [PATCH] +public class UrlValidator implements Serializable { + + private static final long serialVersionUID = 7557161713937335013L; + + private static final int MAX_UNSIGNED_16_BIT_INT = 0xFFFF; // port max + + /** + * Allows all validly formatted schemes to pass validation instead of + * supplying a set of valid schemes. + */ + public static final long ALLOW_ALL_SCHEMES = 1 << 0; + + /** + * Allow two slashes in the path component of the URL. + */ + public static final long ALLOW_2_SLASHES = 1 << 1; + + /** + * Enabling this options disallows any URL fragments. + */ + public static final long NO_FRAGMENTS = 1 << 2; + + /** + * Allow local URLs, such as http://localhost/ or http://machine/ . + * This enables a broad-brush check, for complex local machine name + * validation requirements you should create your validator with + * a {@link RegexValidator} instead ({@link #UrlValidator(RegexValidator, long)}) + */ + public static final long ALLOW_LOCAL_URLS = 1 << 3; // CHECKSTYLE IGNORE MagicNumber + + /** + * This expression derived/taken from the BNF for URI (RFC2396). + */ + private static final String URL_REGEX = + "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?"; + // 12 3 4 5 6 7 8 9 + private static final Pattern URL_PATTERN = Pattern.compile(URL_REGEX); + + /** + * Schema/Protocol (ie. http:, ftp:, file:, etc). + */ + private static final int PARSE_URL_SCHEME = 2; + + /** + * Includes hostname/ip and port number. + */ + private static final int PARSE_URL_AUTHORITY = 4; + + private static final int PARSE_URL_PATH = 5; + + private static final int PARSE_URL_QUERY = 7; + + private static final int PARSE_URL_FRAGMENT = 9; + + /** + * Protocol scheme (e.g. http, ftp, https). + */ + private static final String SCHEME_REGEX = "^\\p{Alpha}[\\p{Alnum}\\+\\-\\.]*"; + private static final Pattern SCHEME_PATTERN = Pattern.compile(SCHEME_REGEX); + + // Drop numeric, and "+-." for now + // TODO does not allow for optional userinfo. + // Validation of character set is done by isValidAuthority + private static final String AUTHORITY_CHARS_REGEX = "\\p{Alnum}\\-\\."; // allows for IPV4 but not IPV6 + private static final String IPV6_REGEX = "[0-9a-fA-F:]+"; // do this as separate match because : could cause ambiguity with port prefix + + // userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) + // unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + // sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "=" + // We assume that password has the same valid chars as user info + private static final String USERINFO_CHARS_REGEX = "[a-zA-Z0-9%-._~!$&'()*+,;=]"; + // since neither ':' nor '@' are allowed chars, we don't need to use non-greedy matching + private static final String USERINFO_FIELD_REGEX = + USERINFO_CHARS_REGEX + "+" + // At least one character for the name + "(?::" + USERINFO_CHARS_REGEX + "*)?@"; // colon and password may be absent + private static final String AUTHORITY_REGEX = + "(?:\\[("+IPV6_REGEX+")\\]|(?:(?:"+USERINFO_FIELD_REGEX+")?([" + AUTHORITY_CHARS_REGEX + "]*)))(?::(\\d*))?(.*)?"; + // 1 e.g. user:pass@ 2 3 4 + private static final Pattern AUTHORITY_PATTERN = Pattern.compile(AUTHORITY_REGEX); + + private static final int PARSE_AUTHORITY_IPV6 = 1; + + private static final int PARSE_AUTHORITY_HOST_IP = 2; // excludes userinfo, if present + + private static final int PARSE_AUTHORITY_PORT = 3; // excludes leading colon + + /** + * Should always be empty. The code currently allows spaces. + */ + private static final int PARSE_AUTHORITY_EXTRA = 4; + + private static final String PATH_REGEX = "^(/[-\\w:@&?=+,.!/~*'%$_;\\(\\)]*)?$"; + private static final Pattern PATH_PATTERN = Pattern.compile(PATH_REGEX); + + private static final String QUERY_REGEX = "^(\\S*)$"; + private static final Pattern QUERY_PATTERN = Pattern.compile(QUERY_REGEX); + + /** + * Holds the set of current validation options. + */ + private final long options; + + /** + * The set of schemes that are allowed to be in a URL. + */ + private final Set allowedSchemes; // Must be lower-case + + /** + * Regular expressions used to manually validate authorities if IANA + * domain name validation isn't desired. + */ + private final RegexValidator authorityValidator; + + /** + * If no schemes are provided, default to this set. + */ + private static final String[] DEFAULT_SCHEMES = {"http", "https", "ftp"}; // Must be lower-case + + /** + * Singleton instance of this class with default schemes and options. + */ + private static final UrlValidator DEFAULT_URL_VALIDATOR = new UrlValidator(); + + /** + * Returns the singleton instance of this class with default schemes and options. + * @return singleton instance with default schemes and options + */ + public static UrlValidator getInstance() { + return DEFAULT_URL_VALIDATOR; + } + + /** + * Create a UrlValidator with default properties. + */ + public UrlValidator() { + this(null); + } + + /** + * Behavior of validation is modified by passing in several strings options: + * @param schemes Pass in one or more url schemes to consider valid, passing in + * a null will default to "http,https,ftp" being valid. + * If a non-null schemes is specified then all valid schemes must + * be specified. Setting the ALLOW_ALL_SCHEMES option will + * ignore the contents of schemes. + */ + public UrlValidator(String[] schemes) { + this(schemes, 0L); + } + + /** + * Initialize a UrlValidator with the given validation options. + * @param options The options should be set using the public constants declared in + * this class. To set multiple options you simply add them together. For example, + * ALLOW_2_SLASHES + NO_FRAGMENTS enables both of those options. + */ + public UrlValidator(long options) { + this(null, null, options); + } + + /** + * Behavior of validation is modified by passing in options: + * @param schemes The set of valid schemes. Ignored if the ALLOW_ALL_SCHEMES option is set. + * @param options The options should be set using the public constants declared in + * this class. To set multiple options you simply add them together. For example, + * ALLOW_2_SLASHES + NO_FRAGMENTS enables both of those options. + */ + public UrlValidator(String[] schemes, long options) { + this(schemes, null, options); + } + + /** + * Initialize a UrlValidator with the given validation options. + * @param authorityValidator Regular expression validator used to validate the authority part + * This allows the user to override the standard set of domains. + * @param options Validation options. Set using the public constants of this class. + * To set multiple options, simply add them together: + *

ALLOW_2_SLASHES + NO_FRAGMENTS

+ * enables both of those options. + */ + public UrlValidator(RegexValidator authorityValidator, long options) { + this(null, authorityValidator, options); + } + + /** + * Customizable constructor. Validation behavior is modifed by passing in options. + * @param schemes the set of valid schemes. Ignored if the ALLOW_ALL_SCHEMES option is set. + * @param authorityValidator Regular expression validator used to validate the authority part + * @param options Validation options. Set using the public constants of this class. + * To set multiple options, simply add them together: + *

ALLOW_2_SLASHES + NO_FRAGMENTS

+ * enables both of those options. + */ + public UrlValidator(String[] schemes, RegexValidator authorityValidator, long options) { + this.options = options; + + if (isOn(ALLOW_ALL_SCHEMES)) { + allowedSchemes = Collections.emptySet(); + } else { + if (schemes == null) { + schemes = DEFAULT_SCHEMES; + } + allowedSchemes = new HashSet(schemes.length); + for(int i=0; i < schemes.length; i++) { + allowedSchemes.add(schemes[i].toLowerCase(Locale.ENGLISH)); + } + } + + this.authorityValidator = authorityValidator; + } + + /** + *

Checks if a field has a valid url address.

+ * + * Note that the method calls #isValidAuthority() + * which checks that the domain is valid. + * + * @param value The value validation is being performed on. A null + * value is considered invalid. + * @return true if the url is valid. + */ + public boolean isValid(String value) { + if (value == null) { + return false; + } + + // Check the whole url address structure + Matcher urlMatcher = URL_PATTERN.matcher(value); + if (!urlMatcher.matches()) { + return false; + } + + String scheme = urlMatcher.group(PARSE_URL_SCHEME); + if (!isValidScheme(scheme)) { + return false; + } + + String authority = urlMatcher.group(PARSE_URL_AUTHORITY); + if ("file".equals(scheme)) {// Special case - file: allows an empty authority + if (authority != null) { + if (authority.contains(":")) { // but cannot allow trailing : + return false; + } + } + // drop through to continue validation + } else { // not file: + // Validate the authority + if (!isValidAuthority(authority)) { + return false; + } + } + + if (!isValidPath(urlMatcher.group(PARSE_URL_PATH))) { + return false; + } + + if (!isValidQuery(urlMatcher.group(PARSE_URL_QUERY))) { + return false; + } + + if (!isValidFragment(urlMatcher.group(PARSE_URL_FRAGMENT))) { + return false; + } + + return true; + } + + /** + * Validate scheme. If schemes[] was initialized to a non null, + * then only those schemes are allowed. + * Otherwise the default schemes are "http", "https", "ftp". + * Matching is case-blind. + * @param scheme The scheme to validate. A null value is considered + * invalid. + * @return true if valid. + */ + protected boolean isValidScheme(String scheme) { + if (scheme == null) { + return false; + } + + // TODO could be removed if external schemes were checked in the ctor before being stored + if (!SCHEME_PATTERN.matcher(scheme).matches()) { + return false; + } + + if (isOff(ALLOW_ALL_SCHEMES) && !allowedSchemes.contains(scheme.toLowerCase(Locale.ENGLISH))) { + return false; + } + + return true; + } + + /** + * Returns true if the authority is properly formatted. An authority is the combination + * of hostname and port. A null authority value is considered invalid. + * Note: this implementation validates the domain unless a RegexValidator was provided. + * If a RegexValidator was supplied and it matches, then the authority is regarded + * as valid with no further checks, otherwise the method checks against the + * AUTHORITY_PATTERN and the DomainValidator (ALLOW_LOCAL_URLS) + * @param authority Authority value to validate, alllows IDN + * @return true if authority (hostname and port) is valid. + */ + protected boolean isValidAuthority(String authority) { + if (authority == null) { + return false; + } + + // check manual authority validation if specified + if (authorityValidator != null && authorityValidator.isValid(authority)) { + return true; + } + // convert to ASCII if possible + final String authorityASCII = DomainValidator.unicodeToASCII(authority); + + Matcher authorityMatcher = AUTHORITY_PATTERN.matcher(authorityASCII); + if (!authorityMatcher.matches()) { + return false; + } + + // We have to process IPV6 separately because that is parsed in a different group + String ipv6 = authorityMatcher.group(PARSE_AUTHORITY_IPV6); + if (ipv6 != null) { + InetAddressValidator inetAddressValidator = InetAddressValidator.getInstance(); + if (!inetAddressValidator.isValidInet6Address(ipv6)) { + return false; + } + } else { + String hostLocation = authorityMatcher.group(PARSE_AUTHORITY_HOST_IP); + // check if authority is hostname or IP address: + // try a hostname first since that's much more likely + DomainValidator domainValidator = DomainValidator.getInstance(isOn(ALLOW_LOCAL_URLS)); + if (!domainValidator.isValid(hostLocation)) { + // try an IPv4 address + InetAddressValidator inetAddressValidator = InetAddressValidator.getInstance(); + if (!inetAddressValidator.isValidInet4Address(hostLocation)) { + // isn't IPv4, so the URL is invalid + return false; + } + } + String port = authorityMatcher.group(PARSE_AUTHORITY_PORT); + if (port != null && port.length() > 0) { + try { + int iPort = Integer.parseInt(port); + if (iPort < 0 || iPort > MAX_UNSIGNED_16_BIT_INT) { + return false; + } + } catch (NumberFormatException nfe) { + return false; // this can happen for big numbers + } + } + } + + String extra = authorityMatcher.group(PARSE_AUTHORITY_EXTRA); + if (extra != null && extra.trim().length() > 0){ + return false; + } + + return true; + } + + /** + * Returns true if the path is valid. A null value is considered invalid. + * @param path Path value to validate. + * @return true if path is valid. + */ + protected boolean isValidPath(String path) { + if (path == null) { + return false; + } + + if (!PATH_PATTERN.matcher(path).matches()) { + return false; + } + + try { + URI uri = new URI(null,null,path,null); + String norm = uri.normalize().getPath(); + if (norm.startsWith("/../") // Trying to go via the parent dir + || norm.equals("/..")) { // Trying to go to the parent dir + return false; + } + } catch (URISyntaxException e) { + return false; + } + + int slash2Count = countToken("//", path); + if (isOff(ALLOW_2_SLASHES) && (slash2Count > 0)) { + return false; + } + + return true; + } + + /** + * Returns true if the query is null or it's a properly formatted query string. + * @param query Query value to validate. + * @return true if query is valid. + */ + protected boolean isValidQuery(String query) { + if (query == null) { + return true; + } + + return QUERY_PATTERN.matcher(query).matches(); + } + + /** + * Returns true if the given fragment is null or fragments are allowed. + * @param fragment Fragment value to validate. + * @return true if fragment is valid. + */ + protected boolean isValidFragment(String fragment) { + if (fragment == null) { + return true; + } + + return isOff(NO_FRAGMENTS); + } + + /** + * Returns the number of times the token appears in the target. + * @param token Token value to be counted. + * @param target Target value to count tokens in. + * @return the number of tokens. + */ + protected int countToken(String token, String target) { + int tokenIndex = 0; + int count = 0; + while (tokenIndex != -1) { + tokenIndex = target.indexOf(token, tokenIndex); + if (tokenIndex > -1) { + tokenIndex++; + count++; + } + } + return count; + } + + /** + * Tests whether the given flag is on. If the flag is not a power of 2 + * (ie. 3) this tests whether the combination of flags is on. + * + * @param flag Flag value to check. + * + * @return whether the specified flag value is on. + */ + private boolean isOn(long flag) { + return (options & flag) > 0; + } + + /** + * Tests whether the given flag is off. If the flag is not a power of 2 + * (ie. 3) this tests whether the combination of flags is off. + * + * @param flag Flag value to check. + * + * @return whether the specified flag value is off. + */ + private boolean isOff(long flag) { + return (options & flag) == 0; + } + + // Unit test access to pattern matcher + Matcher matchURL(String value) { + return URL_PATTERN.matcher(value); + } +} diff --git a/core/src/main/java/jenkins/security/ClassFilterImpl.java b/core/src/main/java/jenkins/security/ClassFilterImpl.java index 5fb8dccf40..df179e7258 100644 --- a/core/src/main/java/jenkins/security/ClassFilterImpl.java +++ b/core/src/main/java/jenkins/security/ClassFilterImpl.java @@ -229,12 +229,12 @@ public class ClassFilterImpl extends ClassFilter { LOGGER.log(Level.WARNING, "problem checking " + loc, x); } } - if (loc.endsWith("/target/classes/")) { + if (loc.endsWith("/target/classes/") || loc.matches(".+/build/classes/[^/]+/main/")) { LOGGER.log(Level.FINE, "{0} seems to be current plugin classes, OK", loc); return true; } if (Main.isUnitTest) { - if (loc.endsWith("/target/test-classes/") || loc.endsWith("-tests.jar")) { + if (loc.endsWith("/target/test-classes/") || loc.endsWith("-tests.jar") || loc.matches(".+/build/classes/[^/]+/test/")) { LOGGER.log(Level.FINE, "{0} seems to be test classes, OK", loc); return true; } diff --git a/core/src/main/java/jenkins/security/QueueItemAuthenticatorConfiguration.java b/core/src/main/java/jenkins/security/QueueItemAuthenticatorConfiguration.java index 7a2ef81427..df85943f26 100644 --- a/core/src/main/java/jenkins/security/QueueItemAuthenticatorConfiguration.java +++ b/core/src/main/java/jenkins/security/QueueItemAuthenticatorConfiguration.java @@ -35,7 +35,7 @@ public class QueueItemAuthenticatorConfiguration extends GlobalConfiguration { } @Override - public GlobalConfigurationCategory getCategory() { + public @Nonnull GlobalConfigurationCategory getCategory() { return GlobalConfigurationCategory.get(GlobalConfigurationCategory.Security.class); } @@ -61,8 +61,8 @@ public class QueueItemAuthenticatorConfiguration extends GlobalConfiguration { } } - public static QueueItemAuthenticatorConfiguration get() { - return Jenkins.getInstance().getInjector().getInstance(QueueItemAuthenticatorConfiguration.class); + public static @Nonnull QueueItemAuthenticatorConfiguration get() { + return GlobalConfiguration.all().getInstance(QueueItemAuthenticatorConfiguration.class); } @Extension(ordinal = 100) diff --git a/core/src/main/java/jenkins/security/UpdateSiteWarningsConfiguration.java b/core/src/main/java/jenkins/security/UpdateSiteWarningsConfiguration.java index a8295d8b75..8ea916bab4 100644 --- a/core/src/main/java/jenkins/security/UpdateSiteWarningsConfiguration.java +++ b/core/src/main/java/jenkins/security/UpdateSiteWarningsConfiguration.java @@ -55,7 +55,7 @@ public class UpdateSiteWarningsConfiguration extends GlobalConfiguration { private HashSet ignoredWarnings = new HashSet<>(); @Override - public GlobalConfigurationCategory getCategory() { + public @Nonnull GlobalConfigurationCategory getCategory() { return GlobalConfigurationCategory.get(GlobalConfigurationCategory.Security.class); } @@ -77,14 +77,14 @@ public class UpdateSiteWarningsConfiguration extends GlobalConfiguration { if (warning.type != UpdateSite.Warning.Type.PLUGIN) { return null; } - return Jenkins.getInstance().getPluginManager().getPlugin(warning.component); + return Jenkins.get().getPluginManager().getPlugin(warning.component); } @Nonnull public Set getAllWarnings() { HashSet allWarnings = new HashSet<>(); - for (UpdateSite site : Jenkins.getInstance().getUpdateCenter().getSites()) { + for (UpdateSite site : Jenkins.get().getUpdateCenter().getSites()) { UpdateSite.Data data = site.getData(); if (data != null) { allWarnings.addAll(data.getWarnings()); diff --git a/core/src/main/java/jenkins/security/csrf/CSRFAdministrativeMonitor.java b/core/src/main/java/jenkins/security/csrf/CSRFAdministrativeMonitor.java index dbdb38e337..6ffc2422e4 100644 --- a/core/src/main/java/jenkins/security/csrf/CSRFAdministrativeMonitor.java +++ b/core/src/main/java/jenkins/security/csrf/CSRFAdministrativeMonitor.java @@ -46,6 +46,6 @@ public class CSRFAdministrativeMonitor extends AdministrativeMonitor { @Override public boolean isActivated() { - return Jenkins.getInstance().getCrumbIssuer() == null; + return Jenkins.get().getCrumbIssuer() == null; } } diff --git a/core/src/main/java/jenkins/security/s2m/ConfigFile.java b/core/src/main/java/jenkins/security/s2m/ConfigFile.java index f52b64d370..99b8c5f975 100644 --- a/core/src/main/java/jenkins/security/s2m/ConfigFile.java +++ b/core/src/main/java/jenkins/security/s2m/ConfigFile.java @@ -50,7 +50,7 @@ abstract class ConfigFile> extends TextFile { /** * Loads the configuration from the configuration file. * @throws IOException if the configuration file could not be read. - * @since TODO + * @since 2.111 */ public synchronized void load2() throws IOException { COL result = create(); diff --git a/core/src/main/java/jenkins/security/s2m/MasterKillSwitchConfiguration.java b/core/src/main/java/jenkins/security/s2m/MasterKillSwitchConfiguration.java index 3a1e2b063d..66e20fdd22 100644 --- a/core/src/main/java/jenkins/security/s2m/MasterKillSwitchConfiguration.java +++ b/core/src/main/java/jenkins/security/s2m/MasterKillSwitchConfiguration.java @@ -1,6 +1,8 @@ package jenkins.security.s2m; import hudson.Extension; + +import javax.annotation.Nonnull; import javax.inject.Inject; import jenkins.model.GlobalConfiguration; import jenkins.model.GlobalConfigurationCategory; @@ -23,7 +25,7 @@ public class MasterKillSwitchConfiguration extends GlobalConfiguration { Jenkins jenkins; @Override - public GlobalConfigurationCategory getCategory() { + public @Nonnull GlobalConfigurationCategory getCategory() { return GlobalConfigurationCategory.get(GlobalConfigurationCategory.Security.class); } diff --git a/core/src/main/java/jenkins/slaves/RemotingVersionInfo.java b/core/src/main/java/jenkins/slaves/RemotingVersionInfo.java index 2c89ec136e..d1e0c06e4b 100644 --- a/core/src/main/java/jenkins/slaves/RemotingVersionInfo.java +++ b/core/src/main/java/jenkins/slaves/RemotingVersionInfo.java @@ -32,11 +32,10 @@ import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; -// TODO: Make the API public (JENKINS-48766) /** * Provides information about Remoting versions used within the core. * @author Oleg Nenashev - * @since TODO + * @since unrestricted since 2.104, initially added in 2.100. */ public class RemotingVersionInfo { diff --git a/core/src/main/java/jenkins/tools/ToolConfigurationCategory.java b/core/src/main/java/jenkins/tools/ToolConfigurationCategory.java index e785369556..5c6d6ce695 100644 --- a/core/src/main/java/jenkins/tools/ToolConfigurationCategory.java +++ b/core/src/main/java/jenkins/tools/ToolConfigurationCategory.java @@ -2,6 +2,7 @@ package jenkins.tools; import hudson.Extension; import jenkins.model.GlobalConfigurationCategory; +import jenkins.management.Messages; /** * Global configuration of tool locations and installers. @@ -12,10 +13,10 @@ import jenkins.model.GlobalConfigurationCategory; public class ToolConfigurationCategory extends GlobalConfigurationCategory { @Override public String getShortDescription() { - return jenkins.management.Messages.ConfigureTools_Description(); + return Messages.ConfigureTools_Description(); } public String getDisplayName() { - return jenkins.management.Messages.ConfigureTools_DisplayName(); + return Messages.ConfigureTools_DisplayName(); } } diff --git a/core/src/main/java/jenkins/util/UrlHelper.java b/core/src/main/java/jenkins/util/UrlHelper.java new file mode 100644 index 0000000000..a71e592304 --- /dev/null +++ b/core/src/main/java/jenkins/util/UrlHelper.java @@ -0,0 +1,64 @@ +/* + * The MIT License + * + * Copyright (c) 2018, CloudBees, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package jenkins.util; + +import jenkins.org.apache.commons.validator.routines.DomainValidator; +import jenkins.org.apache.commons.validator.routines.UrlValidator; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; + +@Restricted(NoExternalUse.class) +public class UrlHelper { + /** + * Authorize the {@code _} and {@code -} characters in domain + *

+ * Avoid {@code -} and {@code .} to be first or last + */ + private static String DOMAIN_REGEX = System.getProperty( + UrlHelper.class.getName() + ".DOMAIN_REGEX", + "(\\w(\\.?-?\\w+)*)(:\\d{1,5})?" + ); + + public static boolean isValidRootUrl(String url) { + UrlValidator validator = new CustomUrlValidator(); + return validator.isValid(url); + } + + private static class CustomUrlValidator extends UrlValidator { + private CustomUrlValidator() { + super(new String[]{"http", "https"}, UrlValidator.ALLOW_LOCAL_URLS + UrlValidator.NO_FRAGMENTS); + } + + @Override + protected boolean isValidAuthority(String authority) { + // to support ipv6 + boolean superResult = super.isValidAuthority(authority); + if(!superResult && authority == null){ + return false; + } + String authorityASCII = DomainValidator.unicodeToASCII(authority); + return authorityASCII.matches(DOMAIN_REGEX); + } + } +} diff --git a/core/src/main/java/jenkins/util/VirtualFile.java b/core/src/main/java/jenkins/util/VirtualFile.java index e59ad888bd..c1ea07d536 100644 --- a/core/src/main/java/jenkins/util/VirtualFile.java +++ b/core/src/main/java/jenkins/util/VirtualFile.java @@ -148,7 +148,7 @@ public abstract class VirtualFile implements Comparable, Serializab * Some implementations may not support symlinks under any conditions. * @return a target (typically a relative path in some format), or null if this is not a link * @throws IOException if reading the link, or even determining whether this file is a link, failed - * @since FIXME + * @since 2.118 */ @Restricted(Beta.class) public @CheckForNull String readLink() throws IOException { @@ -188,7 +188,7 @@ public abstract class VirtualFile implements Comparable, Serializab * @param useDefaultExcludes as per {@link AbstractFileSet#setDefaultexcludes} * @return a list of {@code /}-separated relative names of children (files directly inside or in subdirectories) * @throws IOException if this is not a directory, or listing was not possible for some other reason - * @since FIXME + * @since 2.118 */ @Restricted(Beta.class) public @Nonnull Collection list(@Nonnull String includes, @CheckForNull String excludes, boolean useDefaultExcludes) throws IOException { @@ -266,7 +266,7 @@ public abstract class VirtualFile implements Comparable, Serializab * If the file is symlink (see {@link #readLink}), the mode is that of the link target, not the link itself. * @return for example, 0644 ~ {@code rw-r--r--}; -1 by default, meaning unknown or inapplicable * @throws IOException if checking the mode failed - * @since FIXME + * @since 2.118 */ @Restricted(Beta.class) public int mode() throws IOException { @@ -345,7 +345,7 @@ public abstract class VirtualFile implements Comparable, Serializab *

The URL might be valid for only a limited amount of time or even only a single use; * this method should be called anew every time an external URL is required. * @return an externally usable URL like {@code https://gist.githubusercontent.com/ACCT/GISTID/raw/COMMITHASH/FILE}, or null if there is no such support - * @since FIXME + * @since 2.118 * @see #toURI */ @Restricted(Beta.class) diff --git a/core/src/main/java/jenkins/util/io/LinesStream.java b/core/src/main/java/jenkins/util/io/LinesStream.java index d0296ddf0a..92931c4ccd 100644 --- a/core/src/main/java/jenkins/util/io/LinesStream.java +++ b/core/src/main/java/jenkins/util/io/LinesStream.java @@ -58,7 +58,7 @@ import javax.annotation.Nullable; * obtain a second or subsequent Iterator throws * IllegalStateException. * - * @since TODO + * @since 2.111 */ @CleanupObligation public class LinesStream implements Closeable, Iterable { diff --git a/core/src/main/resources/hudson/logging/LogRecorderManager/levels_de.properties b/core/src/main/resources/hudson/logging/LogRecorderManager/levels_de.properties index 67c63809ce..6917971793 100644 --- a/core/src/main/resources/hudson/logging/LogRecorderManager/levels_de.properties +++ b/core/src/main/resources/hudson/logging/LogRecorderManager/levels_de.properties @@ -23,7 +23,7 @@ Logger\ Configuration=Logger-Konfiguration url=https://jenkins.io/redirect/log-levels Name=Name -Level=Priorit\uFFFDt -Adjust\ Levels=Priorit\uFFFDten (levels) anpassen -defaultLoggerMsg=Der Logger ohne Namen ist der Default-Logger. Seine Priorit\uFFFDt \ - wird von allen Loggern \uFFFDbernommen, f\uFFFDr die keine Priorit\uFFFDt explizit angegeben wurde. \ No newline at end of file +Level=Priorit\u00e4t +Adjust\ Levels=Priorit\u00e4ten (levels) anpassen +defaultLoggerMsg=Der Logger ohne Namen ist der Default-Logger. Seine Priorit\u00e4t \ + wird von allen Loggern \u00fcbernommen, f\u00fcr die keine Priorit\u00e4t explizit angegeben wurde. \ No newline at end of file diff --git a/core/src/main/resources/hudson/logging/LogRecorderManager/levels_es.properties b/core/src/main/resources/hudson/logging/LogRecorderManager/levels_es.properties index 3aa52ced12..b0619b2434 100644 --- a/core/src/main/resources/hudson/logging/LogRecorderManager/levels_es.properties +++ b/core/src/main/resources/hudson/logging/LogRecorderManager/levels_es.properties @@ -22,8 +22,8 @@ url=https://jenkins.io/redirect/log-levels Level=Nivel de log -Logger\ Configuration=Configuraci\uFFFDn del logger +Logger\ Configuration=Configuraci\u00f3n del logger Name=Nombre defaultLoggerMsg=Por defecto se usa un Logger sin mombre. \ - Este nivel ser\uFFFD heredado por todos los loggers que no est\uFFFDn configurados con un nivel de log. + Este nivel ser\u00e0 heredado por todos los loggers que no est\u00e9n configurados con un nivel de log. Adjust\ Levels=Ajustar niveles de log. diff --git a/core/src/main/resources/hudson/logging/LogRecorderManager/levels_it.properties b/core/src/main/resources/hudson/logging/LogRecorderManager/levels_it.properties index 7e27373cde..e34d443d08 100644 --- a/core/src/main/resources/hudson/logging/LogRecorderManager/levels_it.properties +++ b/core/src/main/resources/hudson/logging/LogRecorderManager/levels_it.properties @@ -4,5 +4,5 @@ Adjust\ Levels=Regola livelli Level=Livello Logger\ Configuration=Configurazione registro Name=Nome -defaultLoggerMsg=Il registro senza nome \uFFFD quello predefinito. Questo livello sar\uFFFD ereditato da tutti i registri senza un livello configurato. +defaultLoggerMsg=Il registro senza nome \u00e8 quello predefinito. Questo livello sar\u00e0 ereditato da tutti i registri senza un livello configurato. url=https://jenkins.io/redirect/log-levels diff --git a/core/src/main/resources/hudson/model/Computer/_api_zh_CN.properties b/core/src/main/resources/hudson/model/Computer/_api_zh_CN.properties new file mode 100644 index 0000000000..fe83665bdf --- /dev/null +++ b/core/src/main/resources/hudson/model/Computer/_api_zh_CN.properties @@ -0,0 +1,23 @@ +# The MIT License +# +# Copyright (c) 2018, suren +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +Load\ Statistics=\u8d1f\u8f7d\u7edf\u8ba1 diff --git a/core/src/main/resources/hudson/model/Computer/index_zh_CN.properties b/core/src/main/resources/hudson/model/Computer/index_zh_CN.properties index ecb166e08c..a6f6a29eff 100644 --- a/core/src/main/resources/hudson/model/Computer/index_zh_CN.properties +++ b/core/src/main/resources/hudson/model/Computer/index_zh_CN.properties @@ -1,6 +1,6 @@ # The MIT License # -# Copyright (c) 2004-2010, Sun Microsystems, Inc. +# Copyright (c) 2004-2018, Sun Microsystems, Inc, suren . # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -24,3 +24,5 @@ Labels:=\u6807\u7B7E None=\u65E0 submit.not.temporarilyOffline=\u4E34\u65F6\u65AD\u5F00\u6B64\u8282\u70B9 title.projects_tied_on=\u5173\u8054\u5230{0}\u7684\u9879\u76EE +submit.temporarilyOffline=\u4e0a\u7ebf\u8282\u70b9 +submit.updateOfflineCause=\u66f4\u65b0\u4e0b\u7ebf\u539f\u56e0 diff --git a/core/src/main/resources/hudson/model/Computer/markOffline_zh_CN.properties b/core/src/main/resources/hudson/model/Computer/markOffline_zh_CN.properties new file mode 100644 index 0000000000..99ee4b527e --- /dev/null +++ b/core/src/main/resources/hudson/model/Computer/markOffline_zh_CN.properties @@ -0,0 +1,25 @@ +# The MIT License +# +# Copyright (c) 2018, suren +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +title=\u8ba9 {0} \u4e0b\u7ebf +blurb=\u4f60\u53ef\u4ee5\u89e3\u91ca\u4f7f\u8be5\u8282\u70b9\u4e0b\u7ebf\u7684\u539f\u56e0\uff08\u975e\u5fc5\u586b\uff09\uff0c\u4ee5\u4fbf\u8ba9\u5176\u4ed6\u4eba\u4e86\u89e3\uff1a +submit=\u8ba9\u8be5\u8282\u70b9\u4e34\u65f6\u4e0b\u7ebf diff --git a/core/src/main/resources/hudson/model/Computer/setOfflineCause_zh_CN.properties b/core/src/main/resources/hudson/model/Computer/setOfflineCause_zh_CN.properties new file mode 100644 index 0000000000..d33512a105 --- /dev/null +++ b/core/src/main/resources/hudson/model/Computer/setOfflineCause_zh_CN.properties @@ -0,0 +1,25 @@ +# The MIT License +# +# Copyright (c) 2018, suren +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +title=\u8bbe\u7f6e {0} \u4e0b\u7ebf\u539f\u56e0 +blurb=\u4f60\u53ef\u4ee5\u8bbe\u7f6e\u6216\u8005\u66f4\u65b0\u8be5\u8282\u70b9\u4e0b\u7ebf\u7684\u539f\u56e0\uff0c\u4ee5\u4fbf\u8ba9\u5176\u4ed6\u4eba\u4e86\u89e3\uff1a +submit=\u66f4\u65b0\u539f\u56e0 diff --git a/core/src/main/resources/hudson/model/Computer/sidepanel_zh_CN.properties b/core/src/main/resources/hudson/model/Computer/sidepanel_zh_CN.properties index 0861540bb9..4757829803 100644 --- a/core/src/main/resources/hudson/model/Computer/sidepanel_zh_CN.properties +++ b/core/src/main/resources/hudson/model/Computer/sidepanel_zh_CN.properties @@ -1,6 +1,6 @@ # The MIT License # -# Copyright (c) 2004-2010, Sun Microsystems, Inc. +# Copyright (c) 2004-2018, Sun Microsystems, Inc, suren . # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -26,3 +26,4 @@ Configure=\u914D\u7F6E\u4ECE\u8282\u70B9 Load\ Statistics=\u8d1f\u8f7d\u7edf\u8ba1 Script\ Console=\u811a\u672c\u547d\u4ee4\u884c Status=\u72b6\u6001 +Delete\ Agent=\u5220\u9664\u8282\u70b9 diff --git a/core/src/main/resources/hudson/model/ComputerSet/_new_zh_CN.properties b/core/src/main/resources/hudson/model/ComputerSet/_new_zh_CN.properties index 79d34d46af..08b2b7be72 100644 --- a/core/src/main/resources/hudson/model/ComputerSet/_new_zh_CN.properties +++ b/core/src/main/resources/hudson/model/ComputerSet/_new_zh_CN.properties @@ -2,3 +2,4 @@ Name=\u540D\u5B57 Name\ is\ mandatory=\u540D\u79F0\uFF08\u5FC5\u586B\uFF09 +Save=\u4fdd\u5b58 diff --git a/core/src/main/resources/hudson/model/ComputerSet/index_zh_CN.properties b/core/src/main/resources/hudson/model/ComputerSet/index_zh_CN.properties index 25d63958ff..ca6e959922 100644 --- a/core/src/main/resources/hudson/model/ComputerSet/index_zh_CN.properties +++ b/core/src/main/resources/hudson/model/ComputerSet/index_zh_CN.properties @@ -1,6 +1,6 @@ # The MIT License # -# Copyright (c) 2004-2010, Sun Microsystems, Inc. +# Copyright (c) 2004-2018, Sun Microsystems, Inc, suren . # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -20,6 +20,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. +Nodes=\u8282\u70b9\u5217\u8868 Configure=\u8BBE\u7F6E Data\ obtained=\u83B7\u53D6\u5230\u7684\u6570\u636E Name=\u540D\u79F0 diff --git a/core/src/main/resources/hudson/model/ComputerSet/sidepanel_zh_CN.properties b/core/src/main/resources/hudson/model/ComputerSet/sidepanel_zh_CN.properties index c823d04e2c..0b167ecd6d 100644 --- a/core/src/main/resources/hudson/model/ComputerSet/sidepanel_zh_CN.properties +++ b/core/src/main/resources/hudson/model/ComputerSet/sidepanel_zh_CN.properties @@ -1,6 +1,6 @@ # The MIT License # -# Copyright (c) 2004-2010, Sun Microsystems, Inc. +# Copyright (c) 2004-2018, Sun Microsystems, Inc, suren . # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -20,7 +20,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Back\ to\ Dashboard=\u8fd4\u56de +Back\ to\ Dashboard=\u8fd4\u56de\u5de5\u4f5c\u53f0 Manage\ Jenkins=\u7cfb\u7edf\u7ba1\u7406 Configure=\u914D\u7F6E New\ Node=\u65b0\u5efa\u8282\u70b9 diff --git a/core/src/main/resources/hudson/slaves/ComputerLauncher/main_zh_CN.properties b/core/src/main/resources/hudson/slaves/ComputerLauncher/main_zh_CN.properties new file mode 100644 index 0000000000..9b685ac70c --- /dev/null +++ b/core/src/main/resources/hudson/slaves/ComputerLauncher/main_zh_CN.properties @@ -0,0 +1,26 @@ +# The MIT License +# +# Copyright (c) 2018 suren +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +launchingDescription=\u8be5\u8282\u70b9\u5df2\u7ecf\u542f\u52a8\u3002 +See\ log\ for\ more\ details=\u66f4\u591a\u4fe1\u606f\u8bf7\u67e5\u770b\u65e5\u5fd7 +Relaunch\ agent=\u91cd\u542f\u4ee3\u7406 +Launch\ agent=\u542f\u52a8\u4ee3\u7406 diff --git a/core/src/main/resources/hudson/slaves/DumbSlave/newInstanceDetail_zh_CN.properties b/core/src/main/resources/hudson/slaves/DumbSlave/newInstanceDetail_zh_CN.properties new file mode 100644 index 0000000000..f1e1f47dab --- /dev/null +++ b/core/src/main/resources/hudson/slaves/DumbSlave/newInstanceDetail_zh_CN.properties @@ -0,0 +1,25 @@ +# The MIT License +# +# Copyright (c) 2004-2018, Sun Microsystems, Inc., Kohsuke Kawaguchi, +# suren +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +detail=\ + \u6dfb\u52a0\u4e00\u4e2a\u666e\u901a\u3001\u56fa\u5b9a\u7684\u8282\u70b9\u5230Jenkins\u3002\u4e4b\u6240\u4ee5\u53eb\u505a\u201c\u56fa\u5b9a\u201d\uff0c\u662f\u56e0\u4e3aJenkins\u6ca1\u7ed9\u8fd9\u79cd\u8282\u70b9\u63d0\u4f9b\u66f4\u9ad8\u7ea7\u7684\u96c6\u6210\u65b9\u5f0f\uff0c\u4f8b\u5982\uff1a\u52a8\u6001\u914d\u7f6e\u3002\u6ca1\u6709\u5176\u4ed6\u7c7b\u578b\u80fd\u9009\u62e9\u7684\u8bdd\u53ef\u4ee5\u9009\u62e9\u8be5\u7c7b\u578b\uff1b\u4f8b\u5982\uff0c\u4f60\u5728\u6dfb\u52a0\u4e0d\u53d7Jenkins\u7ba1\u7406\u7684\u7269\u7406\u673a\u3001\u865a\u62df\u673a\u7b49\u7b49\u3002 diff --git a/core/src/main/resources/hudson/slaves/JNLPLauncher/config_zh_CN.properties b/core/src/main/resources/hudson/slaves/JNLPLauncher/config_zh_CN.properties new file mode 100644 index 0000000000..feb6df4894 --- /dev/null +++ b/core/src/main/resources/hudson/slaves/JNLPLauncher/config_zh_CN.properties @@ -0,0 +1,24 @@ +# The MIT License +# +# Copyright (c) 2018, suren +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +JVM\ options=JVM \u9009\u9879 +Tunnel\ connection\ through=Tunnel \u8fde\u63a5\u4f4d\u7f6e diff --git a/core/src/main/resources/hudson/slaves/JNLPLauncher/help-vmargs_zh_CN.html b/core/src/main/resources/hudson/slaves/JNLPLauncher/help-vmargs_zh_CN.html new file mode 100644 index 0000000000..7ea86c5025 --- /dev/null +++ b/core/src/main/resources/hudson/slaves/JNLPLauncher/help-vmargs_zh_CN.html @@ -0,0 +1,5 @@ +

+ 如果代理的Java虚拟机启动时需要附加参数,例如 "-Xmx256m",可以在这里设置。 + 这里 + 列出了所有可用的参数。 +
\ No newline at end of file diff --git a/core/src/main/resources/hudson/slaves/JNLPLauncher/main_zh_CN.properties b/core/src/main/resources/hudson/slaves/JNLPLauncher/main_zh_CN.properties index 1f1a4b8bdc..cf34147ccd 100644 --- a/core/src/main/resources/hudson/slaves/JNLPLauncher/main_zh_CN.properties +++ b/core/src/main/resources/hudson/slaves/JNLPLauncher/main_zh_CN.properties @@ -1,6 +1,6 @@ # The MIT License # -# Copyright (c) 2004-2010, Sun Microsystems, Inc. +# Copyright (c) 2004-2018, Sun Microsystems, Inc, suren . # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -20,4 +20,11 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. +slaveAgentPort.disabled=\u4ece\u8282\u70b9\u7aef\u53e3\u88ab\u7981\u7528 +configure.link.text=\u914d\u7f6e\u94fe\u63a5 +Connect\ agent\ to\ Jenkins\ one\ of\ these\ ways\:=\u8282\u70b9\u8fde\u63a5Jenkins\u7684\u65b9\u5f0f\u5982\u4e0b\uff1a +launch\ agent=\u542f\u52a8\u8282\u70b9 +Launch\ agent\ from\ browser=\u5728\u6d4f\u89c8\u5668\u4e2d\u542f\u52a8\u8282\u70b9 +Run\ from\ agent\ command\ line\:=\u5728\u547d\u4ee4\u884c\u4e2d\u542f\u52a8\u8282\u70b9 +Or\ if\ the\ agent\ is\ headless\:=\u6216\u8005\uff0c\u5f53\u8282\u70b9\u662f\u65e0\u754c\u9762\u7684\u8bdd Connected\ via\ JNLP\ agent.=\u5DF2\u901A\u8FC7JNLP Agent\u8FDE\u63A5 diff --git a/core/src/main/resources/hudson/slaves/Messages_zh_CN.properties b/core/src/main/resources/hudson/slaves/Messages_zh_CN.properties index c8ef214cd4..3c136db31f 100644 --- a/core/src/main/resources/hudson/slaves/Messages_zh_CN.properties +++ b/core/src/main/resources/hudson/slaves/Messages_zh_CN.properties @@ -28,7 +28,7 @@ JNLPLauncher.displayName=\u901A\u8FC7Java Web\u542F\u52A8\u4EE3\u7406 ComputerLauncher.unexpectedError=\u542F\u52A8\u4EE3\u7406\u662F\u51FA\u73B0\u4F4D\u7F6E\u9519\u8BEF\u3002\u8FD9\u53EF\u80FD\u662FJenkins\u7684\u95EE\u9898\u3002 ComputerLauncher.abortedLaunch=\u4EE3\u7406\u542F\u52A8\u8FC7\u7A0B\u88AB\u4E2D\u6B62\u3002 CommandLauncher.NoLaunchCommand=\u6CA1\u6709\u6307\u5B9A\u542F\u52A8\u547D\u4EE4 -DumbSlave.displayName=\u56FA\u5B9A\u4EE3\u7406 +DumbSlave.displayName=\u56fa\u5b9a\u8282\u70b9 NodeProvisioner.EmptyString= OfflineCause.LaunchFailed=\u7531\u4E8E\u4EE3\u7406\u542F\u52A8\u8FC7\u7A0B\u5931\u8D25\u5BFC\u81F4\u7684\u79BB\u7EBF\u3002 OfflineCause.connection_was_broken_=\u8FDE\u63A5\u65AD\u5F00\uFF1A{0} diff --git a/core/src/main/resources/jenkins/diagnostics/Messages.properties b/core/src/main/resources/jenkins/diagnostics/Messages.properties index 38362ae234..6eb87fc358 100644 --- a/core/src/main/resources/jenkins/diagnostics/Messages.properties +++ b/core/src/main/resources/jenkins/diagnostics/Messages.properties @@ -1,3 +1,4 @@ CompletedInitializationMonitor.DisplayName=Jenkins Initialization Monitor SecurityIsOffMonitor.DisplayName=Disabled Security URICheckEncodingMonitor.DisplayName=Check URI Encoding +RootUrlNotSetMonitor.DisplayName=Root URL not configured Monitor diff --git a/core/src/main/resources/jenkins/diagnostics/RootUrlNotSetMonitor/message.jelly b/core/src/main/resources/jenkins/diagnostics/RootUrlNotSetMonitor/message.jelly new file mode 100644 index 0000000000..13d15b4cdd --- /dev/null +++ b/core/src/main/resources/jenkins/diagnostics/RootUrlNotSetMonitor/message.jelly @@ -0,0 +1,45 @@ + + + +
+
+ + + + ${%actionUrlContent} + + + + + ${%urlIsNull} + + + ${%urlIsInvalid} + + +

+ +

+
diff --git a/core/src/main/resources/jenkins/diagnostics/RootUrlNotSetMonitor/message.properties b/core/src/main/resources/jenkins/diagnostics/RootUrlNotSetMonitor/message.properties new file mode 100644 index 0000000000..d1153159c7 --- /dev/null +++ b/core/src/main/resources/jenkins/diagnostics/RootUrlNotSetMonitor/message.properties @@ -0,0 +1,6 @@ +urlIsNull=Jenkins root URL is empty but is required for the proper operation of many Jenkins features like email notifications, \ +PR status update, and environment variables such as BUILD_URL. +urlIsInvalid=Jenkins root URL seems to be invalid. It is required for the proper operation of many Jenkins features like email notifications, \ +PR status update, and environment variables such as BUILD_URL. +actionToTake=Please provide an accurate value in {0}. +actionUrlContent=Jenkins configuration diff --git a/core/src/main/resources/jenkins/install/Messages.properties b/core/src/main/resources/jenkins/install/Messages.properties new file mode 100644 index 0000000000..52b1b94367 --- /dev/null +++ b/core/src/main/resources/jenkins/install/Messages.properties @@ -0,0 +1,24 @@ +# The MIT License +# +# Copyright 2018 CloudBees, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +SetupWizard_ConfigureInstance_ValidationErrors=Some settings are invalid. See the error messages for details. +SetupWizard_ConfigureInstance_RootUrl_Empty=The URL cannot be empty +SetupWizard_ConfigureInstance_RootUrl_Invalid=The URL is invalid, please ensure you are using http:// or https:// with a valid domain. diff --git a/core/src/main/resources/jenkins/install/SetupWizard/setupWizardConfigureInstance.jelly b/core/src/main/resources/jenkins/install/SetupWizard/setupWizardConfigureInstance.jelly new file mode 100644 index 0000000000..0a0b2f5b69 --- /dev/null +++ b/core/src/main/resources/jenkins/install/SetupWizard/setupWizardConfigureInstance.jelly @@ -0,0 +1,122 @@ + + + + + + + + + +
+
+

${%Instance Configuration}

+
+ + + + + + + + +
+ +
+
+
${%jenkinsURL_help}
+
+
+ +
+
+
+
+
diff --git a/core/src/main/resources/jenkins/install/SetupWizard/setupWizardConfigureInstance.properties b/core/src/main/resources/jenkins/install/SetupWizard/setupWizardConfigureInstance.properties new file mode 100644 index 0000000000..4d08f82ba2 --- /dev/null +++ b/core/src/main/resources/jenkins/install/SetupWizard/setupWizardConfigureInstance.properties @@ -0,0 +1,6 @@ +Instance\ Configuration=Instance Configuration +Jenkins\ URL=Jenkins URL +jenkinsURL_help=The Jenkins URL is used to provide the root URL for absolute links to various Jenkins resources. \ +That means this value is required for proper operation of many Jenkins features including email notifications, PR status updates, and the BUILD_URL environment variable provided to build steps.
\ +The proposed default value shown is not saved yet and is generated from the current request, if possible. \ +The best practice is to set this value to the URL that users are expected to use. This will avoid confusion when sharing or viewing links. diff --git a/core/src/main/resources/jenkins/install/SetupWizard/setupWizardConfigureInstance_fr.properties b/core/src/main/resources/jenkins/install/SetupWizard/setupWizardConfigureInstance_fr.properties new file mode 100644 index 0000000000..7c8aae3d61 --- /dev/null +++ b/core/src/main/resources/jenkins/install/SetupWizard/setupWizardConfigureInstance_fr.properties @@ -0,0 +1,2 @@ +Instance\ Configuration=Configuration de l''instance +Jenkins\ URL=Jenkins URL diff --git a/core/src/main/resources/jenkins/install/SetupWizard/setupWizardFirstUser.jelly b/core/src/main/resources/jenkins/install/SetupWizard/setupWizardFirstUser.jelly index 788b353a9e..96e972b9ca 100644 --- a/core/src/main/resources/jenkins/install/SetupWizard/setupWizardFirstUser.jelly +++ b/core/src/main/resources/jenkins/install/SetupWizard/setupWizardFirstUser.jelly @@ -7,7 +7,7 @@