|
54 | 54 | import io.vertx.core.buffer.Buffer; |
55 | 55 | import io.vertx.core.eventbus.Message; |
56 | 56 | import io.vertx.core.eventbus.ReplyException; |
| 57 | +import io.vertx.core.http.HttpMethod; |
57 | 58 | import io.vertx.core.http.HttpServer; |
58 | 59 | import io.vertx.core.http.HttpServerOptions; |
59 | 60 | import io.vertx.core.http.HttpServerRequest; |
@@ -362,7 +363,7 @@ public void deploy(JsonObject config, Promise<Void> prom) { |
362 | 363 | .handler(this::downloadFileAnnotation); |
363 | 364 | router.head( |
364 | 365 | "/webclient/annotation/:annotationId*") |
365 | | - .handler(this::fileAnnotationMetadata); |
| 366 | + .handler(this::downloadFileAnnotation); |
366 | 367 |
|
367 | 368 | // ImageData request handlers |
368 | 369 | router.get("/webgateway/imgData/:imageId/:keys*").handler(this::getImageData); |
@@ -961,76 +962,6 @@ private void getThumbnails(RoutingContext event) { |
961 | 962 | * @param event Current routing context |
962 | 963 | */ |
963 | 964 | private void downloadFileAnnotation(RoutingContext event) { |
964 | | - HttpServerRequest request = event.request(); |
965 | | - HttpServerResponse response = event.response(); |
966 | | - final AnnotationCtx annotationCtx; |
967 | | - try { |
968 | | - annotationCtx = new AnnotationCtx(request.params(), |
969 | | - event.get("omero.session_key")); |
970 | | - } catch (IllegalArgumentException e) { |
971 | | - if (!response.closed()) { |
972 | | - response.setStatusCode(400).end(e.getMessage()); |
973 | | - } |
974 | | - return; |
975 | | - } |
976 | | - annotationCtx.injectCurrentTraceContext(); |
977 | | - vertx.eventBus().<JsonObject>request( |
978 | | - ImageRegionVerticle.GET_FILE_ANNOTATION_METADATA_EVENT, |
979 | | - Json.encode(annotationCtx), new Handler<AsyncResult<Message<JsonObject>>>() { |
980 | | - @Override |
981 | | - public void handle(AsyncResult<Message<JsonObject>> result) { |
982 | | - if (result.failed()) { |
983 | | - log.error(result.cause().getMessage()); |
984 | | - response.setStatusCode(404); |
985 | | - response.end("Could not get annotation " |
986 | | - + request.getParam("annotationId")); |
987 | | - return; |
988 | | - } |
989 | | - JsonObject fileInfo = result.result().body(); |
990 | | - String fileName = fileInfo.getString("originalFileName"); |
991 | | - String filePath = fileInfo.getString("originalFilePath"); |
992 | | - //If the path is a directory, send error response |
993 | | - File file = new File(filePath); |
994 | | - if (!file.exists()) { |
995 | | - response.setStatusCode(404); |
996 | | - response.end("File for given Annotation does not exist"); |
997 | | - return; |
998 | | - } |
999 | | - if (file.isDirectory()) { |
1000 | | - response.setStatusCode(501); |
1001 | | - response.end("File Annotation of Unsupported File Type"); |
1002 | | - return; |
1003 | | - } |
1004 | | - else { |
1005 | | - response.headers().set("Content-Type", "application/octet-stream"); |
1006 | | - response.headers().set("Content-Disposition", |
1007 | | - "attachment; filename=\"" + fileName + "\""); |
1008 | | - if (request.headers().contains("Range")) { |
1009 | | - String range = request.getHeader("Range"); |
1010 | | - if (range.matches("^bytes=\\d+-\\d+$")) { |
1011 | | - String[] startEndStr = |
1012 | | - range.substring("bytes=".length()).split("-"); |
1013 | | - response.sendFile(filePath, Long.valueOf(startEndStr[0]), |
1014 | | - Long.valueOf(startEndStr[1])); |
1015 | | - } else { |
1016 | | - response.setStatusCode(400); |
1017 | | - response.end("Malformed Range header - " |
1018 | | - + "must be of the form \"bytes=x-y\""); |
1019 | | - } |
1020 | | - } else { |
1021 | | - response.sendFile(filePath); |
1022 | | - } |
1023 | | - } |
1024 | | - } |
1025 | | - }); |
1026 | | - } |
1027 | | - |
1028 | | - /** |
1029 | | - * Downloads the {@link OriginalFile} associated with the given |
1030 | | - * {@link FileAnnotation} |
1031 | | - * @param event Current routing context |
1032 | | - */ |
1033 | | - private void fileAnnotationMetadata(RoutingContext event) { |
1034 | 965 | HttpServerRequest request = event.request(); |
1035 | 966 | HttpServerResponse response = event.response(); |
1036 | 967 | final AnnotationCtx annotationCtx; |
@@ -1081,31 +1012,61 @@ public void handle(AsyncResult<Message<JsonObject>> result) { |
1081 | 1012 | fileName)); |
1082 | 1013 | } |
1083 | 1014 | response.headers().set("Content-Type", contentType); |
1084 | | - response.headers().set("Content-Length", Long.toString(file.length())); |
| 1015 | + |
1085 | 1016 | response.headers().set("Accept-Ranges", "bytes"); |
1086 | 1017 | ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant( |
1087 | 1018 | Instant.ofEpochMilli(file.lastModified()), |
1088 | 1019 | ZoneId.of("UTC")); |
1089 | 1020 | DateTimeFormatter formatter = |
1090 | 1021 | DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); |
1091 | 1022 | response.headers().set("Last-Modified", zonedDateTime.format(formatter)); |
| 1023 | + response.headers().set("Content-Disposition", |
| 1024 | + "attachment; filename=\"" + fileName + "\""); |
| 1025 | + |
| 1026 | + if (request.method() == HttpMethod.HEAD) { |
| 1027 | + response.headers().set("Content-Length", Long.toString(file.length())); |
| 1028 | + response.end(); |
| 1029 | + return; |
| 1030 | + } |
1092 | 1031 | if (request.headers().contains("Range")) { |
1093 | 1032 | String range = request.getHeader("Range"); |
| 1033 | + long start; |
| 1034 | + long end; |
1094 | 1035 | if (range.matches("^bytes=\\d+-\\d+$")) { |
1095 | | - String[] startEndStr = |
| 1036 | + String[] startEndStr = |
| 1037 | + range.substring("bytes=".length()).split("-"); |
| 1038 | + start = Long.valueOf(startEndStr[0]); |
| 1039 | + end = Long.valueOf(startEndStr[1]); |
| 1040 | + end = Math.min(end, file.length()); |
| 1041 | + } |
| 1042 | + else if (range.matches("^bytes=\\d+-$")) { |
| 1043 | + String[] startEndStr = |
1096 | 1044 | range.substring("bytes=".length()).split("-"); |
1097 | | - response.sendFile(filePath, Long.valueOf(startEndStr[0]), |
1098 | | - Long.valueOf(startEndStr[1])); |
| 1045 | + start = Long.valueOf(startEndStr[0]); |
| 1046 | + end = file.length() - 1; |
1099 | 1047 | } else { |
1100 | 1048 | response.setStatusCode(400); |
1101 | 1049 | response.end("Malformed Range header - " |
1102 | | - + "must be of the form \"bytes=x-y\""); |
| 1050 | + + "must be of the form \"bytes=x-y\" or \"bytes=x-\""); |
| 1051 | + return; |
1103 | 1052 | } |
| 1053 | + if (start >= file.length()) { |
| 1054 | + response.setStatusCode(416); |
| 1055 | + response.end("Invalid range"); |
| 1056 | + return; |
| 1057 | + } |
| 1058 | + response.setStatusCode(206); |
| 1059 | + log.info("Setting content-range"); |
| 1060 | + response.headers().set("Content-Range", |
| 1061 | + String.format("%d-%d/%d", start, end, |
| 1062 | + file.length())); |
| 1063 | + log.info("Sending file..."); |
| 1064 | + response.sendFile(filePath, start, end - start + 1); |
1104 | 1065 | } else { |
1105 | 1066 | response.sendFile(filePath); |
1106 | 1067 | } |
1107 | 1068 | } |
1108 | | - } |
1109 | | - }); |
| 1069 | + } |
| 1070 | + }); |
1110 | 1071 | } |
1111 | 1072 | } |
0 commit comments