tomdesair / tus-java-server Goto Github PK
View Code? Open in Web Editor NEWLibrary to receive tus v1.0.0 file uploads in a Java server environment
License: MIT License
Library to receive tus v1.0.0 file uploads in a Java server environment
License: MIT License
i checked the source code, the uploadUriPattern in PostURIValidator doesn't consider context-path of spring
I need your tus server to be able to return a json structure in the response. For example, I can perform response.setStatus(422) but along with that code I would like to send it a custom message. It's possible??
As the title says, I've implemented the Java TUS Server sample, which upon uploading a file, returns a Location without the full-url, but just the endpoint, e.g. /api/uploads/random-file-upload-id
I just started looking into TUS, and not sure whether this is an issue on the server side or this flutter client but the client breaks with an exception saying that the Location arg. i.e. resource URL doesn't contain the hostname/base.
I've inspected the client, and fixed this with prepending the Location url with the server hostname, but as said, I'm not sure whether this is an issue on the server or client side impl.
Is there a way to set up the server to provide the full url for the resource?
My flutter dependencies:
http: ^0.12.2
tus_client: ^0.0.4
TUS Server dep:
<dependency>
<groupId>me.desair.tus</groupId>
<artifactId>tus-java-server</artifactId>
<version>1.0.0-2.0</version>
</dependency>
How I temporarily fixed this is with providing a custom e.g. X-Location header param with the full uploaded resource url (containing server hostname), whcih I then use on the client.
Excuse me, where can I see the Javadoc for this lib, which doesn't seem to be at https://tus.desair.me/.
I wonder how to use it
Is it possible to use this with dropwizard? Is there any documentation or example on how to use this with dropwizard?
TusFileUploadService.cleanup()
calls
DiskStorageService.cleanupExpiredUploads(...)
and
DiskLockingService.cleanupStaleLocks()
Those methods throw "directory does not exist" exception if not a single upload was processed, because private method
AbstractDiskBasedService.init()
was never called.
How to fix:
Call
AbstractDiskBasedService.init()
inside
DiskStorageService.cleanupExpiredUploads(...)
and
DiskLockingService.cleanupStaleLocks()
The latest released version of tus-java-server
contains org.apache.commons.io:commons-io:2.6
as a dependency, which is vulnerable to CVE-2021-29425. I noticed commons-io
was updated in #41, but this change was never released to Maven Central. Is it easy to get another release of tus-java-server
with the latest changes? Thanks!
Ability to handle a TUS apload regardless of what the base URI is. For instance /api/upload
causes this error but /upload
works fine.
UploadInfo is not captured from the request. Any attempts at using the TusFileUploadService to fetch (getUploadInfo) results in a null pointer exception.
Create a basic implementation using a base URI other than simple 'upload'.
For example (in Spring):
@RequestMapping(value = { "/api/upload", "/api/upload/**" }, method = { RequestMethod.POST,
RequestMethod.PATCH, RequestMethod.HEAD, RequestMethod.DELETE, RequestMethod.GET })
public void upload(HttpServletRequest servletRequest,
HttpServletResponse servletResponse) throws IOException {
this.tusFileUploadService.process(servletRequest, servletResponse);
String uploadURI = servletRequest.getRequestURI();
UploadInfo uploadInfo = null;
try {
uploadInfo = this.tusFileUploadService.getUploadInfo(uploadURI);
//this is null
}
catch (IOException | TusException e) {
Application.logger.error("get upload info", e);
}
}
I have a question, what purposes of file system locks in DiskStorageService and what kind of risks if I override DiskStorageService implementation and remove this locking logic?
If we protect only from external invention when reading/writing can I provide pull request that make this behavior optional?
Thank you.
hello, i am a student insterested in this project, could you give some steps to run this code correctly? mybe a main(), thank you very much.
we cannot use in spring boot 3.x without java17 support
(What faulty behaviour does the implementation have?)
(Ideally, you specify detailed steps using the curl command.)
To get the uploaded bytes using the tusFileUploadService.getUploadedBytes(String uploadUrl).
I am uploading using this code in my controller:
@RequestMapping(value = "/api/upload")
//access Cross
@CrossOrigin(origins = "*")
public class TusController {
@Autowired
private TusFileUploadService tusFileUploadService;
@Autowired
HelperService helperService;
@RequestMapping(value = {"", "/**"}, method = {RequestMethod.POST, RequestMethod.PATCH, RequestMethod.HEAD,
RequestMethod.DELETE, RequestMethod.OPTIONS, RequestMethod.GET})
public void processUpload(final HttpServletRequest servletRequest, final HttpServletResponse servletResponse) throws IOException, TusException, InterruptedException {
tusFileUploadService.process(servletRequest, servletResponse);
//access response header Location,Upload-Offset,Upload-length
servletResponse.addHeader("Access-Control-Expose-Headers","Location,Upload-Offset,Upload-Length");
}
@RequestMapping(method = RequestMethod.GET, value = "/getBytesTus")
public String getUploadedBytes() throws TusException, IOException {
System.out.println(tusFileUploadService.getUploadedBytes("/api/upload"));
return "done";
}
}
Here the upload url is "/api/upload" and when I try to get the uploaded bytes using the getUploadedBytes() api which uses the getUploadedBytes with the upload URI I get this error: Method threw 'me.desair.tus.server.exception.UploadNotFoundException' exception.
Hi, I have a spring boot server do I need to add some configuration to it in order for this to work?
I'm implementing this library to replace XHR Upload with the Uppy client.
My implementation is very similar to the demos provided:
@RequestMapping(value = {"/tusUpload", "/tusUpload/**"}, method = {RequestMethod.POST,
RequestMethod.PATCH, RequestMethod.HEAD, RequestMethod.DELETE, RequestMethod.GET})
public void upload(HttpServletRequest servletRequest,
HttpServletResponse servletResponse) throws IOException {
tusFileUploadService.process(servletRequest, servletResponse);
String uploadURI = servletRequest.getRequestURI();
UploadInfo uploadInfo = null;
try {
uploadInfo = tusFileUploadService.getUploadInfo(uploadURI);
} catch (IOException | TusException e) {
e.printStackTrace();
}
if (uploadInfo != null && !uploadInfo.isUploadInProgress()) {
try (InputStream stream = tusFileUploadService.getUploadedBytes(uploadURI)) {
String uploadURL = upload(new MockMultipartFile(uploadInfo.getFileName(), uploadInfo.getFileName(), uploadInfo.getFileMimeType(), IOUtils.toByteArray(stream))); // I know this is poor practice, just wanted to get something working first.
System.out.println(response);
// what to do here to tell the Uppy client what URL it's uploaded at?
} catch (IOException | TusException e) {
e.printStackTrace();
}
try {
tusFileUploadService.deleteUpload(uploadURI);
} catch (IOException | TusException e) {
e.printStackTrace();
}
}
My question is: What's the method (Is there one?) to tell the Uppy client the stored URL? Currently the client receives a URL, however it's not one that's hosted permanentlly (my uploadURL string is what I want the client to display).
URL the Uppy client displays for the "Copy Link" button and when clicking on the file's icon:
/tusUpload/f23a6d79-5bd8-4d50-8904-215752aaf483
Hello,
We are facing an exception when trying to upload a file from tus/tus-java-client (demo code) to tomdesair/tus-java-server. The server is located within a Quarkus server. Both tus modules are on their latest versions. We successfully uploaded the same files using Uppy (from tomdesair/tus-java-server-spring-demo) on a web interface.
This exception is raised on the upload start:
java.io.IOException: Protocol violation: Unexpected single newline character in chunk size
at me.desair.tus.server.util.HttpChunkedEncodingInputStream$ChunkSizeState$2.process(HttpChunkedEncodingInputStream.java:388)
at me.desair.tus.server.util.HttpChunkedEncodingInputStream.readChunkSizeInformation(HttpChunkedEncodingInputStream.java:213)
at me.desair.tus.server.util.HttpChunkedEncodingInputStream.getChunkSize(HttpChunkedEncodingInputStream.java:188)
at me.desair.tus.server.util.HttpChunkedEncodingInputStream.nextChunk(HttpChunkedEncodingInputStream.java:163)
at me.desair.tus.server.util.HttpChunkedEncodingInputStream.read(HttpChunkedEncodingInputStream.java:119)
at org.apache.commons.io.input.ProxyInputStream.read(ProxyInputStream.java:102)
at java.base/java.security.DigestInputStream.read(DigestInputStream.java:162)
at java.base/java.security.DigestInputStream.read(DigestInputStream.java:162)
at java.base/java.security.DigestInputStream.read(DigestInputStream.java:162)
at java.base/java.security.DigestInputStream.read(DigestInputStream.java:162)
at java.base/java.security.DigestInputStream.read(DigestInputStream.java:162)
at java.base/java.nio.channels.Channels$ReadableByteChannelImpl.read(Channels.java:388)
at java.base/sun.nio.ch.FileChannelImpl.transferFromArbitraryChannel(FileChannelImpl.java:746)
at java.base/sun.nio.ch.FileChannelImpl.transferFrom(FileChannelImpl.java:782)
at me.desair.tus.server.upload.disk.DiskStorageService.append(DiskStorageService.java:163)
at me.desair.tus.server.upload.cache.ThreadLocalCachedStorageAndLockingService.append(ThreadLocalCachedStorageAndLockingService.java:89)
at me.desair.tus.server.core.CorePatchRequestHandler.process(CorePatchRequestHandler.java:49)
at me.desair.tus.server.util.AbstractTusExtension.process(AbstractTusExtension.java:49)
at me.desair.tus.server.TusFileUploadService.executeProcessingByFeatures(TusFileUploadService.java:422)
at XX.YY.ZZ.service.CustomTusService_Subclass.executeProcessingByFeatures$$superaccessor18(CustomTusService_Subclass.zig:3177)
at XX.YY.ZZ.service.CustomTusService_Subclass$$function$$18.apply(CustomTusService_Subclass$$function$$18.zig:53)
at io.quarkus.arc.impl.AroundInvokeInvocationContext.proceed(AroundInvokeInvocationContext.java:54)
at io.quarkus.arc.runtime.devconsole.InvocationInterceptor.proceed(InvocationInterceptor.java:63)
at io.quarkus.arc.runtime.devconsole.InvocationInterceptor.monitor(InvocationInterceptor.java:49)
at io.quarkus.arc.runtime.devconsole.InvocationInterceptor_Bean.intercept(InvocationInterceptor_Bean.zig:521)
at io.quarkus.arc.impl.InterceptorInvocation.invoke(InterceptorInvocation.java:41)
at io.quarkus.arc.impl.AroundInvokeInvocationContext.perform(AroundInvokeInvocationContext.java:41)
at io.quarkus.arc.impl.InvocationContexts.performAroundInvoke(InvocationContexts.java:32)
at XX.YY.ZZ.service.CustomTusService_Subclass.executeProcessingByFeatures(CustomTusService_Subclass.zig:3110)
at me.desair.tus.server.TusFileUploadService.processLockedRequest(TusFileUploadService.java:408)
at XX.YY.ZZ.service.CustomTusService_Subclass.processLockedRequest$$superaccessor11(CustomTusService_Subclass.zig:2324)
at XX.YY.ZZ.service.CustomTusService_Subclass$$function$$11.apply(CustomTusService_Subclass$$function$$11.zig:53)
at io.quarkus.arc.impl.AroundInvokeInvocationContext.proceed(AroundInvokeInvocationContext.java:54)
at io.quarkus.arc.runtime.devconsole.InvocationInterceptor.proceed(InvocationInterceptor.java:63)
at io.quarkus.arc.runtime.devconsole.InvocationInterceptor.monitor(InvocationInterceptor.java:49)
at io.quarkus.arc.runtime.devconsole.InvocationInterceptor_Bean.intercept(InvocationInterceptor_Bean.zig:521)
at io.quarkus.arc.impl.InterceptorInvocation.invoke(InterceptorInvocation.java:41)
at io.quarkus.arc.impl.AroundInvokeInvocationContext.perform(AroundInvokeInvocationContext.java:41)
at io.quarkus.arc.impl.InvocationContexts.performAroundInvoke(InvocationContexts.java:32)
at XX.YY.ZZ.service.CustomTusService_Subclass.processLockedRequest(CustomTusService_Subclass.zig:2266)
at me.desair.tus.server.TusFileUploadService.process(TusFileUploadService.java:301)
at XX.YY.ZZ.service.CustomTusService_Subclass.process$$superaccessor20(CustomTusService_Subclass.zig:3456)
at XX.YY.ZZ.service.CustomTusService_Subclass$$function$$20.apply(CustomTusService_Subclass$$function$$20.zig:47)
at io.quarkus.arc.impl.AroundInvokeInvocationContext.proceed(AroundInvokeInvocationContext.java:54)
at io.quarkus.arc.runtime.devconsole.InvocationInterceptor.proceed(InvocationInterceptor.java:63)
at io.quarkus.arc.runtime.devconsole.InvocationInterceptor.monitor(InvocationInterceptor.java:49)
at io.quarkus.arc.runtime.devconsole.InvocationInterceptor_Bean.intercept(InvocationInterceptor_Bean.zig:521)
at io.quarkus.arc.impl.InterceptorInvocation.invoke(InterceptorInvocation.java:41)
at io.quarkus.arc.impl.AroundInvokeInvocationContext.perform(AroundInvokeInvocationContext.java:41)
at io.quarkus.arc.impl.InvocationContexts.performAroundInvoke(InvocationContexts.java:32)
at XX.YY.ZZ.service.CustomTusService_Subclass.process(CustomTusService_Subclass.zig:3400)
at me.desair.tus.server.TusFileUploadService.process(TusFileUploadService.java:274)
at XX.YY.ZZ.service.CustomTusService_Subclass.process$$superaccessor28(CustomTusService_Subclass.zig:4466)
at XX.YY.ZZ.service.CustomTusService_Subclass$$function$$28.apply(CustomTusService_Subclass$$function$$28.zig:41)
at io.quarkus.arc.impl.AroundInvokeInvocationContext.proceed(AroundInvokeInvocationContext.java:54)
at io.quarkus.arc.runtime.devconsole.InvocationInterceptor.proceed(InvocationInterceptor.java:63)
at io.quarkus.arc.runtime.devconsole.InvocationInterceptor.monitor(InvocationInterceptor.java:49)
at io.quarkus.arc.runtime.devconsole.InvocationInterceptor_Bean.intercept(InvocationInterceptor_Bean.zig:521)
at io.quarkus.arc.impl.InterceptorInvocation.invoke(InterceptorInvocation.java:41)
at io.quarkus.arc.impl.AroundInvokeInvocationContext.perform(AroundInvokeInvocationContext.java:41)
at io.quarkus.arc.impl.InvocationContexts.performAroundInvoke(InvocationContexts.java:32)
at XX.YY.ZZ.service.CustomTusService_Subclass.process(CustomTusService_Subclass.zig:4412)
at XX.YY.ZZ.service.CustomTusService_ClientProxy.process(CustomTusService_ClientProxy.zig:687)
at XX.YY.ZZ.controller.upload.Upload.processUpload(Upload.java:53)
at XX.YY.ZZ.controller.upload.Upload_Subclass.processUpload$$superaccessor3(Upload_Subclass.zig:557)
at XX.YY.ZZ.controller.upload.Upload_Subclass$$function$$3.apply(Upload_Subclass$$function$$3.zig:41)
at io.quarkus.arc.impl.AroundInvokeInvocationContext.proceed(AroundInvokeInvocationContext.java:54)
at io.quarkus.arc.runtime.devconsole.InvocationInterceptor.proceed(InvocationInterceptor.java:63)
at io.quarkus.arc.runtime.devconsole.InvocationInterceptor.monitor(InvocationInterceptor.java:49)
at io.quarkus.arc.runtime.devconsole.InvocationInterceptor_Bean.intercept(InvocationInterceptor_Bean.zig:521)
at io.quarkus.arc.impl.InterceptorInvocation.invoke(InterceptorInvocation.java:41)
at io.quarkus.arc.impl.AroundInvokeInvocationContext.perform(AroundInvokeInvocationContext.java:41)
at io.quarkus.arc.impl.InvocationContexts.performAroundInvoke(InvocationContexts.java:32)
at XX.YY.ZZ.controller.upload.Upload_Subclass.processUpload(Upload_Subclass.zig:503)
at XX.YY.ZZ.controller.upload.Upload.process2Upload(Upload.java:64)
at XX.YY.ZZ.controller.upload.Upload_Subclass.process2Upload$$superaccessor4(Upload_Subclass.zig:688)
at XX.YY.ZZ.controller.upload.Upload_Subclass$$function$$4.apply(Upload_Subclass$$function$$4.zig:41)
at io.quarkus.arc.impl.AroundInvokeInvocationContext.proceed(AroundInvokeInvocationContext.java:54)
at io.quarkus.arc.runtime.devconsole.InvocationInterceptor.proceed(InvocationInterceptor.java:63)
at io.quarkus.arc.runtime.devconsole.InvocationInterceptor.monitor(InvocationInterceptor.java:49)
at io.quarkus.arc.runtime.devconsole.InvocationInterceptor_Bean.intercept(InvocationInterceptor_Bean.zig:521)
at io.quarkus.arc.impl.InterceptorInvocation.invoke(InterceptorInvocation.java:41)
at io.quarkus.arc.impl.AroundInvokeInvocationContext.perform(AroundInvokeInvocationContext.java:41)
at io.quarkus.arc.impl.InvocationContexts.performAroundInvoke(InvocationContexts.java:32)
at XX.YY.ZZ.controller.upload.Upload_Subclass.process2Upload(Upload_Subclass.zig:634)
at XX.YY.ZZ.controller.upload.Upload_ClientProxy.process2Upload(Upload_ClientProxy.zig:136)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:78)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:170)
at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:130)
at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:643)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:507)
at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$2(ResourceMethodInvoker.java:457)
at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:459)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:419)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:393)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:68)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:492)
at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:261)
at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:161)
at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:164)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:247)
at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:249)
at io.quarkus.resteasy.runtime.ResteasyFilter.doFilter(ResteasyFilter.java:35)
at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:63)
at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
at io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:67)
at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:133)
at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:65)
at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:247)
at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:56)
at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:111)
at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:108)
at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
at io.quarkus.undertow.runtime.UndertowDeploymentRecorder$9$1.call(UndertowDeploymentRecorder.java:587)
at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:227)
at io.undertow.servlet.handlers.ServletInitialHandler.handleRequest(ServletInitialHandler.java:152)
at io.undertow.server.handlers.PathHandler.handleRequest(PathHandler.java:91)
at io.quarkus.undertow.runtime.UndertowDeploymentRecorder$1.handleRequest(UndertowDeploymentRecorder.java:119)
at io.undertow.server.Connectors.executeRootHandler(Connectors.java:290)
at io.undertow.server.DefaultExchangeHandler.handle(DefaultExchangeHandler.java:18)
at io.quarkus.undertow.runtime.UndertowDeploymentRecorder$5$1.run(UndertowDeploymentRecorder.java:413)
at io.quarkus.runtime.CleanableExecutor$CleaningRunnable.run(CleanableExecutor.java:231)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2415)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1452)
at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
at java.base/java.lang.Thread.run(Thread.java:831)
at org.jboss.threads.JBossThread.run(JBossThread.java:501)
Followed by this exception:
2021-04-30 11:37:56,339 ERROR [io.und.req.io] (executor-thread-1) Exception handling request 697b1502-90e6-4dc0-9a44-61f8a78dedcb-1 to /test/api/upload/163b7706-b869-4ef7-ba3e-06a55d200d50: org.jboss.resteasy.spi.UnhandledException: java.lang.IllegalStateException: Response head already sent
at org.jboss.resteasy.core.SynchronousDispatcher.writeException(SynchronousDispatcher.java:230)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:519)
at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:261)
at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:161)
at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:164)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:247)
at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:249)
at io.quarkus.resteasy.runtime.ResteasyFilter.doFilter(ResteasyFilter.java:35)
at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:63)
at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
at io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:67)
at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:133)
at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:65)
at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:247)
at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:56)
at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:111)
at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:108)
at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
at io.quarkus.undertow.runtime.UndertowDeploymentRecorder$9$1.call(UndertowDeploymentRecorder.java:587)
at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:227)
at io.undertow.servlet.handlers.ServletInitialHandler.handleRequest(ServletInitialHandler.java:152)
at io.undertow.server.handlers.PathHandler.handleRequest(PathHandler.java:91)
at io.quarkus.undertow.runtime.UndertowDeploymentRecorder$1.handleRequest(UndertowDeploymentRecorder.java:119)
at io.undertow.server.Connectors.executeRootHandler(Connectors.java:290)
at io.undertow.server.DefaultExchangeHandler.handle(DefaultExchangeHandler.java:18)
at io.quarkus.undertow.runtime.UndertowDeploymentRecorder$5$1.run(UndertowDeploymentRecorder.java:413)
at io.quarkus.runtime.CleanableExecutor$CleaningRunnable.run(CleanableExecutor.java:231)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2415)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1452)
at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
at java.base/java.lang.Thread.run(Thread.java:831)
at org.jboss.threads.JBossThread.run(JBossThread.java:501)
The upload then fail on the client at different percentages of completion.
Thanks for your help
I was trying the https://github.com/tomdesair/tus-java-server-spring-demo with a simple Java Client (based on official tus-java-client)
If I kill the client and resume the upload everything is just fine.
I would expect the same when I kill the server with pending uploads.
After a unexpected shutdown (CTRL+C or power loss) of the tus-java-server, I could not resume the upload that was in progress.
I shutdown the server during a big (1gb) upload.
Then I restarted the server and tried to run the client again. And the server can not handle this upload anymore. (I put the stacktrace and java client at the end)
If I try this same scenario with tusd (official server), everything works as expected (I can resume the upload)
I have the following stacktrace
java.io.EOFException: null
at java.io.ObjectInputStream$PeekInputStream.readFully(ObjectInputStream.java:2681) ~[na:1.8.0_221]
at java.io.ObjectInputStream$BlockDataInputStream.readShort(ObjectInputStream.java:3156) ~[na:1.8.0_221]
at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:862) ~[na:1.8.0_221]
at java.io.ObjectInputStream.<init>(ObjectInputStream.java:358) ~[na:1.8.0_221]
at me.desair.tus.server.util.Utils.readSerializable(Utils.java:86) ~[tus-java-server-1.0.0-2.0.jar!/:na]
at me.desair.tus.server.upload.disk.DiskStorageService.getUploadInfo(DiskStorageService.java:95) ~[tus-java-server-1.0.0-2.0.jar!/:na]
at me.desair.tus.server.upload.cache.ThreadLocalCachedStorageAndLockingService.getUploadInfo(ThreadLocalCachedStorageAndLockingService.java:53) ~[tus-java-server-1.0.0-2.0.jar!/:na]
at me.desair.tus.server.upload.cache.ThreadLocalCachedStorageAndLockingService.getUploadInfo(ThreadLocalCachedStorageAndLockingService.java:61) ~[tus-java-server-1.0.0-2.0.jar!/:na]
at me.desair.tus.server.core.validation.IdExistsValidator.validate(IdExistsValidator.java:24) ~[tus-java-server-1.0.0-2.0.jar!/:na]
at me.desair.tus.server.util.AbstractTusExtension.validate(AbstractTusExtension.java:37) ~[tus-java-server-1.0.0-2.0.jar!/:na]
at me.desair.tus.server.TusFileUploadService.validateRequest(TusFileUploadService.java:431) ~[tus-java-server-1.0.0-2.0.jar!/:na]
at me.desair.tus.server.TusFileUploadService.processLockedRequest(TusFileUploadService.java:406) ~[tus-java-server-1.0.0-2.0.jar!/:na]
at me.desair.tus.server.TusFileUploadService.process(TusFileUploadService.java:301) ~[tus-java-server-1.0.0-2.0.jar!/:na]
at me.desair.tus.server.TusFileUploadService.process(TusFileUploadService.java:274) ~[tus-java-server-1.0.0-2.0.jar!/:na]
at me.desair.spring.tus.FileUploadController.processUpload(FileUploadController.java:24) ~[classes!/:0.0.1-SNAPSHOT]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_221]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_221]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_221]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_221]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-4.3.21.RELEASE.jar!/:4.3.21.RELEASE]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133) ~[spring-web-4.3.21.RELEASE.jar!/:4.3.21.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97) ~[spring-webmvc-4.3.21.RELEASE.jar!/:4.3.21.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:849) ~[spring-webmvc-4.3.21.RELEASE.jar!/:4.3.21.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:760) ~[spring-webmvc-4.3.21.RELEASE.jar!/:4.3.21.RELEASE]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[spring-webmvc-4.3.21.RELEASE.jar!/:4.3.21.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967) ~[spring-webmvc-4.3.21.RELEASE.jar!/:4.3.21.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901) ~[spring-webmvc-4.3.21.RELEASE.jar!/:4.3.21.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) ~[spring-webmvc-4.3.21.RELEASE.jar!/:4.3.21.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861) ~[spring-webmvc-4.3.21.RELEASE.jar!/:4.3.21.RELEASE]
at javax.servlet.http.HttpServlet.doHead(HttpServlet.java:245) ~[tomcat-embed-core-8.5.35.jar!/:8.5.35]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:658) ~[tomcat-embed-core-8.5.35.jar!/:8.5.35]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) ~[spring-webmvc-4.3.21.RELEASE.jar!/:4.3.21.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) ~[tomcat-embed-core-8.5.35.jar!/:8.5.35]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-8.5.35.jar!/:8.5.35]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.35.jar!/:8.5.35]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed-websocket-8.5.35.jar!/:8.5.35]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.35.jar!/:8.5.35]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.35.jar!/:8.5.35]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-4.3.21.RELEASE.jar!/:4.3.21.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.21.RELEASE.jar!/:4.3.21.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.35.jar!/:8.5.35]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.35.jar!/:8.5.35]
at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:109) ~[spring-web-4.3.21.RELEASE.jar!/:4.3.21.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.21.RELEASE.jar!/:4.3.21.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.35.jar!/:8.5.35]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.35.jar!/:8.5.35]
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) ~[spring-web-4.3.21.RELEASE.jar!/:4.3.21.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.21.RELEASE.jar!/:4.3.21.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.35.jar!/:8.5.35]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.35.jar!/:8.5.35]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) ~[spring-web-4.3.21.RELEASE.jar!/:4.3.21.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.21.RELEASE.jar!/:4.3.21.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.35.jar!/:8.5.35]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.35.jar!/:8.5.35]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) ~[tomcat-embed-core-8.5.35.jar!/:8.5.35]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.35.jar!/:8.5.35]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:493) [tomcat-embed-core-8.5.35.jar!/:8.5.35]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.35.jar!/:8.5.35]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81) [tomcat-embed-core-8.5.35.jar!/:8.5.35]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.35.jar!/:8.5.35]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [tomcat-embed-core-8.5.35.jar!/:8.5.35]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:800) [tomcat-embed-core-8.5.35.jar!/:8.5.35]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.35.jar!/:8.5.35]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:806) [tomcat-embed-core-8.5.35.jar!/:8.5.35]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1498) [tomcat-embed-core-8.5.35.jar!/:8.5.35]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.35.jar!/:8.5.35]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_221]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_221]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.35.jar!/:8.5.35]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_221]
I start the server demo
I run this java client
I kill server
I kill client
I start the server demo
I run this java client
(I got error above)
public class Client {
public static void main(String args[]) throws IOException, ProtocolException {
Path testFile = Paths.get("/path/to/big/file");
// Upload file to server
var client = new TusClient();
client.setUploadCreationURL(URI.create("http://localhost:8080/test/api/upload").toURL());
client.enableResuming(new MyTusURLPropertiesStore("./fingerprints.properties"));
TusUpload upload = new TusUpload(testFile.toFile());
var executor = new TusExecutor() {
@Override
protected void makeAttempt() throws ProtocolException, IOException {
TusUploader uploader = client.resumeOrCreateUpload(upload);
uploader.setChunkSize(1024);
do {
long totalBytes = upload.getSize();
long bytesUploaded = uploader.getOffset();
double progress = (double) bytesUploaded / totalBytes * 100;
System.out.printf("Upload at %6.2f %%.\n", progress);
} while (uploader.uploadChunk() > -1);
uploader.finish();
}
};
System.out.println(executor.makeAttempts() ? "Upload successful" : "Upload interrupted");
}
}
class MyTusURLPropertiesStore implements TusURLStore {
private final Path arquivoConfig;
String propertiesFile;
Properties properties;
public MyTusURLPropertiesStore(String propertiesFile) throws IOException {
this.propertiesFile = propertiesFile;
arquivoConfig = Paths.get(propertiesFile);
if (!Files.exists(arquivoConfig)) {
Files.createDirectories(arquivoConfig.getParent());
Files.createFile(arquivoConfig);
}
try (InputStream inputStream = Files.newInputStream(arquivoConfig)) {
this.properties = new Properties();
this.properties.load(inputStream);
}
}
private void gravar() {
try (OutputStream outputStream = Files.newOutputStream(arquivoConfig)) {
this.properties.store(outputStream, null);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void set(String fingerprint, URL url) {
try {
this.properties.put(fingerprint, url.toURI().toASCIIString());
} catch (URISyntaxException e) {
e.printStackTrace();
}
gravar();
}
@Override
public URL get(String fingerprint) {
Object o = this.properties.get(fingerprint);
if (o != null) {
try {
return URI.create((String) o).toURL();
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
return null;
}
@Override
public void remove(String fingerprint) {
this.properties.remove(fingerprint);
gravar();
}
}
In JDK11 the javax.xml.bind
package was removed. You use the javax.xml.bind.DatatypeConverter
for Base64 encoding. Maybe you can replace this with java.util.Base64
from Java 8 or other implementation?
How to make the uploaded file on the server with corrected file extension? Currently, the uploaded file on the server has no file extensions. All of them is named "data".
Does this work with Nginx reverse proxy? How do I set it up?
John
When a call exceeds the defined MaxUploadSize we would like to provide our own error response, so that it matches our other responses made to the frontend.
A (correct) 413 is returned with a predefined error message.
Is there a way to define/use our own response in this case?
CoreDefaultResponseHeadersHandler always writes header Content-Length=0
If some error detected, like incorrect offset, TUS calls HttpServletResponse.sendError() with some message. In other words there is nonempty response with header Content-Length=0. Undertow throws exception, probably because it allocates output buffer based on Content-Length header.
How to fix:
Remove setting Content-Length=0 from CoreDefaultResponseHeadersHandler.
Or overwrite Content-Length header before calling HttpServletResponse.sendError()
I found that the lib not support creation-with-upload extension.
Is there any plan to support that? or is there any problem to support the exension?
Hi thanks for a great lib. Im using it and its working fine. BUt i need some data to be returned in the body. Is there a way to modify the response? because i tried to modify the HttpServletResponse and that doest work. Thanks for help
file feature download chinese filename error
(Please describe the behaviour you expected to see. If possible please refer to paragraphs of the official tus protocol specification on https://tus.io/.)
upload failed with exception
(What faulty behaviour does the implementation have?)
java.io.IOException: Protocol violation: Unexpected single newline character in chunk size at me.desair.tus.server.util.HttpChunkedEncodingInputStream$ChunkSizeState$2.process(HttpChunkedEncodingInputStream.java:389) at me.desair.tus.server.util.HttpChunkedEncodingInputStream.readChunkSizeInformation(HttpChunkedEncodingInputStream.java:214) at me.desair.tus.server.util.HttpChunkedEncodingInputStream.getChunkSize(HttpChunkedEncodingInputStream.java:189) at me.desair.tus.server.util.HttpChunkedEncodingInputStream.nextChunk(HttpChunkedEncodingInputStream.java:164) at me.desair.tus.server.util.HttpChunkedEncodingInputStream.read(HttpChunkedEncodingInputStream.java:120) at org.apache.commons.io.input.ProxyInputStream.read(ProxyInputStream.java:99) at java.security.DigestInputStream.read(DigestInputStream.java:161) at java.security.DigestInputStream.read(DigestInputStream.java:161) at java.security.DigestInputStream.read(DigestInputStream.java:161) at java.security.DigestInputStream.read(DigestInputStream.java:161) at java.security.DigestInputStream.read(DigestInputStream.java:161) at java.nio.channels.Channels$ReadableByteChannelImpl.read(Channels.java:385) at sun.nio.ch.FileChannelImpl.transferFromArbitraryChannel(FileChannelImpl.java:673) at sun.nio.ch.FileChannelImpl.transferFrom(FileChannelImpl.java:711) at me.desair.tus.server.upload.disk.DiskStorageService.append(DiskStorageService.java:158) at me.desair.tus.server.core.CorePatchRequestHandler.process(CorePatchRequestHandler.java:49) at me.desair.tus.server.util.AbstractTusExtension.process(AbstractTusExtension.java:49) at me.desair.tus.server.TusFileUploadService.executeProcessingByFeatures(TusFileUploadService.java:293) at me.desair.tus.server.TusFileUploadService.processLockedRequest(TusFileUploadService.java:279) at me.desair.tus.server.TusFileUploadService.process(TusFileUploadService.java:172) at me.desair.tus.server.TusFileUploadService.process(TusFileUploadService.java:155) at com.acmedcare.tiffany.framework.nas.rest.server.NasServerBootstrap$FileUploadController.processUpload(NasServerBootstrap.java:112) at sun.reflect.GeneratedMethodAccessor28.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:209) at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136) at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:877) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:783) at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:974) at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:877) at javax.servlet.http.HttpServlet.service(HttpServlet.java:661) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:851) at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:96) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:109) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:493) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:800) at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:800) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1471) at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Thread.java:745)
(Ideally, you specify detailed steps using the curl command.)
// Create a new TusClient instance
TusClient client = new TusClient();
// Configure tus HTTP endpoint. This URL will be used for creating new uploads
// using the Creation extension
client.setUploadCreationURL(new URL("https://master.tus.io/files"));
// Enable resumable uploads by storing the upload URL in memory
client.enableResuming(new TusURLMemoryStore());
// Open a file using which we will then create a TusUpload. If you do not have
// a File object, you can manually construct a TusUpload using an InputStream.
// See the documentation for more information.
File file = new File("./cute_kitten.png");
final TusUpload upload = new TusUpload(file);
System.out.println("Starting upload...");
// We wrap our uploading code in the TusExecutor class which will automatically catch
// exceptions and issue retries with small delays between them and take fully
// advantage of tus' resumability to offer more reliability.
// This step is optional but highly recommended.
TusExecutor executor = new TusExecutor() {
@Override
protected void makeAttempt() throws ProtocolException, IOException {
// First try to resume an upload. If that's not possible we will create a new
// upload and get a TusUploader in return. This class is responsible for opening
// a connection to the remote server and doing the uploading.
TusUploader uploader = client.resumeOrCreateUpload(upload);
// Alternatively, if your tus server does not support the Creation extension
// and you obtained an upload URL from another service, you can instruct
// tus-java-client to upload to a specific URL. Please note that this is usually
// _not_ necessary and only if the tus server does not support the Creation
// extension. The Vimeo API would be an example where this method is needed.
// TusUploader uploader = client.beginOrResumeUploadFromURL(upload, new URL("https://tus.server.net/files/my_file"));
// Upload the file in chunks of 1KB sizes.
uploader.setChunkSize(1024);
// Upload the file as long as data is available. Once the
// file has been fully uploaded the method will return -1
do {
// Calculate the progress using the total size of the uploading file and
// the current offset.
long totalBytes = upload.getSize();
long bytesUploaded = uploader.getOffset();
double progress = (double) bytesUploaded / totalBytes * 100;
System.out.printf("Upload at %06.2f%%.\n", progress);
} while(uploader.uploadChunk() > -1);
// Allow the HTTP connection to be closed and cleaned up
uploader.finish();
System.out.println("Upload finished.");
System.out.format("Upload available at: %s", uploader.getUploadURL().toString());
}
};
executor.makeAttempts();
When I integrate my file service into a eureka gateway, I meet a error when I try to upload a file via request /upload
Meet a error :
me.desair.tus.server.TusFileUploadService: Unable to process request POST http://ip:port/upload. Sent response status 405 with message "POST requests have to be send to /api/file/upload"
/api/file
is the prefix of this service in my gateway
It would be nice if the uploadURI can contain some path variables because I need some extra information to the file upload and it fits better to my REST URIs than putting it into the Upload-Metadata.
E.g. /users/{userId}/files/upload
POST /users/123/files/upload
returns 405
with message: POST requests have to be send to /users/{userId}/files/upload
thank u for sharing such a good project, I found the uploaded content is stored at uploads folder of a name like uuid. But how can I get the list of the data information, because I may want to manually delete some content like old images or files. is there an API i can get them?
Hi Tom, thanks for the great work.. the library works great for our file transfer use case.
We are currently using springframework.. and we have the below requirements
Can you provide guidelines on how to implement the same. We can develop the same and share.
@controller
@RequestMapping("/upload")
public class FileUploadController {
@value("${tus.server.data.directory}")
protected String tusDataPath;
@Autowired
private TusFileUploadService tusFileUploadService;
@Autowired
private FileUploadService fileUploadService;
//@CrossOrigin(origins = "http://127.0.0.1:8080",exposedHeaders = {"Location","Upload-Offset","Upload-Length"})
@RequestMapping(value = {"", "/**"}, method = {RequestMethod.POST, RequestMethod.PATCH, RequestMethod.HEAD,
RequestMethod.DELETE, RequestMethod.OPTIONS, RequestMethod.GET})
public void processUpload(final HttpServletRequest servletRequest, final HttpServletResponse servletResponse) {
// tusFileUploadService.withUploadURI(servletRequest.getContextPath() + "/upload");
try {
tusFileUploadService.process(servletRequest, servletResponse);
String hLocation = servletResponse.getHeader(HttpHeader.LOCATION);
if(hLocation!=null){
while(true){
UploadInfo ui = tusFileUploadService.getUploadInfo(hLocation);
if(ui!=null && !ui.isUploadInProgress()) {
InputStream uploadedBytes = tusFileUploadService.getUploadedBytes(hLocation);
///////////////////////////// others code here
break;
}
}
}
} catch (IOException | TusException e) {
e.printStackTrace();
}
}
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.