1818package org .openqa .selenium .grid .node .local ;
1919
2020import static com .google .common .collect .ImmutableSet .toImmutableSet ;
21+ import static java .nio .file .Files .readAttributes ;
22+ import static org .openqa .selenium .HasDownloads .DownloadedFile ;
2123import static org .openqa .selenium .concurrent .ExecutorServices .shutdownGracefully ;
2224import static org .openqa .selenium .grid .data .Availability .DOWN ;
2325import static org .openqa .selenium .grid .data .Availability .DRAINING ;
3739import com .github .benmanes .caffeine .cache .Ticker ;
3840import com .google .common .annotations .VisibleForTesting ;
3941import com .google .common .collect .ImmutableList ;
40- import com .google .common .collect .ImmutableMap ;
4142import java .io .Closeable ;
4243import java .io .File ;
4344import java .io .IOException ;
4445import java .io .Serializable ;
4546import java .io .UncheckedIOException ;
4647import java .net .URI ;
4748import java .net .URISyntaxException ;
49+ import java .nio .file .attribute .BasicFileAttributes ;
4850import java .time .Clock ;
4951import java .time .Duration ;
5052import java .time .Instant ;
@@ -580,8 +582,8 @@ private boolean managedDownloadsRequested(Capabilities capabilities) {
580582 private Capabilities setDownloadsDirectory (TemporaryFilesystem downloadsTfs , Capabilities caps ) {
581583 File tempDir = downloadsTfs .createTempDir ("download" , "" );
582584 if (Browser .CHROME .is (caps ) || Browser .EDGE .is (caps )) {
583- ImmutableMap <String , Serializable > map =
584- ImmutableMap .of (
585+ Map <String , Serializable > map =
586+ Map .of (
585587 "download.prompt_for_download" ,
586588 false ,
587589 "download.default_directory" ,
@@ -592,8 +594,8 @@ private Capabilities setDownloadsDirectory(TemporaryFilesystem downloadsTfs, Cap
592594 return appendPrefs (caps , optionsKey , map );
593595 }
594596 if (Browser .FIREFOX .is (caps )) {
595- ImmutableMap <String , Serializable > map =
596- ImmutableMap .of (
597+ Map <String , Serializable > map =
598+ Map .of (
597599 "browser.download.folderList" , 2 , "browser.download.dir" , tempDir .getAbsolutePath ());
598600 return appendPrefs (caps , "moz:firefoxOptions" , map );
599601 }
@@ -738,25 +740,50 @@ public HttpResponse downloadFile(HttpRequest req, SessionId id) {
738740 }
739741 File downloadsDirectory =
740742 Optional .ofNullable (tempFS .getBaseDir ().listFiles ()).orElse (new File [] {})[0 ];
741- if (req .getMethod ().equals (HttpMethod .GET )) {
742- // User wants to list files that can be downloaded
743- List <String > collected =
744- Arrays .stream (Optional .ofNullable (downloadsDirectory .listFiles ()).orElse (new File [] {}))
745- .map (File ::getName )
746- .collect (Collectors .toList ());
747- ImmutableMap <String , Object > data = ImmutableMap .of ("names" , collected );
748- ImmutableMap <String , Map <String , Object >> result = ImmutableMap .of ("value" , data );
749- return new HttpResponse ().setContent (asJson (result ));
750- }
751- if (req .getMethod ().equals (HttpMethod .DELETE )) {
752- File [] files = Optional .ofNullable (downloadsDirectory .listFiles ()).orElse (new File [] {});
753- for (File file : files ) {
754- FileHandler .delete (file );
743+
744+ try {
745+ if (req .getMethod ().equals (HttpMethod .GET )) {
746+ return listDownloadedFiles (downloadsDirectory );
755747 }
756- Map <String , Object > toReturn = new HashMap <>();
757- toReturn .put ("value" , null );
758- return new HttpResponse ().setContent (asJson (toReturn ));
748+ if (req .getMethod ().equals (HttpMethod .DELETE )) {
749+ return deleteDownloadedFile (downloadsDirectory );
750+ }
751+ return getDownloadedFile (req , downloadsDirectory );
752+ } catch (IOException e ) {
753+ throw new UncheckedIOException (e );
759754 }
755+ }
756+
757+ /** User wants to list files that can be downloaded */
758+ private HttpResponse listDownloadedFiles (File downloadsDirectory ) {
759+ File [] files = Optional .ofNullable (downloadsDirectory .listFiles ()).orElse (new File [] {});
760+ List <String > fileNames = Arrays .stream (files ).map (File ::getName ).collect (Collectors .toList ());
761+ List <DownloadedFile > fileInfos =
762+ Arrays .stream (files ).map (this ::getFileInfo ).collect (Collectors .toList ());
763+
764+ Map <String , Object > data =
765+ Map .of (
766+ "names" , fileNames ,
767+ "files" , fileInfos );
768+ Map <String , Map <String , Object >> result = Map .of ("value" , data );
769+ return new HttpResponse ().setContent (asJson (result ));
770+ }
771+
772+ private DownloadedFile getFileInfo (File file ) {
773+ try {
774+ BasicFileAttributes attributes = readAttributes (file .toPath (), BasicFileAttributes .class );
775+ return new DownloadedFile (
776+ file .getName (),
777+ attributes .creationTime ().toMillis (),
778+ attributes .lastModifiedTime ().toMillis (),
779+ attributes .size ());
780+ } catch (IOException e ) {
781+ throw new UncheckedIOException ("Failed to get file attributes: " + file .getAbsolutePath (), e );
782+ }
783+ }
784+
785+ private HttpResponse getDownloadedFile (HttpRequest req , File downloadsDirectory )
786+ throws IOException {
760787 String raw = string (req );
761788 if (raw .isEmpty ()) {
762789 throw new WebDriverException (
@@ -771,30 +798,37 @@ public HttpResponse downloadFile(HttpRequest req, SessionId id) {
771798 new WebDriverException (
772799 "Please specify file to download in payload as {\" name\" :"
773800 + " \" fileToDownload\" }" ));
774- try {
775- File [] allFiles =
776- Optional .ofNullable (downloadsDirectory .listFiles ((dir , name ) -> name .equals (filename )))
777- .orElse (new File [] {});
778- if (allFiles .length == 0 ) {
779- throw new WebDriverException (
780- String .format (
781- "Cannot find file [%s] in directory %s." ,
782- filename , downloadsDirectory .getAbsolutePath ()));
783- }
784- if (allFiles .length != 1 ) {
785- throw new WebDriverException (
786- String .format ("Expected there to be only 1 file. There were: %s." , allFiles .length ));
787- }
788- String content = Zip .zip (allFiles [0 ]);
789- ImmutableMap <String , Object > data =
790- ImmutableMap .of (
791- "filename" , filename ,
792- "contents" , content );
793- ImmutableMap <String , Map <String , Object >> result = ImmutableMap .of ("value" , data );
794- return new HttpResponse ().setContent (asJson (result ));
795- } catch (IOException e ) {
796- throw new UncheckedIOException (e );
801+ File [] allFiles =
802+ Optional .ofNullable (downloadsDirectory .listFiles ((dir , name ) -> name .equals (filename )))
803+ .orElse (new File [] {});
804+ if (allFiles .length == 0 ) {
805+ throw new WebDriverException (
806+ String .format (
807+ "Cannot find file [%s] in directory %s." ,
808+ filename , downloadsDirectory .getAbsolutePath ()));
809+ }
810+ if (allFiles .length != 1 ) {
811+ throw new WebDriverException (
812+ String .format ("Expected there to be only 1 file. There were: %s." , allFiles .length ));
813+ }
814+ String content = Zip .zip (allFiles [0 ]);
815+ Map <String , Object > data =
816+ Map .of (
817+ "filename" , filename ,
818+ "file" , getFileInfo (allFiles [0 ]),
819+ "contents" , content );
820+ Map <String , Map <String , Object >> result = Map .of ("value" , data );
821+ return new HttpResponse ().setContent (asJson (result ));
822+ }
823+
824+ private HttpResponse deleteDownloadedFile (File downloadsDirectory ) {
825+ File [] files = Optional .ofNullable (downloadsDirectory .listFiles ()).orElse (new File [] {});
826+ for (File file : files ) {
827+ FileHandler .delete (file );
797828 }
829+ Map <String , Object > toReturn = new HashMap <>();
830+ toReturn .put ("value" , null );
831+ return new HttpResponse ().setContent (asJson (toReturn ));
798832 }
799833
800834 @ Override
@@ -829,7 +863,7 @@ public HttpResponse uploadFile(HttpRequest req, SessionId id) {
829863 String .format ("Expected there to be only 1 file. There were: %s" , allFiles .length ));
830864 }
831865
832- ImmutableMap <String , Object > result = ImmutableMap .of ("value" , allFiles [0 ].getAbsolutePath ());
866+ Map <String , Object > result = Map .of ("value" , allFiles [0 ].getAbsolutePath ());
833867
834868 return new HttpResponse ().setContent (asJson (result ));
835869 }
@@ -1063,13 +1097,17 @@ private boolean decrementSessionCount() {
10631097 }
10641098
10651099 private Map <String , Object > toJson () {
1066- return ImmutableMap .of (
1067- "id" , getId (),
1068- "uri" , externalUri ,
1069- "maxSessions" , maxSessionCount ,
1070- "draining" , isDraining (),
1100+ return Map .of (
1101+ "id" ,
1102+ getId (),
1103+ "uri" ,
1104+ externalUri ,
1105+ "maxSessions" ,
1106+ maxSessionCount ,
1107+ "draining" ,
1108+ isDraining (),
10711109 "capabilities" ,
1072- factories .stream ().map (SessionSlot ::getStereotype ).collect (Collectors .toSet ()));
1110+ factories .stream ().map (SessionSlot ::getStereotype ).collect (Collectors .toSet ()));
10731111 }
10741112
10751113 public static class Builder {
0 commit comments