@sproutboat/toolchain 0.4.4 → 0.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @sproutboat/toolchain
2
2
 
3
+ ## 0.4.5
4
+
5
+ ### Patch Changes
6
+
7
+ - 5ee065c: Stream standalone direct R2 byte ranges safely and support ETag conditionals.
8
+
3
9
  ## 0.4.4
4
10
 
5
11
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sproutboat/toolchain",
3
- "version": "0.4.4",
3
+ "version": "0.4.5",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "repository": {
package/src/patch.test.ts CHANGED
@@ -171,6 +171,8 @@ test("#156: status-line fallback synthesizes a line for unlisted codes, idempote
171
171
  expect(once).toContain("try_handle_r2_transfer(res, req, method)");
172
172
  expect(once).toContain("sb_r2_transfer_download_open");
173
173
  expect(once).toContain("sb_r2_transfer_download_v1");
174
+ expect(once).toContain("sb_r2_transfer_range_v1");
175
+ expect(once).toContain("sb_r2_transfer_conditional_v1");
174
176
 
175
177
  // #163: collect_headers takes res, drops a client-sent x-sb-remote-addr, and
176
178
  // appends the real peer; the call site passes res through.
package/src/patch.ts CHANGED
@@ -425,6 +425,7 @@ const R2_TRANSFER_INJECT = `extern "C" {
425
425
  void sb_r2_transfer_abort(sb_r2_transfer_ctx*);
426
426
  int sb_r2_transfer_download_open(const char*, const char*, sb_r2_transfer_ctx**);
427
427
  size_t sb_r2_transfer_download_size(sb_r2_transfer_ctx*);
428
+ const char* sb_r2_transfer_download_etag(sb_r2_transfer_ctx*);
428
429
  size_t sb_r2_transfer_download_read(sb_r2_transfer_ctx*, size_t, char*, size_t);
429
430
  void sb_r2_transfer_download_close(sb_r2_transfer_ctx*);
430
431
  }
@@ -452,22 +453,58 @@ static bool try_handle_r2_transfer(uWS::HttpResponse<false>* res, uWS::HttpReque
452
453
  std::string bucket, token;
453
454
  if (!sb_r2_transfer_path(req->getUrl(), &bucket, &token)) return false;
454
455
  // sb_r2_transfer_download_v1
456
+ // sb_r2_transfer_range_v1
457
+ // sb_r2_transfer_range_header_v2
458
+ // sb_r2_transfer_conditional_v1
459
+ // sb_r2_transfer_streaming_v2
455
460
  if (method == "GET") {
456
461
  sb_r2_transfer_ctx* download = nullptr;
457
462
  const int open_status = sb_r2_transfer_download_open(bucket.c_str(), token.c_str(), &download);
458
463
  if (open_status != 0 || !download) { respond_with_error(res, sb_r2_transfer_status(open_status), "R2 transfer unavailable", true); return true; }
459
- struct Download { sb_r2_transfer_ctx* ctx; uintmax_t size; bool closed = false; };
460
- auto state = std::make_shared<Download>(Download{download, sb_r2_transfer_download_size(download)});
464
+ const std::string etag = sb_r2_transfer_download_etag(download);
465
+ const std::string_view if_none_match = req->getHeader("if-none-match");
466
+ if (if_none_match == "*" || if_none_match == etag || (if_none_match.size() == etag.size() + 2 && if_none_match.front() == '"' && if_none_match.back() == '"' && if_none_match.substr(1, etag.size()) == etag)) {
467
+ sb_r2_transfer_download_close(download); res->writeStatus("304 Not Modified"); res->writeHeader("ETag", etag); res->end(); return true;
468
+ }
469
+ const uintmax_t full_size = sb_r2_transfer_download_size(download);
470
+ uintmax_t first = 0, last = full_size ? full_size - 1 : 0;
471
+ std::string_view range = req->getHeader("range"); if (range.empty()) range = req->getHeader("Range");
472
+ if (!range.empty()) {
473
+ if (range.substr(0, 6) != "bytes=") { sb_r2_transfer_download_close(download); respond_with_error(res, "416 Range Not Satisfiable", "invalid range", true); return true; }
474
+ const std::string_view spec = range.substr(6); const size_t dash = spec.find('-');
475
+ if (dash == std::string_view::npos || dash == 0) { sb_r2_transfer_download_close(download); respond_with_error(res, "416 Range Not Satisfiable", "invalid range", true); return true; }
476
+ first = 0; for (char c : spec.substr(0, dash)) { if (c < '0' || c > '9') { sb_r2_transfer_download_close(download); respond_with_error(res, "416 Range Not Satisfiable", "invalid range", true); return true; } first = first * 10 + (c - '0'); }
477
+ if (dash + 1 < spec.size()) { last = 0; for (char c : spec.substr(dash + 1)) { if (c < '0' || c > '9') { sb_r2_transfer_download_close(download); respond_with_error(res, "416 Range Not Satisfiable", "invalid range", true); return true; } last = last * 10 + (c - '0'); } }
478
+ if (first >= full_size || last < first) { sb_r2_transfer_download_close(download); respond_with_error(res, "416 Range Not Satisfiable", "range outside object", true); return true; }
479
+ if (last >= full_size) last = full_size - 1;
480
+ char content_range[96]; snprintf(content_range, sizeof(content_range), "bytes %llu-%llu/%llu", (unsigned long long)first, (unsigned long long)last, (unsigned long long)full_size);
481
+ res->writeStatus("206 Partial Content"); res->writeHeader("Content-Range", content_range);
482
+ }
483
+ res->writeHeader("ETag", etag); res->writeHeader("Accept-Ranges", "bytes");
484
+ struct Download { sb_r2_transfer_ctx* ctx; uintmax_t base; uintmax_t size; uintmax_t sent = 0; bool closed = false; char chunk[65536]; };
485
+ auto state = std::make_shared<Download>(Download{download, first, last - first + 1});
461
486
  auto pump = std::make_shared<std::function<bool()>>();
462
487
  *pump = [res, state, pump]() {
463
488
  if (state->closed) return false;
464
- const uintmax_t offset = res->getWriteOffset();
465
- char chunk[65536];
466
- const size_t bytes = sb_r2_transfer_download_read(state->ctx, (size_t)offset, chunk, sizeof(chunk));
467
- const auto result = res->tryEnd(std::string_view(chunk, bytes), state->size);
468
- if (result.second) { sb_r2_transfer_download_close(state->ctx); state->closed = true; return false; }
469
- if (!result.first) res->onWritable([pump](uintmax_t) { return (*pump)(); });
470
- return false;
489
+ for (;;) {
490
+ const size_t want = state->size - state->sent < sizeof(state->chunk) ? (size_t)(state->size - state->sent) : sizeof(state->chunk);
491
+ const size_t bytes = sb_r2_transfer_download_read(state->ctx, (size_t)(state->base + state->sent), state->chunk, want);
492
+ const auto result = res->tryEnd(std::string_view(state->chunk, bytes), state->size);
493
+ if (result.second || bytes == 0) { sb_r2_transfer_download_close(state->ctx); state->closed = true; return false; }
494
+ if (!result.first) {
495
+ res->onWritable([res, state](uintmax_t offset) {
496
+ if (state->closed) return true;
497
+ const size_t want = state->size - offset < sizeof(state->chunk) ? (size_t)(state->size - offset) : sizeof(state->chunk);
498
+ const size_t bytes = sb_r2_transfer_download_read(state->ctx, (size_t)(state->base + offset), state->chunk, want);
499
+ const auto resumed = res->tryEnd(std::string_view(state->chunk, bytes), state->size);
500
+ if (resumed.second || bytes == 0) { sb_r2_transfer_download_close(state->ctx); state->closed = true; return true; }
501
+ return resumed.first;
502
+ });
503
+ return false;
504
+ }
505
+ state->sent += bytes;
506
+ if (state->sent == state->size) { sb_r2_transfer_download_close(state->ctx); state->closed = true; return false; }
507
+ }
471
508
  };
472
509
  res->writeHeader("Content-Type", "application/octet-stream");
473
510
  res->onAborted([state]() { if (!state->closed) { sb_r2_transfer_download_close(state->ctx); state->closed = true; } });
@@ -503,30 +540,72 @@ const R2_TRANSFER_CALL_INJECT =
503
540
  " if (try_handle_r2_transfer(res, req, method)) return;\n" + R2_TRANSFER_CALL_ANCHOR;
504
541
  const R2_TRANSFER_CALL_MARKER = "try_handle_r2_transfer(res, req, method)";
505
542
  const R2_DOWNLOAD_CACHE_MARKER = "sb_r2_transfer_download_v1";
543
+ const R2_RANGE_CACHE_MARKER = "sb_r2_transfer_range_v1";
544
+ const R2_CONDITIONAL_CACHE_MARKER = "sb_r2_transfer_conditional_v1";
545
+ const R2_STREAMING_CACHE_MARKER = "sb_r2_transfer_streaming_v2";
546
+ const R2_RANGE_HEADER_CACHE_MARKER = "sb_r2_transfer_range_header_v2";
506
547
  const R2_DOWNLOAD_DECL_ANCHOR = " void sb_r2_transfer_abort(sb_r2_transfer_ctx*);\n}";
507
548
  const R2_DOWNLOAD_DECL_INJECT =
508
549
  " void sb_r2_transfer_abort(sb_r2_transfer_ctx*);\n" +
509
550
  " int sb_r2_transfer_download_open(const char*, const char*, sb_r2_transfer_ctx**);\n" +
510
551
  " size_t sb_r2_transfer_download_size(sb_r2_transfer_ctx*);\n" +
552
+ " const char* sb_r2_transfer_download_etag(sb_r2_transfer_ctx*);\n" +
511
553
  " size_t sb_r2_transfer_download_read(sb_r2_transfer_ctx*, size_t, char*, size_t);\n" +
512
554
  " void sb_r2_transfer_download_close(sb_r2_transfer_ctx*);\n}";
513
555
  const R2_DOWNLOAD_BRANCH_ANCHOR = ' if (method != "PUT") { respond_with_error(res, "405 Method Not Allowed", "R2 transfer requires PUT", true); return true; }';
514
556
  const R2_DOWNLOAD_BRANCH_INJECT = ` // sb_r2_transfer_download_v1
557
+ // sb_r2_transfer_range_v1
558
+ // sb_r2_transfer_range_header_v2
559
+ // sb_r2_transfer_conditional_v1
560
+ // sb_r2_transfer_streaming_v2
515
561
  if (method == "GET") {
516
562
  sb_r2_transfer_ctx* download = nullptr;
517
563
  const int status = sb_r2_transfer_download_open(bucket.c_str(), token.c_str(), &download);
518
564
  if (status != 0 || !download) { respond_with_error(res, sb_r2_transfer_status(status), "R2 transfer unavailable", true); return true; }
519
- struct Download { sb_r2_transfer_ctx* ctx; uintmax_t size; bool closed = false; };
520
- auto state = std::make_shared<Download>(Download{download, sb_r2_transfer_download_size(download)});
565
+ const std::string etag = sb_r2_transfer_download_etag(download);
566
+ const std::string_view if_none_match = req->getHeader("if-none-match");
567
+ if (if_none_match == "*" || if_none_match == etag || (if_none_match.size() == etag.size() + 2 && if_none_match.front() == '"' && if_none_match.back() == '"' && if_none_match.substr(1, etag.size()) == etag)) {
568
+ sb_r2_transfer_download_close(download); res->writeStatus("304 Not Modified"); res->writeHeader("ETag", etag); res->end(); return true;
569
+ }
570
+ const uintmax_t full_size = sb_r2_transfer_download_size(download);
571
+ uintmax_t first = 0, last = full_size ? full_size - 1 : 0;
572
+ std::string_view range = req->getHeader("range"); if (range.empty()) range = req->getHeader("Range");
573
+ if (!range.empty()) {
574
+ if (range.substr(0, 6) != "bytes=") { sb_r2_transfer_download_close(download); respond_with_error(res, "416 Range Not Satisfiable", "invalid range", true); return true; }
575
+ const std::string_view spec = range.substr(6); const size_t dash = spec.find('-');
576
+ if (dash == std::string_view::npos || dash == 0) { sb_r2_transfer_download_close(download); respond_with_error(res, "416 Range Not Satisfiable", "invalid range", true); return true; }
577
+ first = 0; for (char c : spec.substr(0, dash)) { if (c < '0' || c > '9') { sb_r2_transfer_download_close(download); respond_with_error(res, "416 Range Not Satisfiable", "invalid range", true); return true; } first = first * 10 + (c - '0'); }
578
+ if (dash + 1 < spec.size()) { last = 0; for (char c : spec.substr(dash + 1)) { if (c < '0' || c > '9') { sb_r2_transfer_download_close(download); respond_with_error(res, "416 Range Not Satisfiable", "invalid range", true); return true; } last = last * 10 + (c - '0'); } }
579
+ if (first >= full_size || last < first) { sb_r2_transfer_download_close(download); respond_with_error(res, "416 Range Not Satisfiable", "range outside object", true); return true; }
580
+ if (last >= full_size) last = full_size - 1;
581
+ char content_range[96]; snprintf(content_range, sizeof(content_range), "bytes %llu-%llu/%llu", (unsigned long long)first, (unsigned long long)last, (unsigned long long)full_size);
582
+ res->writeStatus("206 Partial Content"); res->writeHeader("Content-Range", content_range);
583
+ }
584
+ res->writeHeader("ETag", etag); res->writeHeader("Accept-Ranges", "bytes");
585
+ struct Download { sb_r2_transfer_ctx* ctx; uintmax_t base; uintmax_t size; uintmax_t sent = 0; bool closed = false; char chunk[65536]; };
586
+ auto state = std::make_shared<Download>(Download{download, first, last - first + 1});
521
587
  auto pump = std::make_shared<std::function<bool()>>();
522
588
  *pump = [res, state, pump]() {
523
589
  if (state->closed) return false;
524
- const uintmax_t offset = res->getWriteOffset(); char chunk[65536];
525
- const size_t bytes = sb_r2_transfer_download_read(state->ctx, (size_t)offset, chunk, sizeof(chunk));
526
- const auto result = res->tryEnd(std::string_view(chunk, bytes), state->size);
527
- if (result.second) { sb_r2_transfer_download_close(state->ctx); state->closed = true; return false; }
528
- if (!result.first) res->onWritable([pump](uintmax_t) { return (*pump)(); });
529
- return false;
590
+ for (;;) {
591
+ const size_t want = state->size - state->sent < sizeof(state->chunk) ? (size_t)(state->size - state->sent) : sizeof(state->chunk);
592
+ const size_t bytes = sb_r2_transfer_download_read(state->ctx, (size_t)(state->base + state->sent), state->chunk, want);
593
+ const auto result = res->tryEnd(std::string_view(state->chunk, bytes), state->size);
594
+ if (result.second || bytes == 0) { sb_r2_transfer_download_close(state->ctx); state->closed = true; return false; }
595
+ if (!result.first) {
596
+ res->onWritable([res, state](uintmax_t offset) {
597
+ if (state->closed) return true;
598
+ const size_t want = state->size - offset < sizeof(state->chunk) ? (size_t)(state->size - offset) : sizeof(state->chunk);
599
+ const size_t bytes = sb_r2_transfer_download_read(state->ctx, (size_t)(state->base + offset), state->chunk, want);
600
+ const auto resumed = res->tryEnd(std::string_view(state->chunk, bytes), state->size);
601
+ if (resumed.second || bytes == 0) { sb_r2_transfer_download_close(state->ctx); state->closed = true; return true; }
602
+ return resumed.first;
603
+ });
604
+ return false;
605
+ }
606
+ state->sent += bytes;
607
+ if (state->sent == state->size) { sb_r2_transfer_download_close(state->ctx); state->closed = true; return false; }
608
+ }
530
609
  };
531
610
  res->writeHeader("Content-Type", "application/octet-stream");
532
611
  res->onAborted([state]() { if (!state->closed) { sb_r2_transfer_download_close(state->ctx); state->closed = true; } });
@@ -585,6 +664,131 @@ export async function patchUwebsockets(root: string): Promise<void> {
585
664
  src = src.replace(R2_DOWNLOAD_BRANCH_ANCHOR, R2_DOWNLOAD_BRANCH_INJECT);
586
665
  changed = true;
587
666
  }
667
+ if (src.includes(R2_DOWNLOAD_CACHE_MARKER) && !src.includes(R2_RANGE_CACHE_MARKER)) {
668
+ const stateAnchor = " struct Download { sb_r2_transfer_ctx* ctx; uintmax_t size; bool closed = false; };\n auto state = std::make_shared<Download>(Download{download, sb_r2_transfer_download_size(download)});";
669
+ const range = ` const uintmax_t full_size = sb_r2_transfer_download_size(download);
670
+ uintmax_t first = 0, last = full_size ? full_size - 1 : 0;
671
+ const std::string_view range = req->getHeader("range");
672
+ if (!range.empty()) {
673
+ if (range.substr(0, 6) != "bytes=") { sb_r2_transfer_download_close(download); respond_with_error(res, "416 Range Not Satisfiable", "invalid range", true); return true; }
674
+ const std::string_view spec = range.substr(6); const size_t dash = spec.find('-');
675
+ if (dash == std::string_view::npos || dash == 0) { sb_r2_transfer_download_close(download); respond_with_error(res, "416 Range Not Satisfiable", "invalid range", true); return true; }
676
+ first = 0; for (char c : spec.substr(0, dash)) { if (c < '0' || c > '9') { sb_r2_transfer_download_close(download); respond_with_error(res, "416 Range Not Satisfiable", "invalid range", true); return true; } first = first * 10 + (c - '0'); }
677
+ if (dash + 1 < spec.size()) { last = 0; for (char c : spec.substr(dash + 1)) { if (c < '0' || c > '9') { sb_r2_transfer_download_close(download); respond_with_error(res, "416 Range Not Satisfiable", "invalid range", true); return true; } last = last * 10 + (c - '0'); } }
678
+ if (first >= full_size || last < first) { sb_r2_transfer_download_close(download); respond_with_error(res, "416 Range Not Satisfiable", "range outside object", true); return true; }
679
+ if (last >= full_size) last = full_size - 1;
680
+ char content_range[96]; snprintf(content_range, sizeof(content_range), "bytes %llu-%llu/%llu", (unsigned long long)first, (unsigned long long)last, (unsigned long long)full_size);
681
+ res->writeStatus("206 Partial Content"); res->writeHeader("Content-Range", content_range);
682
+ }
683
+ `;
684
+ const state = " struct Download { sb_r2_transfer_ctx* ctx; uintmax_t base; uintmax_t size; bool closed = false; };\n auto state = std::make_shared<Download>(Download{download, first, last - first + 1});";
685
+ if (!src.includes(stateAnchor)) throw new Error(`could not upgrade Porffor's direct R2 range bridge: anchor not found in ${file}.`);
686
+ src = src.replace(" // sb_r2_transfer_download_v1\n", " // sb_r2_transfer_download_v1\n // sb_r2_transfer_range_v1\n");
687
+ src = src.replace(stateAnchor, range + state);
688
+ src = src.replace("sb_r2_transfer_download_read(state->ctx, (size_t)offset, chunk, sizeof(chunk))", "sb_r2_transfer_download_read(state->ctx, (size_t)(state->base + offset), chunk, sizeof(chunk))");
689
+ changed = true;
690
+ }
691
+ if (src.includes(R2_RANGE_CACHE_MARKER) && !src.includes(R2_CONDITIONAL_CACHE_MARKER)) {
692
+ const declaration = " size_t sb_r2_transfer_download_size(sb_r2_transfer_ctx*);\n";
693
+ const declarationReplacement = declaration + " const char* sb_r2_transfer_download_etag(sb_r2_transfer_ctx*);\n";
694
+ const anchor = " const uintmax_t full_size = sb_r2_transfer_download_size(download);\n";
695
+ const inject = ` // sb_r2_transfer_conditional_v1
696
+ const std::string etag = sb_r2_transfer_download_etag(download);
697
+ res->writeHeader("ETag", etag); res->writeHeader("Accept-Ranges", "bytes");
698
+ const std::string_view if_none_match = req->getHeader("if-none-match");
699
+ if (if_none_match == "*" || if_none_match == etag || (if_none_match.size() == etag.size() + 2 && if_none_match.front() == '"' && if_none_match.back() == '"' && if_none_match.substr(1, etag.size()) == etag)) {
700
+ sb_r2_transfer_download_close(download); res->writeStatus("304 Not Modified"); res->end(); return true;
701
+ }
702
+ ` + anchor;
703
+ if (!src.includes(declaration) || !src.includes(anchor)) throw new Error(`could not upgrade Porffor's direct R2 conditional bridge: anchor not found in ${file}.`);
704
+ src = src.replace(declaration, declarationReplacement).replace(anchor, inject);
705
+ changed = true;
706
+ }
707
+ if (src.includes(R2_CONDITIONAL_CACHE_MARKER) && !src.includes(R2_STREAMING_CACHE_MARKER)) {
708
+ const oldPump = ` const uintmax_t offset = res->getWriteOffset();
709
+ char chunk[65536];
710
+ const size_t bytes = sb_r2_transfer_download_read(state->ctx, (size_t)(state->base + offset), chunk, sizeof(chunk));
711
+ const auto result = res->tryEnd(std::string_view(chunk, bytes), state->size);
712
+ if (result.second) { sb_r2_transfer_download_close(state->ctx); state->closed = true; return false; }
713
+ if (!result.first) res->onWritable([pump](uintmax_t) { return (*pump)(); });
714
+ return false;`;
715
+ const newPump = ` for (;;) {
716
+ const uintmax_t offset = res->getWriteOffset(); char chunk[65536];
717
+ const size_t bytes = sb_r2_transfer_download_read(state->ctx, (size_t)(state->base + offset), chunk, sizeof(chunk));
718
+ const auto result = res->tryEnd(std::string_view(chunk, bytes), state->size);
719
+ if (result.second) { sb_r2_transfer_download_close(state->ctx); state->closed = true; return false; }
720
+ if (!result.first) { res->onWritable([pump](uintmax_t) { return (*pump)(); }); return false; }
721
+ }`;
722
+ if (!src.includes(oldPump)) throw new Error(`could not upgrade Porffor's direct R2 streaming bridge: anchor not found in ${file}.`);
723
+ src = src.replace(" // sb_r2_transfer_conditional_v1\n", " // sb_r2_transfer_conditional_v1\n // sb_r2_transfer_streaming_v2\n").replace(oldPump, newPump);
724
+ changed = true;
725
+ }
726
+ // A short-lived v2 cache marker was written before its pump fix. Repair
727
+ // those caches as well as applying the current form to future upgrades.
728
+ if (src.includes("state->base + offset") && src.includes("uintmax_t size; bool closed = false;")) {
729
+ const oldState = "struct Download { sb_r2_transfer_ctx* ctx; uintmax_t base; uintmax_t size; bool closed = false; };";
730
+ const newState = "struct Download { sb_r2_transfer_ctx* ctx; uintmax_t base; uintmax_t size; uintmax_t sent = 0; bool closed = false; };";
731
+ const oldPump = ` const uintmax_t offset = res->getWriteOffset(); char chunk[65536];
732
+ const size_t bytes = sb_r2_transfer_download_read(state->ctx, (size_t)(state->base + offset), chunk, sizeof(chunk));
733
+ const auto result = res->tryEnd(std::string_view(chunk, bytes), state->size);
734
+ if (result.second) { sb_r2_transfer_download_close(state->ctx); state->closed = true; return false; }
735
+ if (!result.first) { res->onWritable([pump](uintmax_t) { return (*pump)(); }); return false; }
736
+ }`;
737
+ const newPump = ` char chunk[65536];
738
+ const size_t bytes = sb_r2_transfer_download_read(state->ctx, (size_t)(state->base + state->sent), chunk, sizeof(chunk));
739
+ const auto result = res->tryEnd(std::string_view(chunk, bytes), state->size);
740
+ if (result.second) { sb_r2_transfer_download_close(state->ctx); state->closed = true; return false; }
741
+ if (!result.first) { res->onWritable([pump, state](uintmax_t offset) { state->sent = offset; return (*pump)(); }); return false; }
742
+ state->sent += bytes;
743
+ }`;
744
+ if (!src.includes(oldState) || !src.includes(oldPump)) throw new Error(`could not repair Porffor's direct R2 streaming bridge: anchor not found in ${file}.`);
745
+ src = src.replace(oldState, newState).replace(oldPump, newPump);
746
+ changed = true;
747
+ }
748
+ const duplicatePump = " for (;;) {\n char chunk[65536];\n for (;;) {\n";
749
+ if (src.includes(duplicatePump)) {
750
+ src = src.replace(duplicatePump, " for (;;) {\n char chunk[65536];\n");
751
+ changed = true;
752
+ }
753
+ const unclosedPump = " state->sent += bytes;\n };\n";
754
+ if (src.includes(unclosedPump)) {
755
+ src = src.replace(unclosedPump, " state->sent += bytes;\n }\n };\n");
756
+ changed = true;
757
+ }
758
+ if (src.includes(R2_STREAMING_CACHE_MARKER) && !src.includes(R2_RANGE_HEADER_CACHE_MARKER)) {
759
+ const rangeHeader = " const std::string_view range = req->getHeader(\"range\");\n";
760
+ if (!src.includes(rangeHeader)) throw new Error(`could not upgrade Porffor's direct R2 range-header bridge: anchor not found in ${file}.`);
761
+ src = src.replace(" // sb_r2_transfer_range_v1\n", " // sb_r2_transfer_range_v1\n // sb_r2_transfer_range_header_v2\n");
762
+ src = src.replace(rangeHeader, " std::string_view range = req->getHeader(\"range\"); if (range.empty()) range = req->getHeader(\"Range\");\n");
763
+ changed = true;
764
+ }
765
+ const earlyConditionalHeaders = " res->writeHeader(\"ETag\", etag); res->writeHeader(\"Accept-Ranges\", \"bytes\");\n";
766
+ if (src.includes(earlyConditionalHeaders) && src.indexOf(earlyConditionalHeaders) < src.indexOf(" const uintmax_t full_size = sb_r2_transfer_download_size(download);")) {
767
+ const old304 = " sb_r2_transfer_download_close(download); res->writeStatus(\"304 Not Modified\"); res->end(); return true;";
768
+ const new304 = " sb_r2_transfer_download_close(download); res->writeStatus(\"304 Not Modified\"); res->writeHeader(\"ETag\", etag); res->end(); return true;";
769
+ const rangeEnd = " res->writeStatus(\"206 Partial Content\"); res->writeHeader(\"Content-Range\", content_range);\n }\n";
770
+ if (!src.includes(old304) || !src.includes(rangeEnd)) throw new Error(`could not repair Porffor's direct R2 response ordering: anchor not found in ${file}.`);
771
+ src = src.replace(earlyConditionalHeaders, "").replace(old304, new304).replace(rangeEnd, rangeEnd + " res->writeHeader(\"ETag\", etag); res->writeHeader(\"Accept-Ranges\", \"bytes\");\n");
772
+ changed = true;
773
+ }
774
+ if (src.includes("state->sent") && src.includes(R2_DOWNLOAD_CACHE_MARKER)) {
775
+ const stateStart = src.indexOf(" struct Download {", src.indexOf(R2_DOWNLOAD_CACHE_MARKER));
776
+ const stateEnd = src.indexOf(" res->writeHeader(\"Content-Type\"", stateStart);
777
+ const freshStart = R2_DOWNLOAD_BRANCH_INJECT.indexOf(" struct Download {");
778
+ const freshEnd = R2_DOWNLOAD_BRANCH_INJECT.indexOf(" res->writeHeader(\"Content-Type\"", freshStart);
779
+ if (stateStart < 0 || stateEnd < 0 || freshStart < 0 || freshEnd < 0) throw new Error(`could not replace Porffor's direct R2 stream pump: anchor not found in ${file}.`);
780
+ src = src.slice(0, stateStart) + R2_DOWNLOAD_BRANCH_INJECT.slice(freshStart, freshEnd) + src.slice(stateEnd);
781
+ changed = true;
782
+ }
783
+ if (src.includes("writable_offset") && src.includes(R2_DOWNLOAD_CACHE_MARKER)) {
784
+ const stateStart = src.indexOf(" struct Download {", src.indexOf(R2_DOWNLOAD_CACHE_MARKER));
785
+ const stateEnd = src.indexOf(" res->writeHeader(\"Content-Type\"", stateStart);
786
+ const freshStart = R2_TRANSFER_INJECT.indexOf(" struct Download {");
787
+ const freshEnd = R2_TRANSFER_INJECT.indexOf(" res->writeHeader(\"Content-Type\"", freshStart);
788
+ if (stateStart < 0 || stateEnd < 0 || freshStart < 0 || freshEnd < 0) throw new Error(`could not restore Porffor's direct R2 stream pump: anchor not found in ${file}.`);
789
+ src = src.slice(0, stateStart) + R2_TRANSFER_INJECT.slice(freshStart, freshEnd) + src.slice(stateEnd);
790
+ changed = true;
791
+ }
588
792
  for (const [marker, anchor, inject, what] of UWS_EDITS) {
589
793
  if (src.includes(marker)) continue;
590
794
  if (!src.includes(anchor)) {