mirror of https://github.com/sbt/sbt.git
Drop OkHttp dependency
Ref https://github.com/sbt/sbt/issues/6912 Problem ------- There's apparently a security issue with OkHttp 3.x, which I am not really sure how applicable it is to our usage of OkHttp but it is there. Solution -------- Since most of OkHttp-specic usage within LM is for Apache Ivy downloading, I am going to drop this. Since `sbt.librarymanagement.Http.http` is a public API, I am substituting this with Apache HTTP backed implementation.
This commit is contained in:
parent
91bf2649b2
commit
76452e53ff
10
build.sbt
10
build.sbt
|
|
@ -89,6 +89,7 @@ val mimaSettings = Def settings (
|
||||||
"1.3.0",
|
"1.3.0",
|
||||||
"1.4.0",
|
"1.4.0",
|
||||||
"1.5.0",
|
"1.5.0",
|
||||||
|
"1.6.0",
|
||||||
) map (
|
) map (
|
||||||
version =>
|
version =>
|
||||||
organization.value %% moduleName.value % version
|
organization.value %% moduleName.value % version
|
||||||
|
|
@ -353,6 +354,15 @@ lazy val lmIvy = (project in file("ivy"))
|
||||||
"sbt.internal.librarymanagement.CustomPomParser.versionRangeFlag"
|
"sbt.internal.librarymanagement.CustomPomParser.versionRangeFlag"
|
||||||
),
|
),
|
||||||
exclude[MissingClassProblem]("sbt.internal.librarymanagement.FixedParser*"),
|
exclude[MissingClassProblem]("sbt.internal.librarymanagement.FixedParser*"),
|
||||||
|
exclude[MissingClassProblem]("sbt.internal.librarymanagement.ivyint.GigahorseUrlHandler*"),
|
||||||
|
exclude[MissingClassProblem]("sbt.internal.librarymanagement.JavaNetAuthenticator"),
|
||||||
|
exclude[MissingClassProblem]("sbt.internal.librarymanagement.CustomHttp*"),
|
||||||
|
exclude[DirectMissingMethodProblem]("sbt.internal.librarymanagement.IvySbt.http"),
|
||||||
|
exclude[DirectMissingMethodProblem]("sbt.internal.librarymanagement.IvySbt.this"),
|
||||||
|
exclude[DirectMissingMethodProblem]("sbt.librarymanagement.ivy.IvyPublisher.apply"),
|
||||||
|
exclude[DirectMissingMethodProblem](
|
||||||
|
"sbt.librarymanagement.ivy.IvyDependencyResolution.apply"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package sbt.librarymanagement
|
package sbt.librarymanagement
|
||||||
|
|
||||||
import gigahorse._, support.okhttp.Gigahorse
|
import gigahorse._, support.apachehttp.Gigahorse
|
||||||
import scala.concurrent.duration.DurationInt
|
import scala.concurrent.duration.DurationInt
|
||||||
|
|
||||||
object Http {
|
object Http {
|
||||||
|
|
|
||||||
|
|
@ -1,82 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2013 Square, Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package sbt.internal.librarymanagement;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.Authenticator.RequestorType;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.net.PasswordAuthentication;
|
|
||||||
import java.net.Proxy;
|
|
||||||
import java.util.List;
|
|
||||||
import okhttp3.Authenticator;
|
|
||||||
import okhttp3.Route;
|
|
||||||
import okhttp3.Request;
|
|
||||||
import okhttp3.Response;
|
|
||||||
import okhttp3.HttpUrl;
|
|
||||||
import okhttp3.Challenge;
|
|
||||||
import okhttp3.Credentials;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adapts java.net.Authenticator to Authenticator. Configure OkHttp to use
|
|
||||||
* java.net.Authenticator with OkHttpClient.Builder#authenticator or
|
|
||||||
* OkHttpClient.Builder#proxyAuthenticator(Authenticator).
|
|
||||||
*/
|
|
||||||
public final class JavaNetAuthenticator implements Authenticator {
|
|
||||||
@Override public Request authenticate(Route route, Response response) throws IOException {
|
|
||||||
List<Challenge> challenges = response.challenges();
|
|
||||||
Request request = response.request();
|
|
||||||
HttpUrl url = request.url();
|
|
||||||
boolean proxyAuthorization = response.code() == 407;
|
|
||||||
Proxy proxy = null;
|
|
||||||
if (route != null) {
|
|
||||||
proxy = route.proxy();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0, size = challenges.size(); i < size; i++) {
|
|
||||||
Challenge challenge = challenges.get(i);
|
|
||||||
if (!"Basic".equalsIgnoreCase(challenge.scheme())) continue;
|
|
||||||
|
|
||||||
PasswordAuthentication auth;
|
|
||||||
if (proxyAuthorization) {
|
|
||||||
InetSocketAddress proxyAddress = (InetSocketAddress) proxy.address();
|
|
||||||
auth = java.net.Authenticator.requestPasswordAuthentication(
|
|
||||||
proxyAddress.getHostName(), getConnectToInetAddress(proxy, url), proxyAddress.getPort(),
|
|
||||||
url.scheme(), challenge.realm(), challenge.scheme(), url.url(),
|
|
||||||
RequestorType.PROXY);
|
|
||||||
} else {
|
|
||||||
auth = java.net.Authenticator.requestPasswordAuthentication(
|
|
||||||
url.host(), getConnectToInetAddress(proxy, url), url.port(), url.scheme(),
|
|
||||||
challenge.realm(), challenge.scheme(), url.url(), RequestorType.SERVER);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (auth != null) {
|
|
||||||
String credential = Credentials.basic(auth.getUserName(), new String(auth.getPassword()));
|
|
||||||
return request.newBuilder()
|
|
||||||
.header(proxyAuthorization ? "Proxy-Authorization" : "Authorization", credential)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null; // No challenges were satisfied!
|
|
||||||
}
|
|
||||||
|
|
||||||
private InetAddress getConnectToInetAddress(Proxy proxy, HttpUrl url) throws IOException {
|
|
||||||
return (proxy != null && proxy.type() != Proxy.Type.DIRECT)
|
|
||||||
? ((InetSocketAddress) proxy.address()).getAddress()
|
|
||||||
: InetAddress.getByName(url.host());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
package sbt.internal.librarymanagement
|
|
||||||
|
|
||||||
import gigahorse.HttpClient
|
|
||||||
import okhttp3.{ JavaNetAuthenticator => _, _ }
|
|
||||||
import sbt.librarymanagement.Http
|
|
||||||
|
|
||||||
object CustomHttp {
|
|
||||||
private[this] def http0: HttpClient = Http.http
|
|
||||||
|
|
||||||
private[sbt] def defaultHttpClientBuilder: OkHttpClient.Builder = {
|
|
||||||
http0
|
|
||||||
.underlying[OkHttpClient]
|
|
||||||
.newBuilder()
|
|
||||||
.authenticator(new sbt.internal.librarymanagement.JavaNetAuthenticator)
|
|
||||||
.followRedirects(true)
|
|
||||||
.followSslRedirects(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
private[sbt] lazy val defaultHttpClient: OkHttpClient =
|
|
||||||
defaultHttpClientBuilder.build
|
|
||||||
}
|
|
||||||
|
|
@ -7,7 +7,6 @@ import java.io.File
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import java.util.concurrent.Callable
|
import java.util.concurrent.Callable
|
||||||
|
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
import org.apache.ivy.Ivy
|
import org.apache.ivy.Ivy
|
||||||
import org.apache.ivy.core.IvyPatternHelper
|
import org.apache.ivy.core.IvyPatternHelper
|
||||||
import org.apache.ivy.core.cache.{ CacheMetadataOptions, DefaultRepositoryCacheManager }
|
import org.apache.ivy.core.cache.{ CacheMetadataOptions, DefaultRepositoryCacheManager }
|
||||||
|
|
@ -50,17 +49,13 @@ import ivyint.{
|
||||||
CachedResolutionResolveEngine,
|
CachedResolutionResolveEngine,
|
||||||
ParallelResolveEngine,
|
ParallelResolveEngine,
|
||||||
SbtDefaultDependencyDescriptor,
|
SbtDefaultDependencyDescriptor,
|
||||||
GigahorseUrlHandler
|
|
||||||
}
|
}
|
||||||
import sjsonnew.JsonFormat
|
import sjsonnew.JsonFormat
|
||||||
import sjsonnew.support.murmurhash.Hasher
|
import sjsonnew.support.murmurhash.Hasher
|
||||||
|
|
||||||
final class IvySbt(
|
final class IvySbt(
|
||||||
val configuration: IvyConfiguration,
|
val configuration: IvyConfiguration,
|
||||||
val http: OkHttpClient
|
|
||||||
) { self =>
|
) { self =>
|
||||||
def this(configuration: IvyConfiguration) = this(configuration, CustomHttp.defaultHttpClient)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ========== Configuration/Setup ============
|
* ========== Configuration/Setup ============
|
||||||
* This part configures the Ivy instance by first creating the logger interface to ivy, then IvySettings, and then the Ivy instance.
|
* This part configures the Ivy instance by first creating the logger interface to ivy, then IvySettings, and then the Ivy instance.
|
||||||
|
|
@ -90,7 +85,6 @@ final class IvySbt(
|
||||||
}
|
}
|
||||||
|
|
||||||
private lazy val basicUrlHandler: URLHandler = new BasicURLHandler
|
private lazy val basicUrlHandler: URLHandler = new BasicURLHandler
|
||||||
private lazy val gigahorseUrlHandler: URLHandler = new GigahorseUrlHandler(http)
|
|
||||||
|
|
||||||
private lazy val settings: IvySettings = {
|
private lazy val settings: IvySettings = {
|
||||||
val dispatcher: URLHandlerDispatcher = URLHandlerRegistry.getDefault match {
|
val dispatcher: URLHandlerDispatcher = URLHandlerRegistry.getDefault match {
|
||||||
|
|
@ -106,8 +100,8 @@ final class IvySbt(
|
||||||
disp
|
disp
|
||||||
}
|
}
|
||||||
|
|
||||||
val urlHandler: URLHandler =
|
// Ignore configuration.updateOptions.gigahorse due to sbt/sbt#6912
|
||||||
if (configuration.updateOptions.gigahorse) gigahorseUrlHandler else basicUrlHandler
|
val urlHandler: URLHandler = basicUrlHandler
|
||||||
|
|
||||||
// Only set the urlHandler for the http/https protocols so we do not conflict with any other plugins
|
// Only set the urlHandler for the http/https protocols so we do not conflict with any other plugins
|
||||||
// that might register other protocol handlers.
|
// that might register other protocol handlers.
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,7 @@ class IvyCache(val ivyHome: Option[File]) {
|
||||||
.withResolvers(Vector(local))
|
.withResolvers(Vector(local))
|
||||||
.withLock(lock)
|
.withLock(lock)
|
||||||
.withLog(log)
|
.withLog(log)
|
||||||
(new IvySbt(conf, CustomHttp.defaultHttpClient), local)
|
(new IvySbt(conf), local)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creates a default jar artifact based on the given ID.*/
|
/** Creates a default jar artifact based on the given ID.*/
|
||||||
|
|
|
||||||
|
|
@ -1,339 +0,0 @@
|
||||||
package sbt.internal.librarymanagement
|
|
||||||
package ivyint
|
|
||||||
|
|
||||||
import java.net.{ URL, UnknownHostException }
|
|
||||||
import java.io._
|
|
||||||
|
|
||||||
import scala.util.control.NonFatal
|
|
||||||
|
|
||||||
import okhttp3.{ MediaType, Request, RequestBody }
|
|
||||||
import okhttp3.internal.http.HttpDate
|
|
||||||
|
|
||||||
import okhttp3.{ JavaNetAuthenticator => _, _ }
|
|
||||||
import okio._
|
|
||||||
|
|
||||||
import org.apache.ivy.util.{ CopyProgressEvent, CopyProgressListener, Message }
|
|
||||||
import org.apache.ivy.util.url.{ AbstractURLHandler, BasicURLHandler, IvyAuthenticator, URLHandler }
|
|
||||||
import org.apache.ivy.util.url.URLHandler._
|
|
||||||
import sbt.io.IO
|
|
||||||
|
|
||||||
// Copied from Ivy's BasicURLHandler.
|
|
||||||
class GigahorseUrlHandler(http: OkHttpClient) extends AbstractURLHandler {
|
|
||||||
|
|
||||||
import GigahorseUrlHandler._
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the URLInfo of the given url or a #UNAVAILABLE instance,
|
|
||||||
* if the url is not reachable.
|
|
||||||
*/
|
|
||||||
def getURLInfo(url: URL): URLInfo = getURLInfo(url, 0)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the URLInfo of the given url or a #UNAVAILABLE instance,
|
|
||||||
* if the url is not reachable.
|
|
||||||
*/
|
|
||||||
def getURLInfo(url0: URL, timeout: Int): URLInfo = {
|
|
||||||
// Install the ErrorMessageAuthenticator
|
|
||||||
if ("http" == url0.getProtocol || "https" == url0.getProtocol) {
|
|
||||||
IvyAuthenticator.install()
|
|
||||||
ErrorMessageAuthenticator.install()
|
|
||||||
}
|
|
||||||
|
|
||||||
val url = normalizeToURL(url0)
|
|
||||||
val request = new Request.Builder()
|
|
||||||
.url(url)
|
|
||||||
|
|
||||||
if (getRequestMethod == URLHandler.REQUEST_METHOD_HEAD) request.head() else request.get()
|
|
||||||
|
|
||||||
val response = http.newCall(request.build()).execute()
|
|
||||||
try {
|
|
||||||
val infoOption = try {
|
|
||||||
|
|
||||||
if (checkStatusCode(url, response)) {
|
|
||||||
val bodyCharset =
|
|
||||||
BasicURLHandler.getCharSetFromContentType(
|
|
||||||
Option(response.body().contentType()).map(_.toString).orNull
|
|
||||||
)
|
|
||||||
Some(
|
|
||||||
new SbtUrlInfo(
|
|
||||||
true,
|
|
||||||
response.body().contentLength(),
|
|
||||||
lastModifiedTimestamp(response),
|
|
||||||
bodyCharset
|
|
||||||
)
|
|
||||||
)
|
|
||||||
} else None
|
|
||||||
//
|
|
||||||
// Commented out for now - can potentially be used for non HTTP urls
|
|
||||||
//
|
|
||||||
// val contentLength: Long = con.getContentLengthLong
|
|
||||||
// if (contentLength <= 0) None
|
|
||||||
// else {
|
|
||||||
// // TODO: not HTTP... maybe we *don't* want to default to ISO-8559-1 here?
|
|
||||||
// val bodyCharset = BasicURLHandler.getCharSetFromContentType(con.getContentType)
|
|
||||||
// Some(new SbtUrlInfo(true, contentLength, con.getLastModified(), bodyCharset))
|
|
||||||
// }
|
|
||||||
|
|
||||||
} catch {
|
|
||||||
case e: UnknownHostException =>
|
|
||||||
Message.warn("Host " + e.getMessage + " not found. url=" + url)
|
|
||||||
Message.info(
|
|
||||||
"You probably access the destination server through "
|
|
||||||
+ "a proxy server that is not well configured."
|
|
||||||
)
|
|
||||||
None
|
|
||||||
case e: IOException =>
|
|
||||||
Message.error("Server access Error: " + e.getMessage + " url=" + url)
|
|
||||||
None
|
|
||||||
}
|
|
||||||
infoOption.getOrElse(UNAVAILABLE)
|
|
||||||
} finally {
|
|
||||||
response.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//The caller of this *MUST* call Response.close()
|
|
||||||
private def getUrl(url0: URL): okhttp3.Response = {
|
|
||||||
// Install the ErrorMessageAuthenticator
|
|
||||||
if ("http" == url0.getProtocol || "https" == url0.getProtocol) {
|
|
||||||
IvyAuthenticator.install()
|
|
||||||
ErrorMessageAuthenticator.install()
|
|
||||||
}
|
|
||||||
|
|
||||||
val url = normalizeToURL(url0)
|
|
||||||
val request = new Request.Builder()
|
|
||||||
.url(url)
|
|
||||||
.get()
|
|
||||||
.build()
|
|
||||||
|
|
||||||
val response = http.newCall(request).execute()
|
|
||||||
try {
|
|
||||||
if (!checkStatusCode(url, response)) {
|
|
||||||
throw new IOException(
|
|
||||||
"The HTTP response code for " + url + " did not indicate a success."
|
|
||||||
+ " See log for more detail."
|
|
||||||
)
|
|
||||||
}
|
|
||||||
response
|
|
||||||
} catch {
|
|
||||||
case NonFatal(e) =>
|
|
||||||
//ensure the response gets closed if there's an error
|
|
||||||
response.close()
|
|
||||||
throw e
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
def openStream(url: URL): InputStream = {
|
|
||||||
//It's assumed that the caller of this will call close() on the supplied inputstream,
|
|
||||||
// thus closing the OkHTTP request
|
|
||||||
getUrl(url).body().byteStream()
|
|
||||||
}
|
|
||||||
|
|
||||||
def download(url: URL, dest: File, l: CopyProgressListener): Unit = {
|
|
||||||
|
|
||||||
val response = getUrl(url)
|
|
||||||
try {
|
|
||||||
|
|
||||||
if (l != null) {
|
|
||||||
l.start(new CopyProgressEvent())
|
|
||||||
}
|
|
||||||
val sink = Okio.buffer(Okio.sink(dest))
|
|
||||||
try {
|
|
||||||
sink.writeAll(response.body().source())
|
|
||||||
sink.flush()
|
|
||||||
} finally {
|
|
||||||
sink.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
val contentLength = response.body().contentLength()
|
|
||||||
if (contentLength != -1 && dest.length != contentLength) {
|
|
||||||
IO.delete(dest)
|
|
||||||
throw new IOException(
|
|
||||||
"Downloaded file size doesn't match expected Content Length for " + url
|
|
||||||
+ ". Please retry."
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val lastModified = lastModifiedTimestamp(response)
|
|
||||||
if (lastModified > 0) {
|
|
||||||
IO.setModifiedTimeOrFalse(dest, lastModified)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (l != null) {
|
|
||||||
l.end(new CopyProgressEvent(EmptyBuffer, contentLength))
|
|
||||||
}
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
response.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def upload(source: File, dest0: URL, l: CopyProgressListener): Unit = {
|
|
||||||
|
|
||||||
if (("http" != dest0.getProtocol) && ("https" != dest0.getProtocol)) {
|
|
||||||
throw new UnsupportedOperationException("URL repository only support HTTP PUT at the moment")
|
|
||||||
}
|
|
||||||
|
|
||||||
IvyAuthenticator.install()
|
|
||||||
ErrorMessageAuthenticator.install()
|
|
||||||
|
|
||||||
val dest = normalizeToURL(dest0)
|
|
||||||
|
|
||||||
val body = RequestBody.create(MediaType.parse("application/octet-stream"), source)
|
|
||||||
|
|
||||||
val request = new Request.Builder()
|
|
||||||
.url(dest)
|
|
||||||
.put(body)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
if (l != null) {
|
|
||||||
l.start(new CopyProgressEvent())
|
|
||||||
}
|
|
||||||
val response = http.newCall(request).execute()
|
|
||||||
try {
|
|
||||||
if (l != null) {
|
|
||||||
l.end(new CopyProgressEvent(EmptyBuffer, source.length()))
|
|
||||||
}
|
|
||||||
validatePutStatusCode(dest, response)
|
|
||||||
} finally {
|
|
||||||
response.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val ErrorBodyTruncateLen = 512 // in case some bad service returns files rather than messages in error bodies
|
|
||||||
private val DefaultErrorCharset = java.nio.charset.StandardCharsets.UTF_8
|
|
||||||
|
|
||||||
// neurotic resource managemement...
|
|
||||||
// we could use this elsewhere in the class too
|
|
||||||
private def borrow[S <: AutoCloseable, T](rsrc: => S)(op: S => T): T = {
|
|
||||||
val r = rsrc
|
|
||||||
val out = {
|
|
||||||
try {
|
|
||||||
op(r)
|
|
||||||
} catch {
|
|
||||||
case NonFatal(t) => {
|
|
||||||
try {
|
|
||||||
r.close()
|
|
||||||
} catch {
|
|
||||||
case NonFatal(ct) => t.addSuppressed(ct)
|
|
||||||
}
|
|
||||||
throw t
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
r.close()
|
|
||||||
out
|
|
||||||
}
|
|
||||||
|
|
||||||
// this is perhaps overly cautious, but oh well
|
|
||||||
private def readTruncated(byteStream: InputStream): Option[(Array[Byte], Boolean)] = {
|
|
||||||
borrow(byteStream) { is =>
|
|
||||||
borrow(new ByteArrayOutputStream(ErrorBodyTruncateLen)) { os =>
|
|
||||||
var count = 0
|
|
||||||
var b = is.read()
|
|
||||||
var truncated = false
|
|
||||||
while (!truncated && b >= 0) {
|
|
||||||
if (count >= ErrorBodyTruncateLen) {
|
|
||||||
truncated = true
|
|
||||||
} else {
|
|
||||||
os.write(b)
|
|
||||||
count += 1
|
|
||||||
b = is.read()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (count > 0) {
|
|
||||||
Some((os.toByteArray, truncated))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Supplements the IOException emitted on a bad status code by our inherited validatePutStatusCode(...)
|
|
||||||
* method with any message that might be present in an error response body.
|
|
||||||
*
|
|
||||||
* after calling this method, the object given as the response parameter must be reliably closed.
|
|
||||||
*/
|
|
||||||
private def validatePutStatusCode(dest: URL, response: Response): Unit = {
|
|
||||||
try {
|
|
||||||
validatePutStatusCode(dest, response.code(), response.message())
|
|
||||||
} catch {
|
|
||||||
case ioe: IOException => {
|
|
||||||
val mbBodyMessage = {
|
|
||||||
for {
|
|
||||||
body <- Option(response.body())
|
|
||||||
is <- Option(body.byteStream)
|
|
||||||
(bytes, truncated) <- readTruncated(is)
|
|
||||||
charset <- Option(body.contentType()).map(_.charset(DefaultErrorCharset)) orElse Some(
|
|
||||||
DefaultErrorCharset
|
|
||||||
)
|
|
||||||
} yield {
|
|
||||||
val raw = new String(bytes, charset)
|
|
||||||
if (truncated) raw + "..." else raw
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mbBodyMessage match {
|
|
||||||
case Some(bodyMessage) => { // reconstruct the IOException
|
|
||||||
val newMessage = ioe.getMessage() + s"; Response Body: ${bodyMessage}"
|
|
||||||
val reconstructed = new IOException(newMessage, ioe.getCause())
|
|
||||||
reconstructed.setStackTrace(ioe.getStackTrace())
|
|
||||||
throw reconstructed
|
|
||||||
}
|
|
||||||
case None => {
|
|
||||||
throw ioe
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object GigahorseUrlHandler {
|
|
||||||
// This is requires to access the constructor of URLInfo.
|
|
||||||
private[sbt] class SbtUrlInfo(
|
|
||||||
available: Boolean,
|
|
||||||
contentLength: Long,
|
|
||||||
lastModified: Long,
|
|
||||||
bodyCharset: String
|
|
||||||
) extends URLInfo(available, contentLength, lastModified, bodyCharset) {
|
|
||||||
def this(available: Boolean, contentLength: Long, lastModified: Long) = {
|
|
||||||
this(available, contentLength, lastModified, null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val EmptyBuffer: Array[Byte] = new Array[Byte](0)
|
|
||||||
|
|
||||||
private def checkStatusCode(url: URL, response: Response): Boolean =
|
|
||||||
response.code() match {
|
|
||||||
case 200 => true
|
|
||||||
case 204 if "HEAD" == response.request().method() => true
|
|
||||||
case status =>
|
|
||||||
Message.debug("HTTP response status: " + status + " url=" + url)
|
|
||||||
if (status == 407 /* PROXY_AUTHENTICATION_REQUIRED */ ) {
|
|
||||||
Message.warn("Your proxy requires authentication.")
|
|
||||||
} else if (status == 401) {
|
|
||||||
Message.warn(
|
|
||||||
"CLIENT ERROR: 401 Unauthorized. Check your resolvers username and password."
|
|
||||||
)
|
|
||||||
} else if (String.valueOf(status).startsWith("4")) {
|
|
||||||
Message.verbose("CLIENT ERROR: " + response.message() + " url=" + url)
|
|
||||||
} else if (String.valueOf(status).startsWith("5")) {
|
|
||||||
Message.error("SERVER ERROR: " + response.message() + " url=" + url)
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
private def lastModifiedTimestamp(response: Response): Long = {
|
|
||||||
val lastModifiedDate =
|
|
||||||
Option(response.headers().get("Last-Modified")).flatMap { headerValue =>
|
|
||||||
Option(HttpDate.parse(headerValue))
|
|
||||||
}
|
|
||||||
|
|
||||||
lastModifiedDate.map(_.getTime).getOrElse(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -2,7 +2,6 @@ package sbt
|
||||||
package librarymanagement
|
package librarymanagement
|
||||||
package ivy
|
package ivy
|
||||||
|
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
import sbt.internal.librarymanagement._
|
import sbt.internal.librarymanagement._
|
||||||
import sbt.util.Logger
|
import sbt.util.Logger
|
||||||
|
|
||||||
|
|
@ -30,8 +29,5 @@ class IvyDependencyResolution private[sbt] (val ivySbt: IvySbt)
|
||||||
|
|
||||||
object IvyDependencyResolution {
|
object IvyDependencyResolution {
|
||||||
def apply(ivyConfiguration: IvyConfiguration): DependencyResolution =
|
def apply(ivyConfiguration: IvyConfiguration): DependencyResolution =
|
||||||
apply(ivyConfiguration, CustomHttp.defaultHttpClient)
|
DependencyResolution(new IvyDependencyResolution(new IvySbt(ivyConfiguration)))
|
||||||
|
|
||||||
def apply(ivyConfiguration: IvyConfiguration, http: OkHttpClient): DependencyResolution =
|
|
||||||
DependencyResolution(new IvyDependencyResolution(new IvySbt(ivyConfiguration, http)))
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ package sbt
|
||||||
package librarymanagement
|
package librarymanagement
|
||||||
package ivy
|
package ivy
|
||||||
|
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
import sbt.internal.librarymanagement._
|
import sbt.internal.librarymanagement._
|
||||||
import sbt.util.Logger
|
import sbt.util.Logger
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
@ -36,8 +35,5 @@ class IvyPublisher private[sbt] (val ivySbt: IvySbt) extends PublisherInterface
|
||||||
|
|
||||||
object IvyPublisher {
|
object IvyPublisher {
|
||||||
def apply(ivyConfiguration: IvyConfiguration): Publisher =
|
def apply(ivyConfiguration: IvyConfiguration): Publisher =
|
||||||
apply(ivyConfiguration, CustomHttp.defaultHttpClient)
|
Publisher(new IvyPublisher(new IvySbt(ivyConfiguration)))
|
||||||
|
|
||||||
def apply(ivyConfiguration: IvyConfiguration, http: OkHttpClient): Publisher =
|
|
||||||
Publisher(new IvyPublisher(new IvySbt(ivyConfiguration, http)))
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ import Keys._
|
||||||
import sbt.contraband.ContrabandPlugin.autoImport._
|
import sbt.contraband.ContrabandPlugin.autoImport._
|
||||||
|
|
||||||
object Dependencies {
|
object Dependencies {
|
||||||
val scala212 = "2.12.15"
|
val scala212 = "2.12.16"
|
||||||
val scala213 = "2.13.6"
|
val scala213 = "2.13.8"
|
||||||
|
|
||||||
def nightlyVersion: Option[String] =
|
def nightlyVersion: Option[String] =
|
||||||
sys.env.get("BUILD_VERSION") orElse sys.props.get("sbt.build.version")
|
sys.env.get("BUILD_VERSION") orElse sys.props.get("sbt.build.version")
|
||||||
|
|
@ -61,6 +61,5 @@ object Dependencies {
|
||||||
val sjsonnewScalaJson = Def.setting {
|
val sjsonnewScalaJson = Def.setting {
|
||||||
"com.eed3si9n" %% "sjson-new-scalajson" % contrabandSjsonNewVersion.value
|
"com.eed3si9n" %% "sjson-new-scalajson" % contrabandSjsonNewVersion.value
|
||||||
}
|
}
|
||||||
val gigahorseOkhttp = "com.eed3si9n" %% "gigahorse-okhttp" % "0.5.0"
|
val gigahorseApacheHttp = "com.eed3si9n" %% "gigahorse-apache-http" % "0.7.0"
|
||||||
val okhttpUrlconnection = "com.squareup.okhttp3" % "okhttp-urlconnection" % "3.7.0"
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue