/* * Лицензионное соглашение на использование набора средств разработки * «SDK Яндекс.Диска» доступно по адресу: http://legal.yandex.ru/sdk_agreement * */ package com.yandex.disk.client; import android.content.Context; import android.text.TextUtils; import android.util.Log; import com.yandex.disk.client.exceptions.CancelledDownloadException; import com.yandex.disk.client.exceptions.CancelledPropfindException; import com.yandex.disk.client.exceptions.DuplicateFolderException; import com.yandex.disk.client.exceptions.FileDownloadException; import com.yandex.disk.client.exceptions.FileTooBigServerException; import com.yandex.disk.client.exceptions.FilesLimitExceededServerException; import com.yandex.disk.client.exceptions.IntermediateFolderNotExistException; import com.yandex.disk.client.exceptions.PreconditionFailedException; import com.yandex.disk.client.exceptions.RangeNotSatisfiableException; import com.yandex.disk.client.exceptions.ServerWebdavException; import com.yandex.disk.client.exceptions.UnknownServerWebdavException; import com.yandex.disk.client.exceptions.UnsupportedMediaTypeException; import com.yandex.disk.client.exceptions.WebdavClientInitException; import com.yandex.disk.client.exceptions.WebdavException; import com.yandex.disk.client.exceptions.WebdavFileNotFoundException; import com.yandex.disk.client.exceptions.WebdavForbiddenException; import com.yandex.disk.client.exceptions.WebdavInvalidUserException; import com.yandex.disk.client.exceptions.WebdavNotAuthorizedException; import com.yandex.disk.client.exceptions.WebdavUserNotInitialized; import com.yandex.disk.client.exceptions.WebdavSharingForbiddenException; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.HttpVersion; import org.apache.http.StatusLine; import org.apache.http.client.HttpClient; import org.apache.http.client.HttpRequestRetryHandler; import org.apache.http.client.RedirectHandler; import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpHead; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.conn.ClientConnectionManager; import org.apache.http.conn.params.ConnManagerParams; import org.apache.http.conn.scheme.PlainSocketFactory; import org.apache.http.conn.scheme.Scheme; import org.apache.http.conn.scheme.SchemeRegistry; import org.apache.http.conn.ssl.SSLSocketFactory; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.BasicCookieStore; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.client.DefaultRedirectHandler; import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.CoreProtocolPNames; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; import org.apache.http.params.HttpProtocolParams; import org.apache.http.protocol.BasicHttpContext; import org.apache.http.protocol.HTTP; import org.apache.http.protocol.HttpContext; import org.xmlpull.v1.XmlPullParserException; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLEncoder; import java.security.GeneralSecurityException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.regex.Matcher; import java.util.regex.Pattern; public class TransportClient { private static final String TAG = "TransportClient"; protected static URL serverURL; static { try { serverURL = new URL("https://webdav.yandex.ru:443"); } catch (MalformedURLException ex) { throw new RuntimeException(ex); } } protected static final String userAgent = "Webdav Android Client Example/1.0"; protected static final String LOCATION_HEADER = "Location"; protected static final String NO_REDIRECT_CONTEXT = "yandex.no-redirect"; protected static final String WEBDAV_PROTO_DEPTH = "Depth"; protected static final int NETWORK_TIMEOUT = 30000; protected static final int UPLOAD_NETWORK_TIMEOUT = NETWORK_TIMEOUT * 10; protected Context context; protected Credentials creds; protected final HttpClient httpClient; public static TransportClient getInstance(Context context, Credentials credentials) throws WebdavClientInitException { return new TransportClient(context, credentials, NETWORK_TIMEOUT); } public static TransportClient getUploadInstance(Context context, Credentials credentials) throws WebdavClientInitException { return new TransportClient(context, credentials, UPLOAD_NETWORK_TIMEOUT); } public TransportClient(Context context, Credentials credentials, HttpClient httpClient) throws WebdavClientInitException { this.context = context; this.creds = credentials; this.httpClient = httpClient; } protected TransportClient(Context context, Credentials credentials, int timeout) throws WebdavClientInitException { this(context, credentials, userAgent, timeout); } protected TransportClient(Context context, Credentials credentials, String userAgent, int timeout) throws WebdavClientInitException { this.context = context; this.creds = credentials; DefaultHttpClient httpClient = getNewHttpClient(userAgent, timeout); httpClient.setCookieStore(new BasicCookieStore()); this.httpClient = httpClient; } protected static DefaultHttpClient getNewHttpClient(String userAgent, int timeout) throws WebdavClientInitException { HttpParams params = new BasicHttpParams(); HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); HttpProtocolParams.setContentCharset(params, HTTP.UTF_8); HttpConnectionParams.setSocketBufferSize(params, 8192); HttpConnectionParams.setConnectionTimeout(params, timeout); HttpConnectionParams.setSoTimeout(params, timeout); ConnManagerParams.setMaxTotalConnections(params, 1); SSLSocketFactory sf; try { sf = new SSLSocketFactoryWithTimeout(timeout); } catch (GeneralSecurityException ex) { Log.e(TAG, "getNewHttpClient", ex); throw new WebdavClientInitException(); } sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER); SchemeRegistry registry = new SchemeRegistry(); registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); registry.register(new Scheme("https", sf, 443)); ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry); DefaultHttpClient res = new DefaultHttpClient(ccm, params); if (userAgent != null) { res.getParams().setParameter(CoreProtocolPNames.USER_AGENT, userAgent); } res.getParams().setParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, true); res.getParams().setParameter(CoreProtocolPNames.WAIT_FOR_CONTINUE, timeout); res.setHttpRequestRetryHandler(requestRetryHandler); res.setRedirectHandler(redirectHandler); return res; } private static final HttpRequestRetryHandler requestRetryHandler = new HttpRequestRetryHandler() { @Override public boolean retryRequest(IOException ex, int count, HttpContext httpContext) { return false; } }; private static final RedirectHandler redirectHandler = new DefaultRedirectHandler() { @Override public boolean isRedirectRequested(HttpResponse httpResponse, HttpContext httpContext) { Object noRedirect = httpContext.getAttribute(NO_REDIRECT_CONTEXT); if (noRedirect != null && (Boolean) noRedirect) { return false; } return super.isRedirectRequested(httpResponse, httpContext); } }; protected HttpResponse executeRequest(HttpUriRequest request) throws IOException { return httpClient.execute(request, (HttpContext)null); } protected HttpResponse executeRequest(HttpUriRequest request, HttpContext httpContext) throws IOException { return httpClient.execute(request, httpContext); } public void shutdown() { httpClient.getConnectionManager().shutdown(); } public static void shutdown(TransportClient client) { if (client != null) { client.shutdown(); } } protected String getUrl() { return serverURL.toExternalForm(); } protected static void consumeContent(HttpResponse response) throws IOException { HttpEntity entity = response.getEntity(); if (entity != null) { entity.consumeContent(); } } public static String encodeURL(String url) { if (url == null) { return null; } String[] segments = url.split("/"); StringBuilder sb = new StringBuilder(20); try { for (String segment : segments) { if (!"".equals(segment)) { sb.append("/").append(URLEncoder.encode(segment, "UTF-8")); } } Log.d(TAG, "url encoded: "+sb.toString()); } catch (UnsupportedEncodingException e) { Log.d(TAG, "Exception occured: "+e.getMessage()); } return sb.toString().replace("+", "%20"); } protected static void logMethod(HttpRequestBase method) { logMethod(method, null); } protected static void logMethod(HttpRequestBase method, String add) { Log.d(TAG, "logMethod(): "+method.getMethod()+": "+method.getURI()+(add != null ? " "+add : "")); } public enum HashType { MD5, SHA256 } public static byte[] makeHashBytes(File file, HashType hashType) throws IOException { FileInputStream is = null; try { is = new FileInputStream(file); MessageDigest digest; try { digest = MessageDigest.getInstance(hashType.name()); } catch (NoSuchAlgorithmException ex) { throw new RuntimeException(ex); } byte[] buf = new byte[8192]; int count; while ((count = is.read(buf)) > 0) { digest.update(buf, 0, count); } return digest.digest(); } finally { if (is != null) { is.close(); } } } public static String makeHash(File file, HashType hashType) throws IOException { long time = System.currentTimeMillis(); String hash = hash(makeHashBytes(file, hashType)); Log.d(TAG, hashType.name()+": "+file.getAbsolutePath()+" hash="+hash+" time="+(System.currentTimeMillis()-time)); return hash; } public static String hash(byte[] bytes) { if (bytes == null) { return null; } StringBuilder out = new StringBuilder(); for (byte b : bytes) { String n = Integer.toHexString(b & 0x000000FF); if (n.length() == 1) { out.append('0'); } out.append(n); } return out.toString(); } protected void checkStatusCodes(HttpResponse response, String details) throws WebdavNotAuthorizedException, WebdavUserNotInitialized, FileTooBigServerException, FilesLimitExceededServerException, ServerWebdavException, PreconditionFailedException, UnknownServerWebdavException { StatusLine statusLine = response.getStatusLine(); int statusCode = statusLine.getStatusCode(); switch (statusCode) { case 401: Log.d(TAG, "Not authorized: "+statusLine.getReasonPhrase()); throw new WebdavNotAuthorizedException(statusLine.getReasonPhrase() != null ? statusLine.getReasonPhrase() : ""); case 403: Log.d(TAG, "User not initialized: "+statusLine.getReasonPhrase()); throw new WebdavUserNotInitialized("Error (http code 403): "+details); case 412: Log.d(TAG, "Http code 412 (Precondition failed): "+details); throw new PreconditionFailedException("Error (http code 412): "+details); case 413: Log.d(TAG, "Http code 413 (File too big): "+details); throw new FileTooBigServerException(); case 507: Log.d(TAG, "Http code 507 (Insufficient Storage): "+details); throw new FilesLimitExceededServerException(); default: if (statusCode >= 500 && statusCode < 600) { Log.d(TAG, "Server error "+statusCode); throw new ServerWebdavException("Server error while "+details); } else { Log.d(TAG, "Unknown code "+statusCode); UnknownServerWebdavException exception = new UnknownServerWebdavException("Server error while "+details); exception.statusCode = statusCode; throw exception; } } } private static final String PROPFIND_REQUEST = "<?xml version='1.0' encoding='utf-8' ?>"+ "<d:propfind xmlns:d='DAV:'>"+ "<d:prop xmlns:m='urn:yandex:disk:meta'>"+ "<d:resourcetype/>"+ "<d:displayname/>"+ "<d:getcontentlength/>"+ "<d:getlastmodified/>"+ "<d:getetag/>"+ "<d:getcontenttype/>"+ "<m:alias_enabled/>"+ "<m:visible/>"+ "<m:shared/>"+ "<m:readonly/>"+ "<m:public_url/>"+ "<m:etime/>"+ "</d:prop>"+ "</d:propfind>"; private static final int MAX_ITEMS_PER_PAGE = Integer.MAX_VALUE; /** * Get folder listing * * @param path Path to the folder * @param handler Parsing handler * @throws CancelledPropfindException Cancelled by user * @throws WebdavException Server exceptions * @throws IOException I/O exceptions * @see #getList(String, int, String, String, ListParsingHandler) */ public void getList(String path, ListParsingHandler handler) throws WebdavException, IOException { getList(path, MAX_ITEMS_PER_PAGE, null, null, handler); } public void getList(String path, int itemsPerPage, ListParsingHandler handler) throws WebdavException, IOException { getList(path, itemsPerPage, null, null, handler); } /** * Get folder listing * * @param path Path to the folder * @param itemsPerPage Size of one portion per request * @param handler Parsing handler * @throws CancelledPropfindException Cancelled by user * @throws WebdavException Server exceptions * @throws IOException I/O exceptions */ public void getList(String path, int itemsPerPage, String sortBy, String orderBy, ListParsingHandler handler) throws WebdavException, IOException { Log.d(TAG, "getList for "+path); boolean itemsFinished = false; int offset = 0; while (!itemsFinished) { if (handler.hasCancelled()) { throw new CancelledPropfindException(); } String url = getUrl()+encodeURL(path); if (itemsPerPage != MAX_ITEMS_PER_PAGE) { url += "?offset="+offset+"&amount="+itemsPerPage; if (sortBy != null && orderBy != null) { url += "&sort="+sortBy+"&order="+orderBy; } } PropFind propFind = new PropFind(url); logMethod(propFind); creds.addAuthHeader(propFind); propFind.setHeader(WEBDAV_PROTO_DEPTH, "1"); propFind.setEntity(new StringEntity(PROPFIND_REQUEST)); HttpResponse response = executeRequest(propFind); StatusLine statusLine = response.getStatusLine(); if (statusLine != null) { int code = statusLine.getStatusCode(); switch (code) { case 207: break; case 401: consumeContent(response); throw new WebdavNotAuthorizedException(statusLine.getReasonPhrase() != null ? statusLine.getReasonPhrase() : ""); case 402: consumeContent(response); throw new WebdavInvalidUserException(); case 403: consumeContent(response); throw new WebdavForbiddenException(); case 404: consumeContent(response); throw new WebdavFileNotFoundException("Directory not found: "+path); default: consumeContent(response); checkStatusCodes(response, "PROPFIND "+path); } } HttpEntity entity = response.getEntity(); int countOnPage; try { ListParser parser = new ListParser(entity, handler); parser.parse(); countOnPage = parser.getParsedCount(); Log.d(TAG, "countOnPage="+countOnPage); } catch (XmlPullParserException ex) { throw new WebdavException(ex); } finally { consumeContent(response); } if (countOnPage != itemsPerPage) { itemsFinished = true; } offset += itemsPerPage; } } /** * Check unfinished upload * * @param file File to upload * @param dir Folder on the server * @param destName Name on the server * @param md5 MD5 hash * @return File size on the server. Possibly 0 if no unfinished uploadings * @throws IOException I/O exceptions * @throws WebdavException Webdav exceptions * @throws NumberFormatException Invalid size format from the server */ public long headFile(File file, String dir, String destName, String md5, String sha256) throws IOException, NumberFormatException, WebdavUserNotInitialized, UnknownServerWebdavException, PreconditionFailedException, WebdavNotAuthorizedException, ServerWebdavException { String url = getUrl()+encodeURL(dir+"/"+destName); HttpHead head = new HttpHead(url); logMethod(head, ", file "+file); creds.addAuthHeader(head); head.addHeader("Etag", md5); if (sha256 != null) { head.addHeader("Sha256", sha256); } head.addHeader("Size", String.valueOf(file.length())); HttpResponse response = executeRequest(head); consumeContent(response); StatusLine statusLine = response.getStatusLine(); if (statusLine != null) { int statusCode = statusLine.getStatusCode(); if (statusLine.getStatusCode() == 200) { // Log.d(TAG, "200 "+statusLine.getReasonPhrase()+" for file "+file.getAbsolutePath()+" in dir "+dir); Header[] headers = response.getHeaders("Content-Length"); if (headers.length > 0) { String contentLength = headers[0].getValue(); // Log.d(TAG, "Content-Length: "+contentLength); return Long.valueOf(contentLength); } else { return 0; } } else if (statusCode == 409 || statusCode == 404 || statusCode == 412) { Log.d(TAG, statusLine+" for file "+file.getAbsolutePath()+" in dir "+dir); return 0; } checkStatusCodes(response, "HEAD "+url); } return 0; } /** * Upload file * * @param localPath Local file path * @param serverDir Server folder to upload * @param progressListener Listener to show progress to application * @throws WebdavException Server exeptions * @throws IOException I/O exceptions */ public void uploadFile(String localPath, String serverDir, ProgressListener progressListener) throws IOException, UnknownServerWebdavException, PreconditionFailedException, IntermediateFolderNotExistException, WebdavUserNotInitialized, ServerWebdavException, WebdavNotAuthorizedException { File file = new File(localPath); uploadFile(file, serverDir, file.getName(), makeHash(file, HashType.MD5), null, progressListener); } /** * Upload file * * @param file Local file * @param dir Server folder to upload * @param destFileName File name on the server * @param md5 MD5 hash * @param progressListener Listener to show progress to application * @throws WebdavException Server exceptions * @throws IOException I/O exceptions */ public void uploadFile(File file, String dir, String destFileName, String md5, String sha256, final ProgressListener progressListener) throws IntermediateFolderNotExistException, IOException, WebdavUserNotInitialized, PreconditionFailedException, WebdavNotAuthorizedException, ServerWebdavException, UnknownServerWebdavException { String destName = TextUtils.isEmpty(destFileName) ? file.getName() : destFileName; String url = getUrl()+encodeURL(dir+"/"+destName); Log.d(TAG, "uploadFile: put to "+getUrl()+dir+"/"+destName); long uploadedSize; try { uploadedSize = headFile(file, dir, destName, md5, sha256); } catch (NumberFormatException ex) { Log.w(TAG, "Uploading "+file.getAbsolutePath()+" to "+dir+": HEAD failed", ex); uploadedSize = 0; } HttpPut put = new HttpPut(url); creds.addAuthHeader(put); put.addHeader("Etag", md5); if (sha256 != null) { Log.d(TAG, "Sha256: "+sha256); put.addHeader("Sha256", sha256); } if (uploadedSize > 0) { StringBuffer contentRange = new StringBuffer(); contentRange.append("bytes ").append(uploadedSize).append("-").append(file.length()-1).append("/").append(file.length()); Log.d(TAG, "Content-Range: "+contentRange); put.addHeader("Content-Range", contentRange.toString()); } HttpEntity entity = new FileProgressHttpEntity(file, uploadedSize, progressListener); put.setEntity(entity); logMethod(put, ", file to upload "+file); HttpResponse response = executeRequest(put); StatusLine statusLine = response.getStatusLine(); if (statusLine != null) { consumeContent(response); switch (statusLine.getStatusCode()) { case 201: Log.d(TAG, "File uploaded successfully: "+file); return; case 409: Log.d(TAG, "Parent not exist for dir "+dir); throw new IntermediateFolderNotExistException("Parent folder not exists for '"+dir+"'"); default: checkStatusCodes(response, "PUT '"+file+"' to "+url); } } } public void downloadFile(String path, OutputStream fos, ProgressListener progressListener) throws IOException, WebdavUserNotInitialized, PreconditionFailedException, WebdavNotAuthorizedException, ServerWebdavException, CancelledDownloadException, UnknownServerWebdavException { downloadFile(path, fos, 0, 0, progressListener); } public void downloadFile(String path, OutputStream fos, long length, long fileSize, ProgressListener progressListener) throws IOException, WebdavUserNotInitialized, PreconditionFailedException, WebdavNotAuthorizedException, ServerWebdavException, CancelledDownloadException, UnknownServerWebdavException { String url = getUrl()+encodeURL(path); HttpGet get = new HttpGet(url); //logMethod(get, " to "+saveTo); creds.addAuthHeader(get); if (length > 0) { StringBuffer contentRange = new StringBuffer(); contentRange.append("bytes=").append(length).append("-"); if (fileSize > 0) { contentRange.append(fileSize-1); } Log.d(TAG, "Range: "+contentRange); get.addHeader("Range", contentRange.toString()); } boolean partialContent = false; HttpResponse httpResponse = executeRequest(get); StatusLine statusLine = httpResponse.getStatusLine(); if (statusLine != null) { int statusCode = statusLine.getStatusCode(); switch (statusCode) { case 200: // OK break; case 206: partialContent = true; break; case 404: consumeContent(httpResponse); throw new FileDownloadException("error while downloading file "+url); case 416: consumeContent(httpResponse); throw new RangeNotSatisfiableException("error while downloading file "+url); default: checkStatusCodes(httpResponse, "GET '"+url+"'"); break; } } HttpEntity response = httpResponse.getEntity(); long contentLength = response.getContentLength(); Log.d(TAG, "downloadFile: contentLength="+contentLength); long loaded; if (partialContent) { ContentRangeResponse contentRangeResponse = parseContentRangeHeader(httpResponse.getLastHeader("Content-Range")); Log.d(TAG, "downloadFile: contentRangeResponse="+contentRangeResponse); if (contentRangeResponse != null) { loaded = contentRangeResponse.getStart(); contentLength = contentRangeResponse.getSize(); } else { loaded = length; contentLength = fileSize; } } else { loaded = 0; if (contentLength < 0) { contentLength = 0; } } int count; InputStream content = response.getContent(); //FileOutputStream fos = new FileOutputStream(saveTo, partialContent); try { final byte[] downloadBuffer = new byte[1024]; while ((count = content.read(downloadBuffer)) != -1) { if (progressListener.hasCancelled()) { Log.i(TAG, "Downloading "+path+" canceled"); get.abort(); throw new CancelledDownloadException(); } fos.write(downloadBuffer, 0, count); loaded += count; progressListener.updateProgress(loaded, contentLength); } } catch (CancelledDownloadException ex) { throw ex; } catch (Exception e) { Log.w(TAG, e); get.abort(); if (e instanceof IOException) { throw (IOException) e; } else if (e instanceof RuntimeException) { throw (RuntimeException) e; } else { // never happen throw new RuntimeException(e); } } finally { try { fos.close(); } catch (IOException ex) { // nothing } try { response.consumeContent(); } catch (IOException e) { Log.w(TAG, e); } } } private static Pattern CONTENT_RANGE_HEADER_PATTERN = Pattern.compile("bytes\\D+(\\d+)-\\d+/(\\d+)"); private ContentRangeResponse parseContentRangeHeader(Header header) { if (header == null) { return null; } Log.d(TAG, header.getName()+": "+header.getValue()); Matcher matcher = CONTENT_RANGE_HEADER_PATTERN.matcher(header.getValue()); if (!matcher.matches()) { return null; } try { return new ContentRangeResponse(Long.parseLong(matcher.group(1)), Long.parseLong(matcher.group(2))); } catch (IllegalStateException ex) { Log.d(TAG, "parseContentRangeHeader: "+header, ex); return null; } catch (NumberFormatException ex) { Log.d(TAG, "parseContentRangeHeader: "+header, ex); return null; } } /** * Make folder * * @param dir Path to create * @throws WebdavException Server exceptions * @throws IOException I/O exceptions * @see <a href="http://www.webdav.org/specs/rfc4918.html#METHOD_MKCOL">RFC 4918</a> */ public void makeFolder(String dir) throws IOException, DuplicateFolderException, IntermediateFolderNotExistException, WebdavUserNotInitialized, PreconditionFailedException, WebdavNotAuthorizedException, ServerWebdavException, UnsupportedMediaTypeException, UnknownServerWebdavException { String url = getUrl()+encodeURL(dir); HttpMkcol mkcol = new HttpMkcol(url); logMethod(mkcol); creds.addAuthHeader(mkcol); HttpResponse response = executeRequest(mkcol); consumeContent(response); StatusLine statusLine = response.getStatusLine(); if (statusLine != null) { int statusCode = statusLine.getStatusCode(); switch (statusCode) { case 201: Log.d(TAG, "Folder created successfully"); return; case 405: throw new DuplicateFolderException("Folder '"+dir+"' already exists"); case 409: throw new IntermediateFolderNotExistException("Parent folder not exists for '"+dir+"'"); case 415: throw new UnsupportedMediaTypeException("Folder '"+dir+"' creation error (http code 415)"); default: checkStatusCodes(response, "MKCOL '"+dir+"'"); } } } /** * Delete * * @param path Path to delete * @throws WebdavException Server exceptions * @throws IOException I/O exceptions */ public void delete(String path) throws IOException, WebdavFileNotFoundException, WebdavUserNotInitialized, UnknownServerWebdavException, PreconditionFailedException, WebdavNotAuthorizedException, ServerWebdavException { String url = getUrl()+encodeURL(path); HttpDelete delete = new HttpDelete(url); logMethod(delete); creds.addAuthHeader(delete); HttpResponse response = executeRequest(delete); consumeContent(response); StatusLine statusLine = response.getStatusLine(); if (statusLine != null) { switch (statusLine.getStatusCode()) { case 200: Log.d(TAG, "Delete successfully completed"); return; case 404: throw new WebdavFileNotFoundException("'"+path+"' cannot be deleted"); default: checkStatusCodes(response, "DELETE '"+path+"'"); } } } public void move(String src, String dest) throws WebdavException, IOException { Move move = new Move(getUrl()+encodeURL(src)); move.setHeader("Destination", encodeURL(dest)); move.setHeader("Overwrite", "F"); logMethod(move, "to "+encodeURL(dest)); creds.addAuthHeader(move); HttpResponse response = executeRequest(move); consumeContent(response); StatusLine statusLine = response.getStatusLine(); if (statusLine != null) { int statusCode = statusLine.getStatusCode(); switch (statusCode) { case 201: Log.d(TAG, "Rename successfully completed"); return; case 202: case 207: Log.d(TAG, "HTTP code "+statusCode+": "+statusLine); return; case 404: throw new WebdavFileNotFoundException("'"+src+"' not found"); case 409: throw new DuplicateFolderException("File or folder "+dest+" already exist"); default: checkStatusCodes(response, "MOVE '"+src+"' to '"+dest+"'"); } } } public String publish(String path) throws IOException, WebdavException { // String path = item.getFullName(); HttpPost post = new HttpPost(getUrl()+encodeURL(path)+"?publish"); logMethod(post, "(publish)"); creds.addAuthHeader(post); HttpContext shareHttpContext = new BasicHttpContext(); shareHttpContext.setAttribute(NO_REDIRECT_CONTEXT, true); HttpResponse httpResponse = executeRequest(post, shareHttpContext); consumeContent(httpResponse); StatusLine statusLine = httpResponse.getStatusLine(); if (statusLine != null) { int statusCode = statusLine.getStatusCode(); switch (statusCode){ case 302: Header[] locationHeaders = httpResponse.getHeaders(LOCATION_HEADER); if (locationHeaders.length == 1) { String url = httpResponse.getHeaders(LOCATION_HEADER)[0].getValue(); Log.d(TAG, "publish: "+url); return url; } checkStatusCodes(httpResponse, "publish"); break; case 403: throw new WebdavSharingForbiddenException("Folder "+path+" can't be shared"); default: checkStatusCodes(httpResponse, "publish"); } } return null; // not happen } public void unpublish(String path) throws IOException, WebdavException { HttpPost post = new HttpPost(getUrl()+encodeURL(path)+"?unpublish"); logMethod(post, "(unpublish)"); creds.addAuthHeader(post); HttpResponse httpResponse = executeRequest(post); consumeContent(httpResponse); StatusLine statusLine = httpResponse.getStatusLine(); if (statusLine != null && statusLine.getStatusCode() == 200) { return; } checkStatusCodes(httpResponse, "unpublish"); } public static class PropFind extends HttpPost { public PropFind() { } public PropFind(String url) { super(url); } @Override public String getMethod() { return "PROPFIND"; } } private static class HttpMkcol extends HttpPut { public HttpMkcol(String url) { super(url); } @Override public String getMethod() { return "MKCOL"; } } private static class Move extends HttpPut { public Move(String url) { super(url); } @Override public String getMethod() { return "MOVE"; } } }