view mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialUrlSupport.java @ 960:1aaf8dba4072

fixing TW-48788 for the case of SSH url
author Pavel.Sher
date Tue, 21 Feb 2017 18:22:37 +0100
parents 9e67a769bcc1
children 0a31f12174ca 38adef4f1b8f
line wrap: on
line source
/*
 * Copyright 2000-2014 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package jetbrains.buildServer.buildTriggers.vcs.mercurial;

import jetbrains.buildServer.http.HttpUtil;
import jetbrains.buildServer.log.Loggers;
import jetbrains.buildServer.vcs.*;
import jetbrains.buildServer.vcs.impl.VcsRootImpl;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpState;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.GetMethod;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.net.URL;
import java.util.HashMap;
import java.util.Map;

public class MercurialUrlSupport implements UrlSupport {

  private final MercurialVcsSupport myVcsSupport;

  public MercurialUrlSupport(@NotNull MercurialVcsSupport vcsSupport) {
    myVcsSupport = vcsSupport;
  }

  @Nullable
  public Map<String, String> convertToVcsRootProperties(@NotNull VcsUrl url) throws VcsException {
    String fetchUrl = url.getUrl();

    boolean testRequired = true;

    if (fetchUrl.startsWith("ssh://hg@bitbucket.org")) {
      testRequired = false; // definitely Mercurial
    } else {
      MavenVcsUrl mavenUrl = url.asMavenVcsUrl();
      if (mavenUrl != null && !"hg".equals(mavenUrl.getProviderSchema())) {
        return null;
      }

      if (mavenUrl != null) {
        fetchUrl = mavenUrl.getProviderSpecificPart();
        testRequired = false;
      }

      if (fetchUrl.startsWith("http")) {
        // check URL by sending HTTP request
        if (isMercurialRepository(fetchUrl, url.getCredentials())) {
          testRequired = false;
        }
      }
    }

    Map<String, String> res = new HashMap<>(myVcsSupport.getDefaultVcsProperties());
    res.put(Constants.REPOSITORY_PROP, fetchUrl);
    Credentials credentials = url.getCredentials();
    if (credentials != null) {
      res.put(Constants.USERNAME, credentials.getUsername());
      res.put(Constants.PASSWORD, credentials.getPassword());
    }

    if (testRequired) {
      try {
        TestConnectionSupport testConnectionSupport = myVcsSupport.getTestConnectionSupport();
        testConnectionSupport.testConnection(new VcsRootImpl(-1, res));
      } catch (VcsException e) {
        return null;
      }
    }

    return res;
  }

  private boolean isMercurialRepository(@NotNull String fetchUrl, @Nullable Credentials credentials) {
    String capabilitiesUrl = fetchUrl;
    if (capabilitiesUrl.endsWith("/")) {
      capabilitiesUrl += "?cmd=capabilities";
    } else {
      capabilitiesUrl += "/?cmd=capabilities";
    }

    HttpClient client = HttpUtil.createHttpClient(30);
    GetMethod get = new GetMethod(capabilitiesUrl);

    try {
      if (credentials != null) {
        URL url = new URL(fetchUrl);
        HttpState state = new HttpState();
        state.setCredentials(new AuthScope(url.getHost(), url.getPort()), new UsernamePasswordCredentials(credentials.getUsername(), credentials.getPassword()));
        client.setState(state);
      }

      // emulate HG command request
      get.addRequestHeader("Accept-Encoding", "identity");
      get.addRequestHeader("accept", "application/mercurial-0.1");
      get.addRequestHeader("user-agent", "mercurial/proto-1.0");

      int status = client.executeMethod(get);
      if (status == 200) {
        Header header = get.getResponseHeader("Content-Type");
        if (header == null || !"application/mercurial-0.1".equals(header.getValue())) {
          return false;
        }

        String text = get.getResponseBodyAsString();
        if (text.contains("unbundle=HG10GZ,HG10BZ")) {
          // looks like mercurial repo
          return true;
        }
      }

    } catch (Exception e) {
      Loggers.VCS.debug("Got error while sending HTTP request to " + capabilitiesUrl, e);
    } finally {
      get.releaseConnection();
    }

    return false;
  }
}