FileDownloadUtils { public static String findFilename(FileDownloadConnection connection, String url) throws FileDownloadSecurityException { String filename = FileDownloadUtils.parseContentDisposition(connection. getResponseHeaderField("Content-Disposition")); if (TextUtils.isEmpty(filename)) { filename = findFileNameFromUrl(url); } if (TextUtils.isEmpty(filename)) { filename = FileDownloadUtils.generateFileName(url); } else if (filename.contains("../")) { throw new FileDownloadSecurityException(FileDownloadUtils.formatString( "The filename [%s] from the response is not allowable, because it contains " + "'../', which can raise the directory traversal vulnerability", filename)); } return filename; }  static void setMinProgressStep(int minProgressStep); static void setMinProgressTime(long minProgressTime); static int getMinProgressStep(); static long getMinProgressTime(); @SuppressWarnings({"SameReturnValue", "UnusedParameters"}) static boolean isFilenameValid(String filename); static String getDefaultSaveRootPath(); static String getDefaultSaveFilePath(final String url); static String generateFileName(final String url); static String generateFilePath(String directory, String filename); static void setDefaultSaveRootPath(final String path); static String getTempPath(final String targetPath); static int generateId(final String url, final String path); static int generateId(final String url, final String path,
                                 final boolean pathAsDirectory); static String md5(String string); static String getStack(); static String getStack(final boolean printLine); static String getStack(final StackTraceElement[] stackTrace, final boolean printLine); static boolean isDownloaderProcess(final Context context); static String[] convertHeaderString(final String nameAndValuesString); static long getFreeSpaceBytes(final String path); static String formatString(final String msg, Object... args); @SuppressWarnings("ResultOfMethodCallIgnored") static void markConverted(final Context context); static boolean isFilenameConverted(final Context context); static File getConvertedMarkedFile(final Context context); static long parseContentRangeFoInstanceLength(String contentRange); static String parseContentDisposition(String contentDisposition); static String getTargetFilePath(String path, boolean pathAsDirectory, String filename); static String getParent(final String path); static String getThreadPoolName(String name); static boolean isNetworkNotOnWifiType(); static boolean checkPermission(String permission); static long convertContentLengthString(String s); static String findEtag(final int id, FileDownloadConnection connection); static boolean isAcceptRange(int responseCode, FileDownloadConnection connection); static long findInstanceLengthForTrial(FileDownloadConnection connection); static long findInstanceLengthFromContentRange(FileDownloadConnection connection); static long findContentLength(final int id, FileDownloadConnection connection); static long findContentLengthFromContentRange(FileDownloadConnection connection); static long parseContentLengthFromContentRange(String contentRange); static String findFilename(FileDownloadConnection connection, String url); static FileDownloadOutputStream createOutputStream(final String path); static boolean isBreakpointAvailable(final int id, final FileDownloadModel model); static boolean isBreakpointAvailable(final int id, final FileDownloadModel model,
                                                final Boolean outputStreamSupportSeek); static boolean isBreakpointAvailable(final int id, final FileDownloadModel model,
                                                final String path,
                                                final Boolean outputStreamSupportSeek); static void deleteTaskFiles(String targetFilepath, String tempFilePath); static void deleteTempFile(String tempFilePath); static void deleteTargetFile(String targetFilePath); static boolean isNeedSync(long bytesDelta, long timestampDelta); static String defaultUserAgent(); static boolean needMakeServiceForeground(Context context);  }
@Test public void findFilename_securityIssue() throws FileDownloadSecurityException { final FileDownloadConnection connection = mock(FileDownloadConnection.class); when(connection.getResponseHeaderField("Content-Disposition")) .thenReturn("attachment; filename=\"../abc\""); thrown.expect(FileDownloadSecurityException.class); FileDownloadUtils.findFilename(connection, "url"); thrown.expect(FileDownloadSecurityException.class); when(connection.getResponseHeaderField("Content-Disposition")) .thenReturn("attachment; filename=\"a/b/../abc\""); FileDownloadUtils.findFilename(connection, "url"); when(connection.getResponseHeaderField("Content-Disposition")) .thenReturn("attachment; filename=\"/abc/adb\""); assertThat(FileDownloadUtils.findFilename(connection, "url")).isEqualTo("/abc/adb"); }