• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tomdesair / tus-java-server / 30392977559

28 Jul 2026 07:40PM UTC coverage: 96.255% (+1.4%) from 94.883%
30392977559

push

github

web-flow
feat: Implement IETF Resumable Uploads for HTTP (RUFH) Protocol (#105)

* feat: Implement IETF Resumable Uploads for HTTP (RUFH) draft-11 protocol

* test: increase test coverage for resumable uploads implementation

* "fix: Update spec-watch to only run once per week"

* Refactor RUFH extension to exception-driven error handling, unify response writing, clean request handler and extension interfaces

* Make RequestHandler.process(5 params) default method to support clean compile in Java 21

* Refactor RUFH response headers to RufhResponseHeadersHandler

* refactor: relocate HttpProblemDetails to main me.desair.tus.server package

* Implement RFC 9530 HTTP Digests Extension for RUFH with deduplication index base64-to-hex storage in DiskStorageService

* Support download extension in RUFH protocol version

* feat(rufh): upgrade IETF Resumable Uploads for HTTP implementation to draft-12 compliance

* feat: Small code improvements

* refactor: remove unused ACCEPT_PATCH and test-only HttpProblemDetails methods, enhance RUFH integration tests

* docs: instruct agents to run git and gh commands unsandboxed

* fix: disallow illegal Windows path characters in DiskStorageService path validation

* feat: README improvements

1301 of 1404 branches covered (92.66%)

Branch coverage included in aggregate %.

847 of 848 new or added lines in 47 files covered. (99.88%)

4 existing lines in 2 files now uncovered.

2786 of 2842 relevant lines covered (98.03%)

6.4 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

78.79
/src/main/java/me/desair/tus/server/creationwithupload/CreationWithUploadPostRequestHandler.java
1
package me.desair.tus.server.creationwithupload;
2

3
import java.io.IOException;
4
import java.io.InputStream;
5
import me.desair.tus.server.HttpHeader;
6
import me.desair.tus.server.HttpMethod;
7
import me.desair.tus.server.exception.TusException;
8
import me.desair.tus.server.upload.UploadInfo;
9
import me.desair.tus.server.upload.UploadLockingService;
10
import me.desair.tus.server.upload.UploadStorageService;
11
import me.desair.tus.server.util.AbstractRequestHandler;
12
import me.desair.tus.server.util.InterruptibleInputStream;
13
import me.desair.tus.server.util.TusServletRequest;
14
import me.desair.tus.server.util.TusServletResponse;
15
import me.desair.tus.server.util.Utils;
16
import org.slf4j.Logger;
17
import org.slf4j.LoggerFactory;
18

19
/** Request handler to process the POST request body for the creation-with-upload extension. */
20
public class CreationWithUploadPostRequestHandler extends AbstractRequestHandler {
6✔
21

22
  private static final Logger log =
4✔
23
      LoggerFactory.getLogger(CreationWithUploadPostRequestHandler.class);
4✔
24

25
  @Override
26
  public boolean supports(HttpMethod method) {
27
    return HttpMethod.POST.equals(method);
8✔
28
  }
29

30
  @Override
31
  public void process(
32
      HttpMethod method,
33
      TusServletRequest servletRequest,
34
      TusServletResponse servletResponse,
35
      UploadStorageService uploadStorageService,
36
      String ownerKey)
37
      throws IOException, TusException {
38

39
    Long contentLength = Utils.getLongHeader(servletRequest, HttpHeader.CONTENT_LENGTH);
4✔
40
    if (contentLength != null && contentLength > 0) {
7✔
41
      String location = servletResponse.getHeader(HttpHeader.LOCATION);
4✔
42
      if (location != null) {
2!
43
        UploadInfo uploadInfo = uploadStorageService.getUploadInfo(location, ownerKey);
5✔
44
        if (uploadInfo != null && uploadInfo.isUploadInProgress()) {
5!
45
          InputStream stream = servletRequest.getContentInputStream();
3✔
46
          UploadLockingService lockingService =
2✔
47
              (UploadLockingService)
48
                  servletRequest.getAttribute("me.desair.tus.uploadLockingService");
3✔
49
          if (lockingService != null) {
2!
UNCOV
50
            InterruptibleInputStream interruptibleStream = new InterruptibleInputStream(stream);
×
UNCOV
51
            lockingService.registerInputStream(location, interruptibleStream);
×
UNCOV
52
            stream = interruptibleStream;
×
53
          }
54

55
          uploadInfo = uploadStorageService.append(uploadInfo, stream);
5✔
56

57
          servletResponse.setHeader(
4✔
58
              HttpHeader.UPLOAD_OFFSET, String.valueOf(uploadInfo.getOffset()));
2✔
59
        }
60
      }
61
    }
62
  }
1✔
63
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc