getPrincipalCollectionSet(String url) throws IOException;
+ void enableHttp2();
+
/**
*
* Enables HTTP GZIP compression. If enabled, requests originating from Sardine
diff --git a/src/main/java/com/github/sardine/SardineFactory.java b/src/main/java/com/github/sardine/SardineFactory.java
index 1e3de83f..f4969c59 100644
--- a/src/main/java/com/github/sardine/SardineFactory.java
+++ b/src/main/java/com/github/sardine/SardineFactory.java
@@ -41,6 +41,6 @@ public static Sardine begin(String username, String password)
*/
public static Sardine begin(String username, String password, ProxySelector proxy)
{
- return new SardineImpl(username, password, proxy);
+ return new SardineImpl(username, password != null ? password.toCharArray() : null, proxy);
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/github/sardine/ant/SardineTask.java b/src/main/java/com/github/sardine/ant/SardineTask.java
index fb3b578d..390cd8f6 100644
--- a/src/main/java/com/github/sardine/ant/SardineTask.java
+++ b/src/main/java/com/github/sardine/ant/SardineTask.java
@@ -101,7 +101,7 @@ public void execute() throws BuildException {
sardine = SardineFactory.begin(username, password);
} else {
sardine = SardineFactory.begin();
- sardine.setCredentials(username, password, domain, workstation);
+ sardine.setCredentials(username, password.toCharArray(), domain, workstation);
}
if (ignoreCookies) {
diff --git a/src/main/java/com/github/sardine/impl/SardineException.java b/src/main/java/com/github/sardine/impl/SardineException.java
index 7d14f905..c0256cc1 100644
--- a/src/main/java/com/github/sardine/impl/SardineException.java
+++ b/src/main/java/com/github/sardine/impl/SardineException.java
@@ -16,7 +16,8 @@
package com.github.sardine.impl;
-import org.apache.http.client.HttpResponseException;
+
+import org.apache.hc.client5.http.HttpResponseException;
/**
* Specialized type of exception for Sardine so
@@ -56,4 +57,4 @@ public String getMessage()
{
return String.format("%s (%d %s)", super.getMessage(), this.getStatusCode(), this.getResponsePhrase());
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/github/sardine/impl/SardineImpl.java b/src/main/java/com/github/sardine/impl/SardineImpl.java
index 95a34d4f..a28659db 100644
--- a/src/main/java/com/github/sardine/impl/SardineImpl.java
+++ b/src/main/java/com/github/sardine/impl/SardineImpl.java
@@ -28,46 +28,44 @@
import com.github.sardine.report.SardineReport;
import com.github.sardine.report.VersionTreeReport;
import com.github.sardine.util.SardineUtil;
-import org.apache.http.*;
-import org.apache.http.auth.AuthScope;
-import org.apache.http.auth.AuthState;
-import org.apache.http.auth.NTCredentials;
-import org.apache.http.auth.UsernamePasswordCredentials;
-import org.apache.http.client.AuthCache;
-import org.apache.http.client.CredentialsProvider;
-import org.apache.http.client.HttpResponseException;
-import org.apache.http.client.ResponseHandler;
-import org.apache.http.client.config.AuthSchemes;
-import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.*;
-import org.apache.http.client.protocol.HttpClientContext;
-import org.apache.http.client.protocol.RequestAcceptEncoding;
-import org.apache.http.client.protocol.ResponseContentEncoding;
-import org.apache.http.config.Lookup;
-import org.apache.http.config.Registry;
-import org.apache.http.config.RegistryBuilder;
-import org.apache.http.conn.HttpClientConnectionManager;
-import org.apache.http.conn.SchemePortResolver;
-import org.apache.http.conn.routing.HttpRoutePlanner;
-import org.apache.http.conn.socket.ConnectionSocketFactory;
-import org.apache.http.conn.socket.PlainConnectionSocketFactory;
-import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
-import org.apache.http.cookie.CookieSpecProvider;
-import org.apache.http.entity.ByteArrayEntity;
-import org.apache.http.entity.FileEntity;
-import org.apache.http.entity.InputStreamEntity;
-import org.apache.http.entity.StringEntity;
-import org.apache.http.impl.auth.BasicScheme;
-import org.apache.http.impl.client.*;
-import org.apache.http.impl.conn.DefaultSchemePortResolver;
-import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
-import org.apache.http.impl.conn.SystemDefaultRoutePlanner;
-import org.apache.http.impl.cookie.IgnoreSpecProvider;
-import org.apache.http.message.BasicHeader;
-import org.apache.http.protocol.BasicHttpContext;
-import org.apache.http.protocol.HTTP;
-import org.apache.http.protocol.HttpContext;
-import org.apache.http.util.VersionInfo;
+import org.apache.hc.client5.http.HttpResponseException;
+import org.apache.hc.client5.http.SchemePortResolver;
+import org.apache.hc.client5.http.auth.*;
+import org.apache.hc.client5.http.classic.methods.*;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.cookie.CookieSpecFactory;
+import org.apache.hc.client5.http.entity.GzipDecompressingEntity;
+import org.apache.hc.client5.http.impl.DefaultRedirectStrategy;
+import org.apache.hc.client5.http.impl.DefaultSchemePortResolver;
+import org.apache.hc.client5.http.impl.auth.BasicAuthCache;
+import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
+import org.apache.hc.client5.http.impl.auth.BasicScheme;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
+import org.apache.hc.client5.http.impl.classic.HttpClients;
+import org.apache.hc.client5.http.impl.cookie.IgnoreCookieSpecFactory;
+import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
+import org.apache.hc.client5.http.impl.routing.SystemDefaultRoutePlanner;
+import org.apache.hc.client5.http.io.HttpClientConnectionManager;
+import org.apache.hc.client5.http.protocol.HttpClientContext;
+import org.apache.hc.client5.http.protocol.RedirectStrategy;
+import org.apache.hc.client5.http.routing.HttpRoutePlanner;
+import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
+import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory;
+import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
+import org.apache.hc.core5.http.*;
+import org.apache.hc.core5.http.config.Lookup;
+import org.apache.hc.core5.http.config.Registry;
+import org.apache.hc.core5.http.config.RegistryBuilder;
+import org.apache.hc.core5.http.io.HttpClientResponseHandler;
+import org.apache.hc.core5.http.io.entity.ByteArrayEntity;
+import org.apache.hc.core5.http.io.entity.FileEntity;
+import org.apache.hc.core5.http.io.entity.InputStreamEntity;
+import org.apache.hc.core5.http.io.entity.StringEntity;
+import org.apache.hc.core5.http.message.BasicHeader;
+import org.apache.hc.core5.http.protocol.BasicHttpContext;
+import org.apache.hc.core5.http.protocol.HttpContext;
+import org.apache.hc.core5.util.VersionInfo;
import org.w3c.dom.Element;
import javax.xml.namespace.QName;
@@ -77,7 +75,7 @@
import java.net.ProxySelector;
import java.net.URISyntaxException;
import java.net.URL;
-import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -96,7 +94,16 @@ public class SardineImpl implements Sardine
{
private static final Logger log = Logger.getLogger(DavResource.class.getName());
- private static final String UTF_8 = "UTF-8";
+ /**
+ * Value for "Expect" HTTP header
+ */
+ private static final String EXPECT_CONTINUE = "100-Continue";
+
+ /**
+ * Default content charset originally used by v4 of HTTP client.
+ */
+ private static final String DEF_CONTENT_CHARSET = StandardCharsets.ISO_8859_1.name();
+ private static final String HTTP_MAJOR_VERSION = "HTTP_MAJOR_VERSION";
/**
* HTTP client implementation
@@ -128,7 +135,7 @@ public SardineImpl()
*/
public SardineImpl(String bearerAuth)
{
- Header bearerHeader = new BasicHeader("Authorization", "Bearer " + bearerAuth);
+ Header bearerHeader = new BasicHeader(HttpHeaders.AUTHORIZATION, "Bearer " + bearerAuth);
this.builder = this.configure(null, null).setDefaultHeaders(Collections.singletonList(bearerHeader));
this.client = this.builder.build();
}
@@ -139,7 +146,7 @@ public SardineImpl(String bearerAuth)
* @param username Use in authentication header credentials
* @param password Use in authentication header credentials
*/
- public SardineImpl(String username, String password)
+ public SardineImpl(String username, char[] password)
{
this.builder = this.configure(null, this.createDefaultCredentialsProvider(username, password, null, null));
this.client = this.builder.build();
@@ -150,7 +157,7 @@ public SardineImpl(String username, String password)
* @param password Use in authentication header credentials
* @param selector Proxy configuration
*/
- public SardineImpl(String username, String password, ProxySelector selector)
+ public SardineImpl(String username, char[] password, ProxySelector selector)
{
this.builder = this.configure(selector, this.createDefaultCredentialsProvider(username, password, null, null));
this.client = this.builder.build();
@@ -170,13 +177,18 @@ public SardineImpl(HttpClientBuilder builder)
* @param username Use in authentication header credentials
* @param password Use in authentication header credentials
*/
- public SardineImpl(HttpClientBuilder builder, String username, String password)
+ public SardineImpl(HttpClientBuilder builder, String username, char[] password)
{
this.builder = builder;
this.setCredentials(username, password);
this.client = this.builder.build();
}
+ @Override
+ public void setCredentials(String username, String password) {
+ this.setCredentials(username, password.toCharArray());
+ }
+
/**
* Add credentials to any scope. Supports Basic, Digest and NTLM authentication methods.
*
@@ -184,11 +196,16 @@ public SardineImpl(HttpClientBuilder builder, String username, String password)
* @param password Use in authentication header credentials
*/
@Override
- public void setCredentials(String username, String password)
+ public void setCredentials(String username, char[] password)
{
this.setCredentials(username, password, "", "");
}
+ @Override
+ public void setCredentials(String username, String password, String domain, String workstation) {
+ this.setCredentials(username, password.toCharArray(), domain, workstation);
+ }
+
/**
* @param username Use in authentication header credentials
* @param password Use in authentication header credentials
@@ -196,7 +213,7 @@ public void setCredentials(String username, String password)
* @param workstation NTLM authentication
*/
@Override
- public void setCredentials(String username, String password, String domain, String workstation)
+ public void setCredentials(String username, char[] password, String domain, String workstation)
{
this.setCredentials(this.createDefaultCredentialsProvider(username, password, domain, workstation));
}
@@ -204,28 +221,27 @@ public void setCredentials(String username, String password, String domain, Stri
public void setCredentials(CredentialsProvider provider)
{
this.context.setCredentialsProvider(provider);
- this.context.setAttribute(HttpClientContext.TARGET_AUTH_STATE, new AuthState());
}
- private CredentialsProvider createDefaultCredentialsProvider(String username, String password, String domain, String workstation)
+ private CredentialsProvider createDefaultCredentialsProvider(String username, char[] password, String domain, String workstation)
{
- CredentialsProvider provider = new BasicCredentialsProvider();
+ CredentialsStore provider = new BasicCredentialsProvider();
if (username != null)
{
provider.setCredentials(
- new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, AuthSchemes.NTLM),
+ new AuthScope(null, null, -1, null, StandardAuthScheme.NTLM),
new NTCredentials(username, password, workstation, domain));
provider.setCredentials(
- new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, AuthSchemes.BASIC),
+ new AuthScope(null, null, -1, null, StandardAuthScheme.BASIC),
new UsernamePasswordCredentials(username, password));
provider.setCredentials(
- new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, AuthSchemes.DIGEST),
+ new AuthScope(null, null, -1, null, StandardAuthScheme.DIGEST),
new UsernamePasswordCredentials(username, password));
provider.setCredentials(
- new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, AuthSchemes.SPNEGO),
+ new AuthScope(null, null, -1, null, StandardAuthScheme.SPNEGO),
new NTCredentials(username, password, workstation, domain));
provider.setCredentials(
- new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, AuthSchemes.KERBEROS),
+ new AuthScope(null, null, -1, null, StandardAuthScheme.KERBEROS),
new UsernamePasswordCredentials(username, password));
}
return provider;
@@ -237,8 +253,23 @@ private CredentialsProvider createDefaultCredentialsProvider(String username, St
@Override
public void enableCompression()
{
- this.builder.addInterceptorLast(new RequestAcceptEncoding());
- this.builder.addInterceptorLast(new ResponseContentEncoding());
+ // Adding content encoding (gzip) support
+ this.builder.addRequestInterceptorLast((httpRequest, entityDetails, context) -> {
+ httpRequest.addHeader("Accept-Encoding", "gzip");
+ });
+
+ this.builder.addResponseInterceptorLast((httpResponse, entityDetails, context) -> {
+ ClassicHttpResponse classicHttpResponse = (ClassicHttpResponse) httpResponse;
+ HttpEntity entity = classicHttpResponse.getEntity();
+
+ if (httpResponse.containsHeader("Content-Encoding") &&
+ "gzip".equalsIgnoreCase(httpResponse.getHeader("Content-Encoding").getValue())) {
+ // Decompressing the gzip content
+ ClassicHttpResponse.class.cast(httpResponse).setEntity(
+ new GzipDecompressingEntity(entity));
+ }
+ });
+
this.client = this.builder.build();
}
@@ -258,14 +289,7 @@ public void disableCompression()
@Override
public void ignoreCookies()
{
- this.builder.setDefaultCookieSpecRegistry(new Lookup()
- {
- @Override
- public CookieSpecProvider lookup(String name)
- {
- return new IgnoreSpecProvider();
- }
- });
+ this.builder.setDefaultCookieSpecRegistry(name -> new IgnoreCookieSpecFactory());
this.client = this.builder.build();
}
@@ -303,30 +327,25 @@ else if ("http".equals(protocol))
@Override
public void enablePreemptiveAuthentication(String hostname, int httpPort, int httpsPort)
{
- enablePreemptiveAuthentication(hostname, httpPort, httpsPort, Consts.ISO_8859_1);
- }
-
- public void enablePreemptiveAuthentication(String hostname, int httpPort, int httpsPort, Charset credentialsCharset)
- {
- AuthCache cache = this.context.getAuthCache();
+ AuthCache cache = context.getAuthCache();
if (cache == null)
{
// Add AuthCache to the execution context
cache = new BasicAuthCache();
- this.context.setAuthCache(cache);
+ context.setAuthCache(cache);
}
// Generate Basic preemptive scheme object and stick it to the local execution context
- BasicScheme basicAuth = new BasicScheme(credentialsCharset);
+ BasicScheme basicAuth = new BasicScheme();
// Configure HttpClient to authenticate preemptively by prepopulating the authentication data cache.
- cache.put(new HttpHost(hostname, httpPort == -1 ? 80 : httpPort, "http"), basicAuth);
- cache.put(new HttpHost(hostname, httpsPort == -1 ? 443 : httpsPort, "https"), basicAuth);
+ cache.put(new HttpHost("http", hostname, httpPort), basicAuth);
+ cache.put(new HttpHost("https", hostname, httpsPort), basicAuth);
}
@Override
public void disablePreemptiveAuthentication()
{
- this.context.removeAttribute(HttpClientContext.AUTH_CACHE);
+ context.setAuthCache(null);
}
@Override
@@ -358,7 +377,7 @@ public List list(String url, int depth, boolean allProp) throws IOE
}
else
{
- return list(url, depth, Collections.emptySet());
+ return list(url, depth, Collections.emptySet());
}
}
@@ -369,7 +388,7 @@ public List versionsList(String url) throws IOException {
@Override
public List versionsList(String url, int depth) throws IOException {
- return versionsList(url, depth, Collections.emptySet());
+ return versionsList(url, depth, Collections.emptySet());
}
@Override
@@ -420,10 +439,10 @@ protected List propfind(String url, int depth, Propfind body) throw
{
HttpPropFind entity = new HttpPropFind(url);
entity.setDepth(depth < 0 ? "infinity" : Integer.toString(depth));
- entity.setEntity(new StringEntity(SardineUtil.toXml(body), UTF_8));
+ entity.setEntity(new StringEntity(SardineUtil.toXml(body), StandardCharsets.UTF_8));
Multistatus multistatus = this.execute(entity, new MultiStatusResponseHandler());
List responses = multistatus.getResponse();
- List resources = new ArrayList(responses.size());
+ List resources = new ArrayList<>(responses.size());
for (Response response : responses)
{
try
@@ -442,20 +461,20 @@ public T report(String url, int depth, SardineReport report) throws IOExc
{
HttpReport entity = new HttpReport(url);
entity.setDepth(depth < 0 ? "infinity" : Integer.toString(depth));
- entity.setEntity(new StringEntity(report.toXml(), UTF_8));
+ entity.setEntity(new StringEntity(report.toXml(), StandardCharsets.UTF_8));
Multistatus multistatus = this.execute(entity, new MultiStatusResponseHandler());
return report.fromMultistatus(multistatus);
}
public List search(String url, String language, String query) throws IOException
{
- HttpEntityEnclosingRequestBase search = new HttpSearch(url);
+ HttpSearch search = new HttpSearch(url);
SearchRequest searchBody = new SearchRequest(language, query);
String body = SardineUtil.toXml(searchBody);
- search.setEntity(new StringEntity(body, UTF_8));
+ search.setEntity(createEntity(body));
Multistatus multistatus = this.execute(search, new MultiStatusResponseHandler());
List responses = multistatus.getResponse();
- List resources = new ArrayList(responses.size());
+ List resources = new ArrayList<>(responses.size());
for (Response response : responses)
{
try
@@ -479,7 +498,7 @@ public void setCustomProps(String url, Map set, List rem
@Override
public List patch(String url, Map setProps) throws IOException
{
- return this.patch(url, setProps, Collections.emptyList());
+ return this.patch(url, setProps, Collections.emptyList());
}
/**
@@ -490,7 +509,7 @@ public List patch(String url, Map setProps) throws I
@Override
public List patch(String url, Map setProps, List removeProps) throws IOException
{
- List setPropsElements = new ArrayList();
+ List setPropsElements = new ArrayList<>();
for (Entry entry : setProps.entrySet())
{
Element element = SardineUtil.createElement(entry.getKey());
@@ -508,7 +527,7 @@ public List patch(String url, Map setProps, List patch(String url, List setProps, List removeProps) throws IOException
{
- return this.patch(url, setProps, removeProps, Collections.emptyMap());
+ return this.patch(url, setProps, removeProps, Collections.emptyMap());
}
@Override
@@ -519,6 +538,7 @@ public List patch(String url, List setProps, List r
{
patch.addHeader(new BasicHeader(h.getKey(), h.getValue()));
}
+ HttpPropPatch entity = new HttpPropPatch(url);
// Build WebDAV PROPPATCH entity.
Propertyupdate body = new Propertyupdate();
// Add properties
@@ -550,10 +570,10 @@ public List patch(String url, List setProps, List r
remove.setProp(prop);
}
}
- patch.setEntity(new StringEntity(SardineUtil.toXml(body), UTF_8));
- Multistatus multistatus = this.execute(patch, new MultiStatusResponseHandler());
+ entity.setEntity(createEntity(body));
+ Multistatus multistatus = this.execute(entity, new MultiStatusResponseHandler());
List responses = multistatus.getResponse();
- List resources = new ArrayList(responses.size());
+ List resources = new ArrayList<>(responses.size());
for (Response response : responses)
{
try
@@ -579,7 +599,7 @@ public String lock(String url) throws IOException
Locktype lockType = new Locktype();
lockType.setWrite(new Write());
body.setLocktype(lockType);
- entity.setEntity(new StringEntity(SardineUtil.toXml(body), UTF_8));
+ entity.setEntity(createEntity(body));
// Return the lock token
return this.execute(entity, new LockResponseHandler());
}
@@ -596,13 +616,6 @@ public String refreshLock(String url, String token, String file) throws IOExcept
public void unlock(String url, String token) throws IOException
{
HttpUnlock entity = new HttpUnlock(url, token);
- Lockinfo body = new Lockinfo();
- Lockscope scopeType = new Lockscope();
- scopeType.setExclusive(new Exclusive());
- body.setLockscope(scopeType);
- Locktype lockType = new Locktype();
- lockType.setWrite(new Write());
- body.setLocktype(lockType);
this.execute(entity, new VoidResponseHandler());
}
@@ -627,7 +640,7 @@ public void setAcl(String url, List aces) throws IOException
HttpAcl entity = new HttpAcl(url);
// Build WebDAV ACL entity.
Acl body = new Acl();
- body.setAce(new ArrayList());
+ body.setAce(new ArrayList<>());
for (DavAce davAce : aces)
{
// protected and inherited acl must not be part of ACL http request
@@ -638,7 +651,7 @@ public void setAcl(String url, List aces) throws IOException
Ace ace = davAce.toModel();
body.getAce().add(ace);
}
- entity.setEntity(new StringEntity(SardineUtil.toXml(body), UTF_8));
+ entity.setEntity(createEntity(body));
this.execute(entity, new VoidResponseHandler());
}
@@ -654,7 +667,7 @@ public DavAcl getAcl(String url) throws IOException
prop.setGroup(new Group());
prop.setAcl(new Acl());
body.setProp(prop);
- entity.setEntity(new StringEntity(SardineUtil.toXml(body), UTF_8));
+ entity.setEntity(createEntity(body));
Multistatus multistatus = this.execute(entity, new MultiStatusResponseHandler());
List responses = multistatus.getResponse();
if (responses.isEmpty())
@@ -677,7 +690,7 @@ public DavQuota getQuota(String url) throws IOException
prop.setQuotaAvailableBytes(new QuotaAvailableBytes());
prop.setQuotaUsedBytes(new QuotaUsedBytes());
body.setProp(prop);
- entity.setEntity(new StringEntity(SardineUtil.toXml(body), UTF_8));
+ entity.setEntity(createEntity(body));
Multistatus multistatus = this.execute(entity, new MultiStatusResponseHandler());
List responses = multistatus.getResponse();
if (responses.isEmpty())
@@ -709,7 +722,7 @@ public List getPrincipals(String url) throws IOException
prop.setResourcetype(new Resourcetype());
prop.setPrincipalURL(new PrincipalURL());
body.setProp(prop);
- entity.setEntity(new StringEntity(SardineUtil.toXml(body), UTF_8));
+ entity.setEntity(createEntity(body));
Multistatus multistatus = this.execute(entity, new MultiStatusResponseHandler());
List responses = multistatus.getResponse();
if (responses.isEmpty())
@@ -718,7 +731,7 @@ public List getPrincipals(String url) throws IOException
}
else
{
- List collections = new ArrayList();
+ List collections = new ArrayList<>();
for (Response r : responses)
{
if (r.getPropstat() != null)
@@ -749,7 +762,7 @@ public List getPrincipalCollectionSet(String url) throws IOException
Prop prop = new Prop();
prop.setPrincipalCollectionSet(new PrincipalCollectionSet());
body.setProp(prop);
- entity.setEntity(new StringEntity(SardineUtil.toXml(body), UTF_8));
+ entity.setEntity(createEntity(body));
Multistatus multistatus = this.execute(entity, new MultiStatusResponseHandler());
List responses = multistatus.getResponse();
if (responses.isEmpty())
@@ -758,7 +771,7 @@ public List getPrincipalCollectionSet(String url) throws IOException
}
else
{
- List collections = new ArrayList();
+ List collections = new ArrayList<>();
for (Response r : responses)
{
if (r.getPropstat() != null)
@@ -778,10 +791,15 @@ public List getPrincipalCollectionSet(String url) throws IOException
}
}
+ @Override
+ public void enableHttp2() {
+ context.setAttribute(HTTP_MAJOR_VERSION, 2);
+ }
+
@Override
public ContentLengthInputStream get(String url) throws IOException
{
- return this.get(url, Collections.emptyMap());
+ return this.get(url, Collections.emptyMap());
}
@Override
@@ -794,7 +812,7 @@ public ContentLengthInputStream get(String url, String version) throws IOExcepti
@Override
public ContentLengthInputStream get(String url, Map headers) throws IOException
{
- List list = new ArrayList();
+ List list = new ArrayList<>();
for (Map.Entry h : headers.entrySet())
{
list.add(new BasicHeader(h.getKey(), h.getValue()));
@@ -811,7 +829,7 @@ public ContentLengthInputStream get(String url, List headers) throws IOE
}
// Must use #execute without handler, otherwise the entity is consumed
// already after the handler exits.
- HttpResponse response = this.execute(get);
+ ClassicHttpResponse response = this.execute(get);
VoidResponseHandler handler = new VoidResponseHandler();
try
{
@@ -835,14 +853,14 @@ public void put(String url, byte[] data) throws IOException
@Override
public void put(String url, byte[] data, String contentType) throws IOException
{
- ByteArrayEntity entity = new ByteArrayEntity(data);
+ ByteArrayEntity entity = new ByteArrayEntity(data, createContentType(contentType));
this.put(url, entity, contentType, true);
}
@Override
public void put(String url, InputStream dataStream) throws IOException
{
- this.put(url, dataStream, (String) null);
+ this.put(url, dataStream, null);
}
@Override
@@ -861,25 +879,25 @@ public void put(String url, InputStream dataStream, String contentType, boolean
@Override
public void put(String url, InputStream dataStream, String contentType, boolean expectContinue, long contentLength) throws IOException
{
- InputStreamEntity entity = new InputStreamEntity(dataStream, contentLength);
+ InputStreamEntity entity = new InputStreamEntity(dataStream, contentLength, createContentType(contentType));
this.put(url, entity, contentType, expectContinue);
}
@Override
- public void put(String url, InputStream dataStream, Map headers) throws IOException
+ public void put(String url, InputStream dataStream, String contentType, Map headers) throws IOException
{
- List list = new ArrayList();
+ List list = new ArrayList<>();
for (Map.Entry h : headers.entrySet())
{
list.add(new BasicHeader(h.getKey(), h.getValue()));
}
- this.put(url, dataStream, list);
+ this.put(url, dataStream, contentType, list);
}
- public void put(String url, InputStream dataStream, List headers) throws IOException
+ public void put(String url, InputStream dataStream, String contentType, List headers) throws IOException
{
// A length of -1 means "go until end of stream"
- InputStreamEntity entity = new InputStreamEntity(dataStream, -1);
+ InputStreamEntity entity = new InputStreamEntity(dataStream, -1, createContentType(contentType));
this.put(url, entity, headers);
}
@@ -893,14 +911,14 @@ public void put(String url, InputStream dataStream, List headers) throws
*/
public void put(String url, HttpEntity entity, String contentType, boolean expectContinue) throws IOException
{
- List headers = new ArrayList();
+ List headers = new ArrayList<>();
if (contentType != null)
{
headers.add(new BasicHeader(HttpHeaders.CONTENT_TYPE, contentType));
}
if (expectContinue)
{
- headers.add(new BasicHeader(HTTP.EXPECT_DIRECTIVE, HTTP.EXPECT_CONTINUE));
+ headers.add(new BasicHeader(HttpHeaders.EXPECT, EXPECT_CONTINUE));
}
this.put(url, entity, headers);
}
@@ -917,7 +935,7 @@ public void put(String url, HttpEntity entity, List headers) throws IOEx
this.put(url, entity, headers, new VoidResponseHandler());
}
- public T put(String url, HttpEntity entity, List headers, ResponseHandler handler) throws IOException
+ public T put(String url, HttpEntity entity, List headers, HttpClientResponseHandler handler) throws IOException
{
HttpPut put = new HttpPut(url);
put.setEntity(entity);
@@ -927,7 +945,7 @@ public T put(String url, HttpEntity entity, List headers, ResponseHa
}
if (entity.getContentType() == null && !put.containsHeader(HttpHeaders.CONTENT_TYPE))
{
- put.addHeader(HttpHeaders.CONTENT_TYPE, HTTP.DEF_CONTENT_CHARSET.name());
+ put.addHeader(HttpHeaders.CONTENT_TYPE, DEF_CONTENT_CHARSET);
}
try
{
@@ -938,7 +956,7 @@ public T put(String url, HttpEntity entity, List headers, ResponseHa
if (e.getStatusCode() == HttpStatus.SC_EXPECTATION_FAILED)
{
// Retry with the Expect header removed
- put.removeHeaders(HTTP.EXPECT_DIRECTIVE);
+ put.removeHeaders(HttpHeaders.EXPECT);
if (entity.isRepeatable())
{
return this.execute(put, handler);
@@ -951,21 +969,21 @@ public T put(String url, HttpEntity entity, List headers, ResponseHa
@Override
public void put(String url, File localFile, String contentType) throws IOException
{
- //don't use ExpectContinue for repetable FileEntity, some web server (IIS for exmaple) may return 400 bad request after retry
- this.put(url, localFile, contentType, false);
+ //don't use ExpectContinue for repeatable FileEntity, some web server (IIS for example) may return 400 bad request after retry
+ put(url, localFile, contentType, false);
}
@Override
public void put(String url, File localFile, String contentType, boolean expectContinue) throws IOException
{
- FileEntity content = new FileEntity(localFile);
+ FileEntity content = new FileEntity(localFile, createContentType(contentType));
this.put(url, content, contentType, expectContinue);
}
@Override
public void delete(String url) throws IOException
{
- this.delete(url, Collections.emptyMap());
+ this.delete(url, Collections.emptyMap());
}
@Override
@@ -984,7 +1002,7 @@ public void move(String sourceUrl, String destinationUrl) throws IOException
@Override
public void move(String sourceUrl, String destinationUrl, boolean overwrite) throws IOException
{
- this.move(sourceUrl, destinationUrl, overwrite, Collections.emptyMap());
+ this.move(sourceUrl, destinationUrl, overwrite, Collections.emptyMap());
}
@Override
@@ -1001,13 +1019,13 @@ public void move(String sourceUrl, String destinationUrl, boolean overwrite, Map
@Override
public void copy(String sourceUrl, String destinationUrl) throws IOException
{
- this.copy(sourceUrl, destinationUrl, true);
+ copy(sourceUrl, destinationUrl, true);
}
@Override
public void copy(String sourceUrl, String destinationUrl, boolean overwrite) throws IOException
{
- this.copy(sourceUrl, destinationUrl, overwrite, Collections.emptyMap());
+ this.copy(sourceUrl, destinationUrl, overwrite, Collections.emptyMap());
}
@Override
@@ -1043,7 +1061,7 @@ public boolean exists(String url) throws IOException
* @param responseHandler Determines the return type.
* @return parsed response
*/
- protected T execute(HttpRequestBase request, ResponseHandler responseHandler)
+ protected T execute(HttpUriRequestBase request, HttpClientResponseHandler responseHandler)
throws IOException
{
return execute(context, request, responseHandler);
@@ -1055,7 +1073,7 @@ protected T execute(HttpRequestBase request, ResponseHandler responseHand
* @param request Request to execute
* @return The response to check the reply status code
*/
- protected HttpResponse execute(HttpRequestBase request)
+ protected ClassicHttpResponse execute(HttpUriRequestBase request)
throws IOException
{
return execute(context, request, null);
@@ -1069,15 +1087,20 @@ protected HttpResponse execute(HttpRequestBase request)
* @param will return raw HttpResponse when responseHandler is null or value reslved using provided ResponseHandler instance
* @return value resolved using response handler or raw HttpResponse when responseHandler is null
*/
- protected T execute(HttpClientContext context, HttpRequestBase request, ResponseHandler responseHandler)
+ protected T execute(HttpClientContext context, HttpUriRequestBase request, HttpClientResponseHandler responseHandler)
throws IOException
{
- HttpContext requestLocalContext = new BasicHttpContext(context);
+ Integer httpMajorVersion = (Integer) context.getAttribute(HTTP_MAJOR_VERSION);
+
+ if (httpMajorVersion != null){
+ request.setVersion(new ProtocolVersion("HTTP", httpMajorVersion, 0));
+ }
+ HttpClientContext requestLocalContext = new HttpClientContext(context);
try
{
if (responseHandler != null)
{
- return this.client.execute(request, responseHandler, requestLocalContext);
+ return this.client.execute(request, requestLocalContext, responseHandler);
}
else
{
@@ -1096,7 +1119,7 @@ protected T execute(HttpClientContext context, HttpRequestBase request, Resp
}
finally
{
- context.setAttribute(HttpClientContext.USER_TOKEN, requestLocalContext.getAttribute(HttpClientContext.USER_TOKEN));
+ context.setUserToken(requestLocalContext.getUserToken());
}
}
@@ -1137,9 +1160,9 @@ protected DefaultSchemePortResolver createDefaultSchemePortResolver()
return new DefaultSchemePortResolver();
}
- protected SardineRedirectStrategy createDefaultRedirectStrategy()
+ protected RedirectStrategy createDefaultRedirectStrategy()
{
- return new SardineRedirectStrategy();
+ return new DefaultRedirectStrategy();
}
/**
@@ -1191,4 +1214,26 @@ protected HttpRoutePlanner createDefaultRoutePlanner(SchemePortResolver resolver
{
return new SystemDefaultRoutePlanner(resolver, selector);
}
+
+ /**
+ * Common logic to create an HTTP entity for a JAXB element.
+ *
+ * @param jaxbElement the JAXB element.
+ * @return the HTTP entity.
+ * @throws IOException if an error occurs serialising the element.
+ */
+ private static HttpEntity createEntity(Object jaxbElement) throws IOException
+ {
+ return new StringEntity(SardineUtil.toXml(jaxbElement), StandardCharsets.UTF_8);
+ }
+
+ /**
+ * Create MIME content type from string
+ *
+ * @param contentType MIME content type or null
+ * @return May be null
+ */
+ private static ContentType createContentType(String contentType) {
+ return contentType != null ? ContentType.create(contentType) : null;
+ }
}
diff --git a/src/main/java/com/github/sardine/impl/SardineRedirectStrategy.java b/src/main/java/com/github/sardine/impl/SardineRedirectStrategy.java
deleted file mode 100644
index 023b6220..00000000
--- a/src/main/java/com/github/sardine/impl/SardineRedirectStrategy.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright 2009-2011 Jon Stevens et al.
- *
- * 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 com.github.sardine.impl;
-
-import org.apache.http.Header;
-import org.apache.http.HttpEntityEnclosingRequest;
-import org.apache.http.HttpRequest;
-import org.apache.http.HttpResponse;
-import org.apache.http.ProtocolException;
-import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
-import org.apache.http.client.methods.HttpUriRequest;
-import org.apache.http.impl.client.DefaultRedirectStrategy;
-import org.apache.http.protocol.HttpContext;
-
-import com.github.sardine.impl.methods.HttpPropFind;
-import com.github.sardine.impl.methods.HttpReport;
-
-public class SardineRedirectStrategy extends DefaultRedirectStrategy {
-
- @Override
- protected boolean isRedirectable(String method) {
- if (super.isRedirectable(method))
- {
- return true;
- }
- return method.equalsIgnoreCase(HttpPropFind.METHOD_NAME);
- }
-
- @Override
- public HttpUriRequest getRedirect(HttpRequest request, HttpResponse response, HttpContext context)
- throws ProtocolException
- {
- String method = request.getRequestLine().getMethod();
- if (method.equalsIgnoreCase(HttpPropFind.METHOD_NAME))
- {
- HttpPropFind propfind = new HttpPropFind(this.getLocationURI(request, response, context));
- Header depth = request.getFirstHeader("Depth");
- if (depth != null && depth.getValue() != null)
- {
- propfind.setDepth(depth.getValue());
- }
- return this.copyEntity(propfind, request);
- }
- else if (method.equalsIgnoreCase(HttpReport.METHOD_NAME))
- {
- HttpReport report = new HttpReport(this.getLocationURI(request, response, context));
- Header depth = request.getFirstHeader("Depth");
- if (depth != null && depth.getValue() != null)
- {
- report.setDepth(depth.getValue());
- }
- return this.copyEntity(report, request);
- }
- return super.getRedirect(request, response, context);
- }
-
- private HttpUriRequest copyEntity(final HttpEntityEnclosingRequestBase redirect, final HttpRequest original) {
- if (original instanceof HttpEntityEnclosingRequest)
- {
- redirect.setEntity(((HttpEntityEnclosingRequest) original).getEntity());
- }
- return redirect;
- }
-}
diff --git a/src/main/java/com/github/sardine/impl/handler/ETagResponseHandler.java b/src/main/java/com/github/sardine/impl/handler/ETagResponseHandler.java
index 5c1d89f6..23396149 100644
--- a/src/main/java/com/github/sardine/impl/handler/ETagResponseHandler.java
+++ b/src/main/java/com/github/sardine/impl/handler/ETagResponseHandler.java
@@ -18,12 +18,13 @@
import java.io.IOException;
-import org.apache.http.HttpHeaders;
-import org.apache.http.HttpResponse;
+import org.apache.hc.core5.http.ClassicHttpResponse;
+import org.apache.hc.core5.http.HttpHeaders;
+
public class ETagResponseHandler extends ValidatingResponseHandler {
@Override
- public String handleResponse(HttpResponse response) throws IOException {
+ public String handleResponse(ClassicHttpResponse response) throws IOException {
this.validateResponse(response);
if(response.containsHeader(HttpHeaders.ETAG)) {
return response.getFirstHeader(HttpHeaders.ETAG).getValue();
diff --git a/src/main/java/com/github/sardine/impl/handler/ExistsResponseHandler.java b/src/main/java/com/github/sardine/impl/handler/ExistsResponseHandler.java
index df6dfca1..b06e81ac 100644
--- a/src/main/java/com/github/sardine/impl/handler/ExistsResponseHandler.java
+++ b/src/main/java/com/github/sardine/impl/handler/ExistsResponseHandler.java
@@ -16,23 +16,24 @@
package com.github.sardine.impl.handler;
-import org.apache.http.HttpResponse;
-import org.apache.http.HttpStatus;
-import org.apache.http.StatusLine;
+
+import org.apache.hc.core5.http.ClassicHttpResponse;
+import org.apache.hc.core5.http.HttpStatus;
+import org.apache.hc.core5.http.message.StatusLine;
import com.github.sardine.impl.SardineException;
/**
- * {@link org.apache.http.client.ResponseHandler} which checks whether a given resource exists.
+ * {@link org.apache.hc.core5.http.io.HttpClientResponseHandler} which checks whether a given resource exists.
*
* @author mirko
*/
public class ExistsResponseHandler extends ValidatingResponseHandler
{
@Override
- public Boolean handleResponse(HttpResponse response) throws SardineException
+ public Boolean handleResponse(ClassicHttpResponse response) throws SardineException
{
- StatusLine statusLine = response.getStatusLine();
+ StatusLine statusLine = new StatusLine(response);
int statusCode = statusLine.getStatusCode();
if (statusCode < HttpStatus.SC_MULTIPLE_CHOICES)
{
diff --git a/src/main/java/com/github/sardine/impl/handler/HeadersResponseHandler.java b/src/main/java/com/github/sardine/impl/handler/HeadersResponseHandler.java
index 13a841e0..051add32 100644
--- a/src/main/java/com/github/sardine/impl/handler/HeadersResponseHandler.java
+++ b/src/main/java/com/github/sardine/impl/handler/HeadersResponseHandler.java
@@ -20,15 +20,16 @@
import java.util.HashMap;
import java.util.Map;
-import org.apache.http.Header;
-import org.apache.http.HttpResponse;
+import org.apache.hc.core5.http.ClassicHttpResponse;
+import org.apache.hc.core5.http.Header;
+
public class HeadersResponseHandler extends ValidatingResponseHandler