Turns out this has been tripping an assertion basically forever, but until https://github.com/elastic/elasticsearch/pull/102976 we were just swallowing it.

**Build scan:**
https://gradle-enterprise.elastic.co/s/fqyklzmrdoozc/tests/:x-pack:plugin:snapshot-repo-test-kit:qa:s3:javaRestTest/org.elasticsearch.repositories.blobstore.testkit.S3SnapshotRepoTestKitIT/testRepositoryAnalysis


**Reproduction line:**
```
./gradlew ':x-pack:plugin:snapshot-repo-test-kit:qa:s3:javaRestTest' --tests "org.elasticsearch.repositories.blobstore.testkit.S3SnapshotRepoTestKitIT.testRepositoryAnalysis" -Dtests.seed=AD352AD47F2A3AA5 -Dtests.locale=lt -Dtests.timezone=Europe/Oslo -Druntime.java=21
```

**Applicable branches:**
main

**Reproduces locally?:**
Didn't try

**Failure history:**
[Failure dashboard for `org.elasticsearch.repositories.blobstore.testkit.S3SnapshotRepoTestKitIT#testRepositoryAnalysis`](https://es-delivery-stats.elastic.dev/app/dashboards#/view/dcec9e60-72ac-11ee-8f39-55975ded9e63?_g=(refreshInterval:(pause:!t,value:60000),time:(from:now-7d%2Fd,to:now))&_a=(controlGroupInput:(chainingSystem:HIERARCHICAL,controlStyle:twoLine,ignoreParentSettings:(ignoreFilters:!f,ignoreQuery:!f,ignoreTimerange:!f,ignoreValidations:!t),panels:('0c0c9cb8-ccd2-45c6-9b13-96bac4abc542':(explicitInput:(dataViewId:fbbdc689-be23-4b3d-8057-aa402e9ed0c5,enhancements:(),fieldName:task.keyword,grow:!t,id:'0c0c9cb8-ccd2-45c6-9b13-96bac4abc542',searchTechnique:wildcard,selectedOptions:!(),singleSelect:!t,title:'Gradle%20Task',width:medium),grow:!t,order:0,type:optionsListControl,width:small),'144933da-5c1b-4257-a969-7f43455a7901':(explicitInput:(dataViewId:fbbdc689-be23-4b3d-8057-aa402e9ed0c5,enhancements:(),fieldName:name.keyword,grow:!t,id:'144933da-5c1b-4257-a969-7f43455a7901',searchTechnique:wildcard,selectedOptions:!('testRepositoryAnalysis'),title:Test,width:medium),grow:!t,order:2,type:optionsListControl,width:medium),'4e6ad9d6-6fdc-4fcc-bf1a-aa6ca79e0850':(explicitInput:(dataViewId:fbbdc689-be23-4b3d-8057-aa402e9ed0c5,enhancements:(),fieldName:className.keyword,grow:!t,id:'4e6ad9d6-6fdc-4fcc-bf1a-aa6ca79e0850',searchTechnique:wildcard,selectedOptions:!('org.elasticsearch.repositories.blobstore.testkit.S3SnapshotRepoTestKitIT'),title:Suite,width:medium),grow:!t,order:1,type:optionsListControl,width:medium)))))


**Failure excerpt:**
```
java.lang.AssertionError: parseRequestBody failed

  at __randomizedtesting.SeedInfo.seed([AD352AD47F2A3AA5]:0)
  at fixture.s3.S3HttpHandler.parseRequestBody(S3HttpHandler.java:390)
  at fixture.s3.S3HttpHandler.handle(S3HttpHandler.java:183)
  at fixture.s3.S3HttpFixture$1.handle(S3HttpFixture.java:58)
  at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:98)
  at sun.net.httpserver.AuthFilter.doFilter(AuthFilter.java:82)
  at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:101)
  at sun.net.httpserver.ServerImpl$Exchange$LinkHandler.handle(ServerImpl.java:871)
  at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:98)
  at sun.net.httpserver.ServerImpl$Exchange.run(ServerImpl.java:847)
  at sun.net.httpserver.ServerImpl$DefaultExecutor.execute(ServerImpl.java:204)
  at sun.net.httpserver.ServerImpl$Dispatcher.handle(ServerImpl.java:566)
  at sun.net.httpserver.ServerImpl$Dispatcher.run(ServerImpl.java:532)
  at java.lang.Thread.run(Thread.java:1583)

  Caused by: java.io.IOException: connection closed before all data received

    at sun.net.httpserver.FixedLengthInputStream.readImpl(FixedLengthInputStream.java:67)
    at sun.net.httpserver.LeftOverInputStream.read(LeftOverInputStream.java:99)
    at java.io.FilterInputStream.read(FilterInputStream.java:95)
    at org.elasticsearch.core.Streams.copy(Streams.java:45)
    at org.elasticsearch.core.Streams.copy(Streams.java:79)
    at org.elasticsearch.common.io.Streams.readFully(Streams.java:189)
    at fixture.s3.S3HttpHandler.parseRequestBody(S3HttpHandler.java:320)
    at fixture.s3.S3HttpHandler.handle(S3HttpHandler.java:183)
    at fixture.s3.S3HttpFixture$1.handle(S3HttpFixture.java:58)
    at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:98)
    at sun.net.httpserver.AuthFilter.doFilter(AuthFilter.java:82)
    at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:101)
    at sun.net.httpserver.ServerImpl$Exchange$LinkHandler.handle(ServerImpl.java:871)
    at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:98)
    at sun.net.httpserver.ServerImpl$Exchange.run(ServerImpl.java:847)
    at sun.net.httpserver.ServerImpl$DefaultExecutor.execute(ServerImpl.java:204)
    at sun.net.httpserver.ServerImpl$Dispatcher.handle(ServerImpl.java:566)
    at sun.net.httpserver.ServerImpl$Dispatcher.run(ServerImpl.java:532)
    at java.lang.Thread.run(Thread.java:1583)

```
test/fixtures/s3-fixture/src/main/java/fixture/s3/S3HttpHandler.java
exchange.getResponseHeaders().add("Content-Type", "application/xml");
                exchange.sendResponseHeaders(RestStatus.OK.getStatus(), response.length);
                exchange.getResponseBody().write(response);
            } else if (Regex.simpleMatch("GET /" + path + "/*", request)) {
                final BytesReference blob = blobs.get(exchange.getRequestURI().toString());
                if (blob != null) {
                    final String range = exchange.getRequestHeaders().getFirst("Range");
                    if (range == null) {
                        exchange.getResponseHeaders().add("Content-Type", "application/octet-stream");
                        exchange.sendResponseHeaders(RestStatus.OK.getStatus(), blob.length());
                        blob.writeTo(exchange.getResponseBody());
                    } else {
                        final Matcher matcher = Pattern.compile("^bytes=([0-9]+)-([0-9]+)$").matcher(range);
                        if (matcher.matches() == false) {
                            throw new AssertionError("Bytes range does not match expected pattern: " + range);
                        }
                        final int start = Integer.parseInt(matcher.group(1));
                        final int end = Integer.parseInt(matcher.group(2));
                        final BytesReference rangeBlob = blob.slice(start, end + 1 - start);
                        exchange.getResponseHeaders().add("Content-Type", "application/octet-stream");
                        exchange.getResponseHeaders()
                            .add("Content-Range", String.format(Locale.ROOT, "bytes %d-%d/%d", start, end, rangeBlob.length()));
                        exchange.sendResponseHeaders(RestStatus.OK.getStatus(), rangeBlob.length());
                        rangeBlob.writeTo(exchange.getResponseBody());
                    }
                } else {
                    exchange.sendResponseHeaders(RestStatus.NOT_FOUND.getStatus(), -1);
                }
            } else if (Regex.simpleMatch("DELETE /" + path + "/*", request)) {
                int deletions = 0;