Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.github.sardine.impl.SardineImpl Maven / Gradle / Ivy
/*
* 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 com.github.sardine.DavAce;
import com.github.sardine.DavAcl;
import com.github.sardine.DavPrincipal;
import com.github.sardine.DavQuota;
import com.github.sardine.DavResource;
import com.github.sardine.Sardine;
import com.github.sardine.Version;
import com.github.sardine.impl.handler.ExistsResponseHandler;
import com.github.sardine.impl.handler.LockResponseHandler;
import com.github.sardine.impl.handler.MultiStatusResponseHandler;
import com.github.sardine.impl.handler.VoidResponseHandler;
import com.github.sardine.impl.io.ContentLengthInputStream;
import com.github.sardine.impl.io.HttpMethodReleaseInputStream;
import com.github.sardine.impl.methods.HttpAcl;
import com.github.sardine.impl.methods.HttpCopy;
import com.github.sardine.impl.methods.HttpLock;
import com.github.sardine.impl.methods.HttpMkCol;
import com.github.sardine.impl.methods.HttpMove;
import com.github.sardine.impl.methods.HttpPropFind;
import com.github.sardine.impl.methods.HttpPropPatch;
import com.github.sardine.impl.methods.HttpReport;
import com.github.sardine.impl.methods.HttpSearch;
import com.github.sardine.impl.methods.HttpUnlock;
import com.github.sardine.model.Ace;
import com.github.sardine.model.Acl;
import com.github.sardine.model.Allprop;
import com.github.sardine.model.Displayname;
import com.github.sardine.model.Exclusive;
import com.github.sardine.model.Group;
import com.github.sardine.model.Lockinfo;
import com.github.sardine.model.Lockscope;
import com.github.sardine.model.Locktype;
import com.github.sardine.model.Multistatus;
import com.github.sardine.model.ObjectFactory;
import com.github.sardine.model.Owner;
import com.github.sardine.model.PrincipalCollectionSet;
import com.github.sardine.model.PrincipalURL;
import com.github.sardine.model.Prop;
import com.github.sardine.model.Propertyupdate;
import com.github.sardine.model.Propfind;
import com.github.sardine.model.Propstat;
import com.github.sardine.model.QuotaAvailableBytes;
import com.github.sardine.model.QuotaUsedBytes;
import com.github.sardine.model.Remove;
import com.github.sardine.model.Resourcetype;
import com.github.sardine.model.Response;
import com.github.sardine.model.SearchRequest;
import com.github.sardine.model.Set;
import com.github.sardine.model.Write;
import com.github.sardine.report.SardineReport;
import com.github.sardine.util.SardineUtil;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
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.HttpDelete;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
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.BasicAuthCache;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
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.w3c.dom.Element;
import javax.xml.namespace.QName;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.ProxySelector;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Logger;
/**
* Implementation of the Sardine interface. This is where the meat of the Sardine library lives.
*
* @author jonstevens
*/
public class SardineImpl implements Sardine
{
private static final Logger log = Logger.getLogger(DavResource.class.getName());
private static final String UTF_8 = "UTF-8";
/**
* HTTP client implementation
*/
protected CloseableHttpClient client;
/**
* HTTP client configuration
*/
private HttpClientBuilder builder;
/**
* Local context with authentication cache. Make sure the same context is used to execute
* logically related requests.
*/
protected HttpClientContext context = HttpClientContext.create();
/**
* Access resources with no authentication
*/
public SardineImpl()
{
this.builder = this.configure(null, null);
this.client = this.builder.build();
}
/**
* Access resources with Bearer authorization
*/
public SardineImpl(String bearerAuth)
{
Header bearerHeader = new BasicHeader("Authorization", "Bearer " + bearerAuth);
this.builder = this.configure(null, null).setDefaultHeaders(Collections.singletonList(bearerHeader));
this.client = this.builder.build();
}
/**
* Supports standard authentication mechanisms
*
* @param username Use in authentication header credentials
* @param password Use in authentication header credentials
*/
public SardineImpl(String username, String password)
{
this.builder = this.configure(null, this.getCredentialsProvider(username, password, null, null));
this.client = this.builder.build();
}
/**
* @param username Use in authentication header credentials
* @param password Use in authentication header credentials
* @param selector Proxy configuration
*/
public SardineImpl(String username, String password, ProxySelector selector)
{
this.builder = this.configure(selector, this.getCredentialsProvider(username, password, null, null));
this.client = this.builder.build();
}
/**
* @param builder Custom client configuration
*/
public SardineImpl(HttpClientBuilder builder)
{
this.builder = builder;
this.client = this.builder.build();
}
/**
* @param builder Custom client configuration
* @param username Use in authentication header credentials
* @param password Use in authentication header credentials
*/
public SardineImpl(HttpClientBuilder builder, String username, String password)
{
this.builder = builder;
this.setCredentials(username, password);
this.client = this.builder.build();
}
/**
* Add credentials to any scope. Supports Basic, Digest and NTLM authentication methods.
*
* @param username Use in authentication header credentials
* @param password Use in authentication header credentials
*/
@Override
public void setCredentials(String username, String password)
{
this.setCredentials(username, password, "", "");
}
/**
* @param username Use in authentication header credentials
* @param password Use in authentication header credentials
* @param domain NTLM authentication
* @param workstation NTLM authentication
*/
@Override
public void setCredentials(String username, String password, String domain, String workstation)
{
this.context.setCredentialsProvider(this.getCredentialsProvider(username, password, domain, workstation));
this.context.setAttribute(HttpClientContext.TARGET_AUTH_STATE, new AuthState());
}
private CredentialsProvider getCredentialsProvider(String username, String password, String domain, String workstation)
{
CredentialsProvider provider = new BasicCredentialsProvider();
if (username != null)
{
provider.setCredentials(
new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, AuthSchemes.NTLM),
new NTCredentials(username, password, workstation, domain));
provider.setCredentials(
new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, AuthSchemes.BASIC),
new UsernamePasswordCredentials(username, password));
provider.setCredentials(
new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, AuthSchemes.DIGEST),
new UsernamePasswordCredentials(username, password));
provider.setCredentials(
new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, AuthSchemes.SPNEGO),
new UsernamePasswordCredentials(username, password));
provider.setCredentials(
new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, AuthSchemes.KERBEROS),
new UsernamePasswordCredentials(username, password));
}
return provider;
}
/**
* Adds handling of GZIP compression to the client.
*/
@Override
public void enableCompression()
{
this.builder.addInterceptorLast(new RequestAcceptEncoding());
this.builder.addInterceptorLast(new ResponseContentEncoding());
this.client = this.builder.build();
}
/**
* Disable GZIP compression header.
*/
@Override
public void disableCompression()
{
this.builder.disableContentCompression();
this.client = this.builder.build();
}
/**
* Ignores cookies by always returning the IgnoreSpecFactory regardless of the cookieSpec value being looked up.
*/
@Override
public void ignoreCookies()
{
this.builder.setDefaultCookieSpecRegistry(new Lookup()
{
@Override
public CookieSpecProvider lookup(String name)
{
return new IgnoreSpecProvider();
}
});
this.client = this.builder.build();
}
@Override
public void enablePreemptiveAuthentication(String hostname)
{
enablePreemptiveAuthentication(hostname, -1, -1);
}
@Override
public void enablePreemptiveAuthentication(URL url)
{
final String host = url.getHost();
final int port = url.getPort();
final String protocol = url.getProtocol();
final int httpPort;
final int httpsPort;
if ("https".equals(protocol))
{
httpsPort = port;
httpPort = -1;
}
else if ("http".equals(protocol))
{
httpPort = port;
httpsPort = -1;
}
else
{
throw new IllegalArgumentException("Unsupported protocol " + protocol);
}
enablePreemptiveAuthentication(host, httpPort, httpsPort);
}
@Override
public void enablePreemptiveAuthentication(String hostname, int httpPort, int httpsPort)
{
AuthCache cache = this.context.getAuthCache();
if (cache == null)
{
// Add AuthCache to the execution context
cache = new BasicAuthCache();
this.context.setAuthCache(cache);
}
// Generate Basic preemptive scheme object and stick it to the local execution context
BasicScheme basicAuth = new BasicScheme();
// Configure HttpClient to authenticate preemptively by prepopulating the authentication data cache.
cache.put(new HttpHost(hostname, httpPort, "http"), basicAuth);
cache.put(new HttpHost(hostname, httpsPort, "https"), basicAuth);
}
@Override
public void disablePreemptiveAuthentication()
{
this.context.removeAttribute(HttpClientContext.AUTH_CACHE);
}
@Override
public List getResources(String url) throws IOException
{
return this.list(url);
}
@Override
public List list(String url) throws IOException
{
return this.list(url, 1);
}
@Override
public List list(String url, int depth) throws IOException
{
return list(url, depth, true);
}
@Override
public List list(String url, int depth, boolean allProp) throws IOException
{
if (allProp)
{
Propfind body = new Propfind();
body.setAllprop(new Allprop());
return propfind(url, depth, body);
}
else
{
return list(url, depth, Collections.emptySet());
}
}
@Override
public List list(String url, int depth, java.util.Set props) throws IOException
{
Propfind body = new Propfind();
Prop prop = new Prop();
ObjectFactory objectFactory = new ObjectFactory();
prop.setGetcontentlength(objectFactory.createGetcontentlength());
prop.setGetlastmodified(objectFactory.createGetlastmodified());
prop.setCreationdate(objectFactory.createCreationdate());
prop.setDisplayname(objectFactory.createDisplayname());
prop.setGetcontenttype(objectFactory.createGetcontenttype());
prop.setResourcetype(objectFactory.createResourcetype());
prop.setGetetag(objectFactory.createGetetag());
addCustomProperties(prop, props);
body.setProp(prop);
return propfind(url, depth, body);
}
@Override
public List propfind(String url, int depth, java.util.Set props) throws IOException
{
Propfind body = new Propfind();
Prop prop = new Prop();
addCustomProperties(prop, props);
body.setProp(prop);
return propfind(url, depth, body);
}
private void addCustomProperties(Prop prop, java.util.Set props)
{
List any = prop.getAny();
for (QName entry : props)
{
Element element = SardineUtil.createElement(entry);
any.add(element);
}
}
protected List propfind(String url, int depth, Propfind body) throws IOException
{
HttpPropFind entity = new HttpPropFind(url);
entity.setDepth(depth < 0 ? "infinity" : Integer.toString(depth));
entity.setEntity(new StringEntity(SardineUtil.toXml(body), UTF_8));
Multistatus multistatus = this.execute(entity, new MultiStatusResponseHandler());
List responses = multistatus.getResponse();
List resources = new ArrayList(responses.size());
for (Response response : responses)
{
try
{
resources.add(new DavResource(response));
}
catch (URISyntaxException e)
{
log.warning(String.format("Ignore resource with invalid URI %s", response.getHref().get(0)));
}
}
return resources;
}
public T report(String url, int depth, SardineReport report) throws IOException
{
HttpReport entity = new HttpReport(url);
entity.setDepth(depth < 0 ? "infinity" : Integer.toString(depth));
entity.setEntity(new StringEntity(report.toXml(), 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);
SearchRequest searchBody = new SearchRequest(language, query);
String body = SardineUtil.toXml(searchBody);
search.setEntity(new StringEntity(body, UTF_8));
Multistatus multistatus = this.execute(search, new MultiStatusResponseHandler());
List responses = multistatus.getResponse();
List resources = new ArrayList(responses.size());
for (Response response : responses)
{
try
{
resources.add(new DavResource(response));
}
catch (URISyntaxException e)
{
log.warning(String.format("Ignore resource with invalid URI %s", response.getHref().get(0)));
}
}
return resources;
}
@Override
public void setCustomProps(String url, Map set, List remove) throws IOException
{
this.patch(url, SardineUtil.toQName(set), SardineUtil.toQName(remove));
}
@Override
public List patch(String url, Map setProps) throws IOException
{
return this.patch(url, setProps, Collections.emptyList());
}
/**
* Creates a {@link com.github.sardine.model.Propertyupdate} element containing all properties to set from setProps and all properties to
* remove from removeProps. Note this method will use a {@link com.github.sardine.util.SardineUtil#CUSTOM_NAMESPACE_URI} as
* namespace and {@link com.github.sardine.util.SardineUtil#CUSTOM_NAMESPACE_PREFIX} as prefix.
*/
@Override
public List patch(String url, Map setProps, List removeProps) throws IOException
{
List setPropsElements = new ArrayList();
for (Entry entry : setProps.entrySet())
{
Element element = SardineUtil.createElement(entry.getKey());
element.setTextContent(entry.getValue());
setPropsElements.add(element);
}
return this.patch(url, setPropsElements, removeProps);
}
/**
* Creates a {@link com.github.sardine.model.Propertyupdate} element containing all properties to set from setProps and all properties to
* remove from removeProps. Note this method will use a {@link com.github.sardine.util.SardineUtil#CUSTOM_NAMESPACE_URI} as
* namespace and {@link com.github.sardine.util.SardineUtil#CUSTOM_NAMESPACE_PREFIX} as prefix.
*/
@Override
public List patch(String url, List setProps, List removeProps) throws IOException
{
HttpPropPatch entity = new HttpPropPatch(url);
// Build WebDAV PROPPATCH
entity.
Propertyupdate body = new Propertyupdate();
// Add properties
{
Set set = new Set();
body.getRemoveOrSet().add(set);
Prop prop = new Prop();
// Returns a reference to the live list
List any = prop.getAny();
for (Element element : setProps)
{
any.add(element);
}
set.setProp(prop);
}
// Remove properties
{
Remove remove = new Remove();
body.getRemoveOrSet().add(remove);
Prop prop = new Prop();
// Returns a reference to the live list
List any = prop.getAny();
for (QName entry : removeProps)
{
Element element = SardineUtil.createElement(entry);
any.add(element);
}
remove.setProp(prop);
}
entity.setEntity(new StringEntity(SardineUtil.toXml(body), UTF_8));
Multistatus multistatus = this.execute(entity, new MultiStatusResponseHandler());
List responses = multistatus.getResponse();
List resources = new ArrayList(responses.size());
for (Response response : responses)
{
try
{
resources.add(new DavResource(response));
}
catch (URISyntaxException e)
{
log.warning(String.format("Ignore resource with invalid URI %s", response.getHref().get(0)));
}
}
return resources;
}
@Override
public String lock(String url) throws IOException
{
HttpLock entity = new HttpLock(url);
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);
entity.setEntity(new StringEntity(SardineUtil.toXml(body), UTF_8));
// Return the lock token
return this.execute(entity, new LockResponseHandler());
}
@Override
public String refreshLock(String url, String token, String file) throws IOException
{
HttpLock entity = new HttpLock(url);
entity.setHeader("If", "<" + file + "> (<" + token + ">)");
return this.execute(entity, new LockResponseHandler());
}
@Override
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());
}
@Override
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());
for (DavAce davAce : aces)
{
// protected and inherited acl must not be part of ACL http request
if (davAce.getInherited() != null || davAce.isProtected())
{
continue;
}
Ace ace = davAce.toModel();
body.getAce().add(ace);
}
entity.setEntity(new StringEntity(SardineUtil.toXml(body), UTF_8));
this.execute(entity, new VoidResponseHandler());
}
@Override
public DavAcl getAcl(String url) throws IOException
{
HttpPropFind entity = new HttpPropFind(url);
entity.setDepth("0");
Propfind body = new Propfind();
Prop prop = new Prop();
prop.setOwner(new Owner());
prop.setGroup(new Group());
prop.setAcl(new Acl());
body.setProp(prop);
entity.setEntity(new StringEntity(SardineUtil.toXml(body), UTF_8));
Multistatus multistatus = this.execute(entity, new MultiStatusResponseHandler());
List responses = multistatus.getResponse();
if (responses.isEmpty())
{
return null;
}
else
{
return new DavAcl(responses.get(0));
}
}
@Override
public DavQuota getQuota(String url) throws IOException
{
HttpPropFind entity = new HttpPropFind(url);
entity.setDepth("0");
Propfind body = new Propfind();
Prop prop = new Prop();
prop.setQuotaAvailableBytes(new QuotaAvailableBytes());
prop.setQuotaUsedBytes(new QuotaUsedBytes());
body.setProp(prop);
entity.setEntity(new StringEntity(SardineUtil.toXml(body), UTF_8));
Multistatus multistatus = this.execute(entity, new MultiStatusResponseHandler());
List responses = multistatus.getResponse();
if (responses.isEmpty())
{
return null;
}
else
{
return new DavQuota(responses.get(0));
}
}
@Override
public List getPrincipals(String url) throws IOException
{
HttpPropFind entity = new HttpPropFind(url);
entity.setDepth("1");
Propfind body = new Propfind();
Prop prop = new Prop();
prop.setDisplayname(new Displayname());
prop.setResourcetype(new Resourcetype());
prop.setPrincipalURL(new PrincipalURL());
body.setProp(prop);
entity.setEntity(new StringEntity(SardineUtil.toXml(body), UTF_8));
Multistatus multistatus = this.execute(entity, new MultiStatusResponseHandler());
List responses = multistatus.getResponse();
if (responses.isEmpty())
{
return null;
}
else
{
List collections = new ArrayList();
for (Response r : responses)
{
if (r.getPropstat() != null)
{
for (Propstat propstat : r.getPropstat())
{
if (propstat.getProp() != null
&& propstat.getProp().getResourcetype() != null
&& propstat.getProp().getResourcetype().getPrincipal() != null)
{
collections.add(new DavPrincipal(DavPrincipal.PrincipalType.HREF,
r.getHref().get(0),
propstat.getProp().getDisplayname().getContent().get(0)));
}
}
}
}
return collections;
}
}
@Override
public List getPrincipalCollectionSet(String url) throws IOException
{
HttpPropFind entity = new HttpPropFind(url);
entity.setDepth("0");
Propfind body = new Propfind();
Prop prop = new Prop();
prop.setPrincipalCollectionSet(new PrincipalCollectionSet());
body.setProp(prop);
entity.setEntity(new StringEntity(SardineUtil.toXml(body), UTF_8));
Multistatus multistatus = this.execute(entity, new MultiStatusResponseHandler());
List responses = multistatus.getResponse();
if (responses.isEmpty())
{
return null;
}
else
{
List collections = new ArrayList();
for (Response r : responses)
{
if (r.getPropstat() != null)
{
for (Propstat propstat : r.getPropstat())
{
if (propstat.getProp() != null
&& propstat.getProp().getPrincipalCollectionSet() != null
&& propstat.getProp().getPrincipalCollectionSet().getHref() != null)
{
collections.addAll(propstat.getProp().getPrincipalCollectionSet().getHref());
}
}
}
}
return collections;
}
}
@Override
public ContentLengthInputStream get(String url) throws IOException
{
return this.get(url, Collections.emptyMap());
}
@Override
public ContentLengthInputStream get(String url, Map headers) throws IOException
{
List list = new ArrayList();
for (Map.Entry h : headers.entrySet())
{
list.add(new BasicHeader(h.getKey(), h.getValue()));
}
return this.get(url, list);
}
public ContentLengthInputStream get(String url, List headers) throws IOException
{
HttpGet get = new HttpGet(url);
for (Header header : headers)
{
get.addHeader(header);
}
// Must use #execute without handler, otherwise the entity is consumed
// already after the handler exits.
HttpResponse response = this.execute(get);
VoidResponseHandler handler = new VoidResponseHandler();
try
{
handler.handleResponse(response);
// Will abort the read when closed before EOF.
return new ContentLengthInputStream(new HttpMethodReleaseInputStream(response), response.getEntity().getContentLength());
}
catch (IOException ex)
{
get.abort();
throw ex;
}
}
@Override
public void put(String url, byte[] data) throws IOException
{
this.put(url, data, null);
}
@Override
public void put(String url, byte[] data, String contentType) throws IOException
{
ByteArrayEntity entity = new ByteArrayEntity(data);
this.put(url, entity, contentType, true);
}
@Override
public void put(String url, InputStream dataStream) throws IOException
{
this.put(url, dataStream, (String) null);
}
@Override
public void put(String url, InputStream dataStream, String contentType) throws IOException
{
this.put(url, dataStream, contentType, true);
}
@Override
public void put(String url, InputStream dataStream, String contentType, boolean expectContinue) throws IOException
{
// A length of -1 means "go until end of stream"
put(url, dataStream, contentType, expectContinue, -1);
}
@Override
public void put(String url, InputStream dataStream, String contentType, boolean expectContinue, long contentLength) throws IOException
{
InputStreamEntity entity = new InputStreamEntity(dataStream, contentLength);
this.put(url, entity, contentType, expectContinue);
}
@Override
public void put(String url, InputStream dataStream, Map headers) throws IOException
{
List list = new ArrayList();
for (Map.Entry h : headers.entrySet())
{
list.add(new BasicHeader(h.getKey(), h.getValue()));
}
this.put(url, dataStream, list);
}
public void put(String url, InputStream dataStream, List headers) throws IOException
{
// A length of -1 means "go until end of stream"
InputStreamEntity entity = new InputStreamEntity(dataStream, -1);
this.put(url, entity, headers);
}
/**
* Upload the entity using PUT
*
* @param url Resource
* @param entity The entity to read from
* @param contentType Content Type header
* @param expectContinue Add Expect: continue
header
*/
public void put(String url, HttpEntity entity, String contentType, boolean expectContinue) throws IOException
{
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));
}
this.put(url, entity, headers);
}
/**
* Upload the entity using PUT
*
* @param url Resource
* @param entity The entity to read from
* @param headers Headers to add to request
*/
public void put(String url, HttpEntity entity, List headers) throws IOException
{
this.put(url, entity, headers, new VoidResponseHandler());
}
public T put(String url, HttpEntity entity, List headers, ResponseHandler handler) throws IOException
{
HttpPut put = new HttpPut(url);
put.setEntity(entity);
for (Header header : headers)
{
put.addHeader(header);
}
if (entity.getContentType() == null && !put.containsHeader(HttpHeaders.CONTENT_TYPE))
{
put.addHeader(HttpHeaders.CONTENT_TYPE, HTTP.DEF_CONTENT_CHARSET.name());
}
try
{
return this.execute(put, handler);
}
catch (HttpResponseException e)
{
if (e.getStatusCode() == HttpStatus.SC_EXPECTATION_FAILED)
{
// Retry with the Expect header removed
put.removeHeaders(HTTP.EXPECT_DIRECTIVE);
if (entity.isRepeatable())
{
return this.execute(put, handler);
}
}
throw e;
}
}
@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
put(url, localFile, contentType, false);
}
@Override
public void put(String url, File localFile, String contentType, boolean expectContinue) throws IOException
{
FileEntity content = new FileEntity(localFile);
this.put(url, content, contentType, expectContinue);
}
@Override
public void delete(String url) throws IOException
{
HttpDelete delete = new HttpDelete(url);
this.execute(delete, new VoidResponseHandler());
}
@Override
public void move(String sourceUrl, String destinationUrl) throws IOException
{
move(sourceUrl, destinationUrl, true);
}
@Override
public void move(String sourceUrl, String destinationUrl, boolean overwrite) throws IOException
{
HttpMove move = new HttpMove(sourceUrl, destinationUrl, overwrite);
this.execute(move, new VoidResponseHandler());
}
@Override
public void copy(String sourceUrl, String destinationUrl) throws IOException
{
copy(sourceUrl, destinationUrl, true);
}
@Override
public void copy(String sourceUrl, String destinationUrl, boolean overwrite) throws IOException
{
HttpCopy copy = new HttpCopy(sourceUrl, destinationUrl, overwrite);
this.execute(copy, new VoidResponseHandler());
}
@Override
public void createDirectory(String url) throws IOException
{
HttpMkCol mkcol = new HttpMkCol(url);
this.execute(mkcol, new VoidResponseHandler());
}
@Override
public boolean exists(String url) throws IOException
{
HttpHead head = new HttpHead(url);
return this.execute(head, new ExistsResponseHandler());
}
/**
* Validate the response using the response handler. Aborts the request if there is an exception.
*
* @param Return type
* @param request Request to execute
* @param responseHandler Determines the return type.
* @return parsed response
*/
protected T execute(HttpRequestBase request, ResponseHandler responseHandler)
throws IOException
{
return execute(context, request, responseHandler);
}
/**
* No validation of the response. Aborts the request if there is an exception.
*
* @param request Request to execute
* @return The response to check the reply status code
*/
protected HttpResponse execute(HttpRequestBase request)
throws IOException
{
return execute(context, request, null);
}
/**
* Common method as single entry point responsible fo request execution
* @param context clientContext to be used when executing request
* @param request Request to execute
* @param responseHandler can be null if you need raw HttpResponse or not null response handler for result handling.
* @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)
throws IOException
{
try
{
HttpContext requestLocalContext = new BasicHttpContext(context);
if (responseHandler != null)
{
return this.client.execute(request, responseHandler, requestLocalContext);
}
else
{
return (T) this.client.execute(request, requestLocalContext);
}
}
catch (HttpResponseException e)
{
// Don't abort if we get this exception, caller may want to repeat request.
throw e;
}
catch (IOException e)
{
request.abort();
throw e;
}
}
@Override
public void shutdown() throws IOException
{
this.client.close();
}
/**
* Creates a client with all of the defaults.
*
* @param selector Proxy configuration or null
* @param credentials Authentication credentials or null
*/
protected HttpClientBuilder configure(ProxySelector selector, CredentialsProvider credentials)
{
Registry schemeRegistry = this.createDefaultSchemeRegistry();
HttpClientConnectionManager cm = this.createDefaultConnectionManager(schemeRegistry);
String version = Version.getSpecification();
if (version == null)
{
version = VersionInfo.UNAVAILABLE;
}
return HttpClients.custom()
.setUserAgent("Sardine/" + version)
.setDefaultCredentialsProvider(credentials)
.setRedirectStrategy(this.createDefaultRedirectStrategy())
.setDefaultRequestConfig(RequestConfig.custom()
// Only selectively enable this for PUT but not all entity enclosing methods
.setExpectContinueEnabled(false).build())
.setConnectionManager(cm)
.setRoutePlanner(this.createDefaultRoutePlanner(this.createDefaultSchemePortResolver(), selector));
}
protected DefaultSchemePortResolver createDefaultSchemePortResolver()
{
return new DefaultSchemePortResolver();
}
protected SardineRedirectStrategy createDefaultRedirectStrategy()
{
return new SardineRedirectStrategy();
}
/**
* Creates a new registry for default ports with socket factories.
*/
protected Registry createDefaultSchemeRegistry()
{
return RegistryBuilder.create()
.register("http", this.createDefaultSocketFactory())
.register("https", this.createDefaultSecureSocketFactory())
.build();
}
/**
* @return Default socket factory
*/
protected ConnectionSocketFactory createDefaultSocketFactory()
{
return PlainConnectionSocketFactory.getSocketFactory();
}
/**
* @return Default SSL socket factory
*/
protected ConnectionSocketFactory createDefaultSecureSocketFactory()
{
return SSLConnectionSocketFactory.getSocketFactory();
}
/**
* Use fail fast connection manager when connections are not released properly.
*
* @param schemeRegistry Protocol registry
* @return Default connection manager
*/
protected HttpClientConnectionManager createDefaultConnectionManager(Registry schemeRegistry)
{
return new PoolingHttpClientConnectionManager(schemeRegistry);
}
/**
* Override to provide proxy configuration
*
* @param resolver Protocol registry
* @param selector Proxy configuration
* @return ProxySelectorRoutePlanner configured with schemeRegistry and selector
*/
protected HttpRoutePlanner createDefaultRoutePlanner(SchemePortResolver resolver, ProxySelector selector)
{
return new SystemDefaultRoutePlanner(resolver, selector);
}
}