Loading app/build.gradle +3 −0 Original line number Diff line number Diff line Loading @@ -105,4 +105,7 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.3.1' implementation 'androidx.annotation:annotation:1.3.0' api 'org.apache.jackrabbit:jackrabbit-webdav:2.12.6+' } app/src/main/java/foundation/e/drive/operations/ListFileRemoteOperation.java +2 −1 Original line number Diff line number Diff line Loading @@ -14,7 +14,7 @@ import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.resources.files.model.RemoteFile; import com.owncloud.android.lib.resources.files.LightReadFolderRemoteOperation; //import com.owncloud.android.lib.resources.files.LightReadFolderRemoteOperation; import java.io.File; import java.util.ArrayList; import java.util.List; Loading @@ -22,6 +22,7 @@ import java.util.ListIterator; import foundation.e.drive.database.DbHelper; import foundation.e.drive.models.SyncedFolder; import foundation.e.drive.utils.CommonUtils; import foundation.e.drive.utils.ncLib.LightReadFolderRemoteOperation; import static org.apache.jackrabbit.webdav.DavConstants.DEPTH_1; Loading app/src/main/java/foundation/e/drive/utils/ncLib/LightReadFolderRemoteOperation.java 0 → 100644 +155 −0 Original line number Diff line number Diff line package foundation.e.drive.utils.ncLib; import com.owncloud.android.lib.common.OwnCloudClient; //import com.owncloud.android.lib.common.method.GzipedPropfind; import com.owncloud.android.lib.common.network.WebdavEntry; import com.owncloud.android.lib.common.network.WebdavUtils; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.lib.resources.files.model.RemoteFile; import org.apache.commons.httpclient.HttpStatus; import org.apache.jackrabbit.webdav.DavConstants; import org.apache.jackrabbit.webdav.MultiStatus; import org.apache.jackrabbit.webdav.client.methods.PropFindMethod; import java.util.ArrayList; import foundation.e.drive.utils.ncLib.common.method.GzipedPropfind; public class LightReadFolderRemoteOperation extends RemoteOperation { private static final String TAG = LightReadFolderRemoteOperation.class.getSimpleName(); private String mRemotePath; private ArrayList<Object> mFolderAndFiles; private int depth; private boolean allowGzip; /** * Constructor * @param remotePath remothe path of folder * @param depth depth to reach. Value should be in DavConstants (DEPTH_0, DEPTH_1 or DEPTH_INFINITY). DEPTH_0 by default */ public LightReadFolderRemoteOperation(String remotePath, int depth, boolean allowGzip){ mRemotePath = remotePath; if(depth == DavConstants.DEPTH_0 || depth == DavConstants.DEPTH_1 || depth == DavConstants.DEPTH_INFINITY) { this.depth = depth; }else{ this.depth = DavConstants.DEPTH_0; } this.allowGzip = allowGzip; } /** * Performs the read operation. * * @param client Client object to communicate with the remote ownCloud server. */ @Override protected RemoteOperationResult run(OwnCloudClient client) { RemoteOperationResult result = null; PropFindMethod propfind = null; String userAgent =""; try { // remote request if(allowGzip){ propfind = new GzipedPropfind(client.getWebdavUri() + WebdavUtils.encodePath(mRemotePath), WebdavUtils.getMinimumPropSet(), // PropFind Properties this.depth); propfind.setRequestHeader("Accept-Encoding", "gzip"); userAgent = "gzipUserAgent"; }else{ propfind = new PropFindMethod(client.getWebdavUri() + WebdavUtils.encodePath(mRemotePath), WebdavUtils.getAllPropSet(), // PropFind Properties this.depth); } int status = client.executeMethod(propfind, userAgent); // check and process response boolean isSuccess = (status == HttpStatus.SC_MULTI_STATUS || status == HttpStatus.SC_OK); if (isSuccess) { // get data from remote folder MultiStatus dataInServer = propfind.getResponseBodyAsMultiStatus(); readData(dataInServer, client); // Result of the operation result = new RemoteOperationResult(true, propfind); // Add data to the result if (result.isSuccess()) { result.setData(mFolderAndFiles); } } else { // synchronization failed client.exhaustResponse( ( (GzipedPropfind) propfind).getDecompressedResponseBodyasStream() ); result = new RemoteOperationResult(false, propfind); } } catch (Exception e) { result = new RemoteOperationResult(e); } finally { if (propfind != null) propfind.releaseConnection(); // let the connection available for other methods if (result == null) { result = new RemoteOperationResult(new Exception("unknown error")); Log_OC.e(TAG, "Synchronized " + mRemotePath + ": failed"); } } return result; } public boolean isMultiStatus(int status) { return (status == HttpStatus.SC_MULTI_STATUS); } /** * Read the data retrieved from the server about the contents of the target folder * * @param remoteData Full response got from the server with the data of the target * folder and its direct children. * @param client Client instance to the remote server where the data were * retrieved. * @return */ private void readData(MultiStatus remoteData, OwnCloudClient client) { mFolderAndFiles = new ArrayList<>(); // parse data from remote folder WebdavEntry we = new WebdavEntry(remoteData.getResponses()[0], client.getWebdavUri().getPath()); mFolderAndFiles.add(fillOCFile(we)); // loop to update every child RemoteFile remoteFile; for (int i =0 ; ++i < remoteData.getResponses().length;) { /// new OCFile instance with the data from the server we = new WebdavEntry(remoteData.getResponses()[i], client.getWebdavUri().getPath()); remoteFile = fillOCFile(we); mFolderAndFiles.add(remoteFile); } } /** * Creates and populates a new {@link RemoteFile} object with the data read from the server. * * @param we WebDAV entry read from the server for a WebDAV resource (remote file or folder). * @return New OCFile instance representing the remote resource described by we. */ private RemoteFile fillOCFile(WebdavEntry we) { RemoteFile file = new RemoteFile(we.decodedPath()); file.setLength(we.contentLength()); file.setMimeType(we.contentType()); file.setModifiedTimestamp(we.modifiedTimestamp()); file.setEtag(we.etag()); file.setPermissions(we.permissions()); file.setRemoteId(we.remoteId()); file.setSize(we.size()); return file; } } app/src/main/java/foundation/e/drive/utils/ncLib/common/method/GzipedPropfind.java 0 → 100644 +113 −0 Original line number Diff line number Diff line package foundation.e.drive.utils.ncLib.common.method; import org.apache.commons.httpclient.Header; import org.apache.jackrabbit.webdav.client.methods.PropFindMethod; import org.apache.jackrabbit.webdav.property.DavPropertyNameSet; import org.apache.jackrabbit.webdav.xml.DomUtil; import org.w3c.dom.Document; import org.xml.sax.SAXException; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.zip.GZIPInputStream; import javax.xml.parsers.ParserConfigurationException; public class GzipedPropfind extends PropFindMethod { public GzipedPropfind(String uri) throws IOException { super(uri); } public boolean isResponseGzipped(){ Header contentEncodingHeader= getResponseHeader("Content-Encoding"); if(contentEncodingHeader != null && contentEncodingHeader.getValue().contains("gzip") ) { return true; } return false; } public InputStream getDecompressedResponseBodyasStream() throws IOException{ if(!isResponseGzipped() ) return super.getResponseBodyAsStream(); //@TOdo: look for potential optimisation like pipe gzipInputStream directly in InputStream in StringBuilder s = new StringBuilder(); String line; try{ GZIPInputStream gzipis = new GZIPInputStream(getResponseBodyAsStream()); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(gzipis)); while ((line = bufferedReader.readLine()) != null) { s.append(line); } bufferedReader.close(); return new ByteArrayInputStream(s.toString().getBytes()); }catch(IOException e){ throw e; } } /* * Uncompress the gzipSteam before to parse it with SAX * In the case of no "Content-Encoding:gzip" headers is found, the * */ @Override public Document getResponseBodyAsDocument() throws IOException { if(!isResponseGzipped() ) return super.getResponseBodyAsDocument(); //@TOdo: look for potential optimisation like pipe gzipInputStream directly in InputStream in StringBuilder s = new StringBuilder(); String line; try{ GZIPInputStream gzipis = new GZIPInputStream(getResponseBodyAsStream()); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(gzipis)); while ((line = bufferedReader.readLine()) != null) { s.append(line); } bufferedReader.close(); }catch(IOException e){ throw e; } InputStream in = new ByteArrayInputStream(s.toString().getBytes()); if (in != null) { // read response and try to build a xml document try { return DomUtil.parseDocument(in); } catch (ParserConfigurationException e) { IOException exception = new IOException("XML parser configuration error"); exception.initCause(e); throw exception; } catch (SAXException e) { IOException exception = new IOException("XML parsing error"); exception.initCause(e); throw exception; } finally { in.close(); } } // no body or no parseable. return null; } public GzipedPropfind(String uri, DavPropertyNameSet propNameSet, int depth) throws IOException { super(uri, propNameSet, depth); } public GzipedPropfind(String uri, int propfindType, int depth) throws IOException { super(uri, propfindType, depth); } public GzipedPropfind(String uri, int propfindType, DavPropertyNameSet propNameSet, int depth) throws IOException { super(uri, propfindType, propNameSet, depth); } } Loading
app/build.gradle +3 −0 Original line number Diff line number Diff line Loading @@ -105,4 +105,7 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.3.1' implementation 'androidx.annotation:annotation:1.3.0' api 'org.apache.jackrabbit:jackrabbit-webdav:2.12.6+' }
app/src/main/java/foundation/e/drive/operations/ListFileRemoteOperation.java +2 −1 Original line number Diff line number Diff line Loading @@ -14,7 +14,7 @@ import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.resources.files.model.RemoteFile; import com.owncloud.android.lib.resources.files.LightReadFolderRemoteOperation; //import com.owncloud.android.lib.resources.files.LightReadFolderRemoteOperation; import java.io.File; import java.util.ArrayList; import java.util.List; Loading @@ -22,6 +22,7 @@ import java.util.ListIterator; import foundation.e.drive.database.DbHelper; import foundation.e.drive.models.SyncedFolder; import foundation.e.drive.utils.CommonUtils; import foundation.e.drive.utils.ncLib.LightReadFolderRemoteOperation; import static org.apache.jackrabbit.webdav.DavConstants.DEPTH_1; Loading
app/src/main/java/foundation/e/drive/utils/ncLib/LightReadFolderRemoteOperation.java 0 → 100644 +155 −0 Original line number Diff line number Diff line package foundation.e.drive.utils.ncLib; import com.owncloud.android.lib.common.OwnCloudClient; //import com.owncloud.android.lib.common.method.GzipedPropfind; import com.owncloud.android.lib.common.network.WebdavEntry; import com.owncloud.android.lib.common.network.WebdavUtils; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.lib.resources.files.model.RemoteFile; import org.apache.commons.httpclient.HttpStatus; import org.apache.jackrabbit.webdav.DavConstants; import org.apache.jackrabbit.webdav.MultiStatus; import org.apache.jackrabbit.webdav.client.methods.PropFindMethod; import java.util.ArrayList; import foundation.e.drive.utils.ncLib.common.method.GzipedPropfind; public class LightReadFolderRemoteOperation extends RemoteOperation { private static final String TAG = LightReadFolderRemoteOperation.class.getSimpleName(); private String mRemotePath; private ArrayList<Object> mFolderAndFiles; private int depth; private boolean allowGzip; /** * Constructor * @param remotePath remothe path of folder * @param depth depth to reach. Value should be in DavConstants (DEPTH_0, DEPTH_1 or DEPTH_INFINITY). DEPTH_0 by default */ public LightReadFolderRemoteOperation(String remotePath, int depth, boolean allowGzip){ mRemotePath = remotePath; if(depth == DavConstants.DEPTH_0 || depth == DavConstants.DEPTH_1 || depth == DavConstants.DEPTH_INFINITY) { this.depth = depth; }else{ this.depth = DavConstants.DEPTH_0; } this.allowGzip = allowGzip; } /** * Performs the read operation. * * @param client Client object to communicate with the remote ownCloud server. */ @Override protected RemoteOperationResult run(OwnCloudClient client) { RemoteOperationResult result = null; PropFindMethod propfind = null; String userAgent =""; try { // remote request if(allowGzip){ propfind = new GzipedPropfind(client.getWebdavUri() + WebdavUtils.encodePath(mRemotePath), WebdavUtils.getMinimumPropSet(), // PropFind Properties this.depth); propfind.setRequestHeader("Accept-Encoding", "gzip"); userAgent = "gzipUserAgent"; }else{ propfind = new PropFindMethod(client.getWebdavUri() + WebdavUtils.encodePath(mRemotePath), WebdavUtils.getAllPropSet(), // PropFind Properties this.depth); } int status = client.executeMethod(propfind, userAgent); // check and process response boolean isSuccess = (status == HttpStatus.SC_MULTI_STATUS || status == HttpStatus.SC_OK); if (isSuccess) { // get data from remote folder MultiStatus dataInServer = propfind.getResponseBodyAsMultiStatus(); readData(dataInServer, client); // Result of the operation result = new RemoteOperationResult(true, propfind); // Add data to the result if (result.isSuccess()) { result.setData(mFolderAndFiles); } } else { // synchronization failed client.exhaustResponse( ( (GzipedPropfind) propfind).getDecompressedResponseBodyasStream() ); result = new RemoteOperationResult(false, propfind); } } catch (Exception e) { result = new RemoteOperationResult(e); } finally { if (propfind != null) propfind.releaseConnection(); // let the connection available for other methods if (result == null) { result = new RemoteOperationResult(new Exception("unknown error")); Log_OC.e(TAG, "Synchronized " + mRemotePath + ": failed"); } } return result; } public boolean isMultiStatus(int status) { return (status == HttpStatus.SC_MULTI_STATUS); } /** * Read the data retrieved from the server about the contents of the target folder * * @param remoteData Full response got from the server with the data of the target * folder and its direct children. * @param client Client instance to the remote server where the data were * retrieved. * @return */ private void readData(MultiStatus remoteData, OwnCloudClient client) { mFolderAndFiles = new ArrayList<>(); // parse data from remote folder WebdavEntry we = new WebdavEntry(remoteData.getResponses()[0], client.getWebdavUri().getPath()); mFolderAndFiles.add(fillOCFile(we)); // loop to update every child RemoteFile remoteFile; for (int i =0 ; ++i < remoteData.getResponses().length;) { /// new OCFile instance with the data from the server we = new WebdavEntry(remoteData.getResponses()[i], client.getWebdavUri().getPath()); remoteFile = fillOCFile(we); mFolderAndFiles.add(remoteFile); } } /** * Creates and populates a new {@link RemoteFile} object with the data read from the server. * * @param we WebDAV entry read from the server for a WebDAV resource (remote file or folder). * @return New OCFile instance representing the remote resource described by we. */ private RemoteFile fillOCFile(WebdavEntry we) { RemoteFile file = new RemoteFile(we.decodedPath()); file.setLength(we.contentLength()); file.setMimeType(we.contentType()); file.setModifiedTimestamp(we.modifiedTimestamp()); file.setEtag(we.etag()); file.setPermissions(we.permissions()); file.setRemoteId(we.remoteId()); file.setSize(we.size()); return file; } }
app/src/main/java/foundation/e/drive/utils/ncLib/common/method/GzipedPropfind.java 0 → 100644 +113 −0 Original line number Diff line number Diff line package foundation.e.drive.utils.ncLib.common.method; import org.apache.commons.httpclient.Header; import org.apache.jackrabbit.webdav.client.methods.PropFindMethod; import org.apache.jackrabbit.webdav.property.DavPropertyNameSet; import org.apache.jackrabbit.webdav.xml.DomUtil; import org.w3c.dom.Document; import org.xml.sax.SAXException; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.zip.GZIPInputStream; import javax.xml.parsers.ParserConfigurationException; public class GzipedPropfind extends PropFindMethod { public GzipedPropfind(String uri) throws IOException { super(uri); } public boolean isResponseGzipped(){ Header contentEncodingHeader= getResponseHeader("Content-Encoding"); if(contentEncodingHeader != null && contentEncodingHeader.getValue().contains("gzip") ) { return true; } return false; } public InputStream getDecompressedResponseBodyasStream() throws IOException{ if(!isResponseGzipped() ) return super.getResponseBodyAsStream(); //@TOdo: look for potential optimisation like pipe gzipInputStream directly in InputStream in StringBuilder s = new StringBuilder(); String line; try{ GZIPInputStream gzipis = new GZIPInputStream(getResponseBodyAsStream()); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(gzipis)); while ((line = bufferedReader.readLine()) != null) { s.append(line); } bufferedReader.close(); return new ByteArrayInputStream(s.toString().getBytes()); }catch(IOException e){ throw e; } } /* * Uncompress the gzipSteam before to parse it with SAX * In the case of no "Content-Encoding:gzip" headers is found, the * */ @Override public Document getResponseBodyAsDocument() throws IOException { if(!isResponseGzipped() ) return super.getResponseBodyAsDocument(); //@TOdo: look for potential optimisation like pipe gzipInputStream directly in InputStream in StringBuilder s = new StringBuilder(); String line; try{ GZIPInputStream gzipis = new GZIPInputStream(getResponseBodyAsStream()); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(gzipis)); while ((line = bufferedReader.readLine()) != null) { s.append(line); } bufferedReader.close(); }catch(IOException e){ throw e; } InputStream in = new ByteArrayInputStream(s.toString().getBytes()); if (in != null) { // read response and try to build a xml document try { return DomUtil.parseDocument(in); } catch (ParserConfigurationException e) { IOException exception = new IOException("XML parser configuration error"); exception.initCause(e); throw exception; } catch (SAXException e) { IOException exception = new IOException("XML parsing error"); exception.initCause(e); throw exception; } finally { in.close(); } } // no body or no parseable. return null; } public GzipedPropfind(String uri, DavPropertyNameSet propNameSet, int depth) throws IOException { super(uri, propNameSet, depth); } public GzipedPropfind(String uri, int propfindType, int depth) throws IOException { super(uri, propfindType, depth); } public GzipedPropfind(String uri, int propfindType, DavPropertyNameSet propNameSet, int depth) throws IOException { super(uri, propfindType, propNameSet, depth); } }