@aptre/bldr-saucer 0.2.2 → 0.2.3

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/CMakeLists.txt CHANGED
@@ -34,7 +34,6 @@ add_executable(bldr-saucer
34
34
  )
35
35
 
36
36
  target_link_libraries(bldr-saucer PRIVATE saucer::saucer yamux)
37
- target_compile_features(bldr-saucer PRIVATE cxx_std_23)
38
37
 
39
38
  # Platform-specific socket libraries.
40
39
  if(WIN32)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aptre/bldr-saucer",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "Native webview bridge for Bldr using Saucer",
5
5
  "main": "index.js",
6
6
  "repository": {
@@ -33,11 +33,11 @@
33
33
  "release:publish": "git push && git push --tags"
34
34
  },
35
35
  "optionalDependencies": {
36
- "@aptre/bldr-saucer-darwin-arm64": "0.2.2",
37
- "@aptre/bldr-saucer-darwin-x64": "0.2.2",
38
- "@aptre/bldr-saucer-linux-x64": "0.2.2",
39
- "@aptre/bldr-saucer-linux-arm64": "0.2.2",
40
- "@aptre/bldr-saucer-win32-x64": "0.2.2"
36
+ "@aptre/bldr-saucer-darwin-arm64": "0.2.3",
37
+ "@aptre/bldr-saucer-darwin-x64": "0.2.3",
38
+ "@aptre/bldr-saucer-linux-x64": "0.2.3",
39
+ "@aptre/bldr-saucer-linux-arm64": "0.2.3",
40
+ "@aptre/bldr-saucer-win32-x64": "0.2.3"
41
41
  },
42
42
  "files": [
43
43
  "index.js",
package/src/main.cpp CHANGED
@@ -21,8 +21,8 @@ coco::stray start(saucer::application* app) {
21
21
  const char* init_b64 = std::getenv("BLDR_SAUCER_INIT");
22
22
  if (init_b64) {
23
23
  auto data = bldr::proto::Base64Decode(init_b64);
24
- if (!data.empty()) {
25
- bldr::proto::DecodeSaucerInit(data.data(), data.size(), saucer_init);
24
+ if (!data.empty() && !bldr::proto::DecodeSaucerInit(data.data(), data.size(), saucer_init)) {
25
+ std::cerr << "Failed to decode BLDR_SAUCER_INIT" << std::endl;
26
26
  }
27
27
  }
28
28
 
@@ -40,7 +40,7 @@ bool PipeClient::connect(const std::string& pipe_path) {
40
40
  return false;
41
41
  }
42
42
 
43
- // Set pipe mode to message mode
43
+ // Set pipe to byte read mode.
44
44
  DWORD mode = PIPE_READMODE_BYTE;
45
45
  if (!SetNamedPipeHandleState(handle_, &mode, nullptr, nullptr)) {
46
46
  std::cerr << "Failed to set pipe mode: " << GetLastError() << std::endl;
@@ -193,12 +193,20 @@ bool PipeClient::write(const uint8_t* data, size_t length) {
193
193
  }
194
194
 
195
195
  #ifdef _WIN32
196
- DWORD bytes_written = 0;
197
- if (!WriteFile(handle_, data, (DWORD)length, &bytes_written, nullptr)) {
198
- connected_ = false;
199
- return false;
196
+ size_t total_written = 0;
197
+ while (total_written < length) {
198
+ DWORD bytes_written = 0;
199
+ if (!WriteFile(handle_, data + total_written, (DWORD)(length - total_written), &bytes_written, nullptr)) {
200
+ connected_ = false;
201
+ return false;
202
+ }
203
+ if (bytes_written == 0) {
204
+ connected_ = false;
205
+ return false;
206
+ }
207
+ total_written += bytes_written;
200
208
  }
201
- return bytes_written == length;
209
+ return true;
202
210
  #else
203
211
  size_t total_written = 0;
204
212
  while (total_written < length) {
@@ -1,18 +1,33 @@
1
1
  #include "scheme_forwarder.h"
2
2
 
3
+ #include <algorithm>
4
+ #include <cctype>
3
5
  #include <cstring>
4
6
  #include <iostream>
5
7
 
6
8
  namespace bldr {
7
9
 
10
+ // toLower returns a lowercase copy of the string.
11
+ static std::string toLower(const std::string& s) {
12
+ std::string out = s;
13
+ std::transform(out.begin(), out.end(), out.begin(),
14
+ [](unsigned char c) { return std::tolower(c); });
15
+ return out;
16
+ }
17
+
18
+ // sendError sends an error response to the saucer writer.
19
+ static void sendError(saucer::scheme::stream_writer& writer, int status) {
20
+ writer.start({.mime = "text/plain", .status = status});
21
+ writer.finish();
22
+ }
23
+
8
24
  void SchemeForwarder::forward(const saucer::scheme::request& req,
9
25
  saucer::scheme::stream_writer& writer) {
10
26
  // Open a new yamux stream.
11
27
  auto [stream, err] = session_->OpenStream();
12
28
  if (err != yamux::Error::OK || !stream) {
13
29
  std::cerr << "[forwarder] failed to open yamux stream" << std::endl;
14
- writer.start({.mime = "text/plain", .status = 502});
15
- writer.finish();
30
+ sendError(writer, 502);
16
31
  return;
17
32
  }
18
33
 
@@ -35,8 +50,7 @@ void SchemeForwarder::forward(const saucer::scheme::request& req,
35
50
  if (!writeFrame(stream.get(), reqInfoMsg)) {
36
51
  std::cerr << "[forwarder] failed to write request info" << std::endl;
37
52
  stream->Close();
38
- writer.start({.mime = "text/plain", .status = 502});
39
- writer.finish();
53
+ sendError(writer, 502);
40
54
  return;
41
55
  }
42
56
 
@@ -53,8 +67,7 @@ void SchemeForwarder::forward(const saucer::scheme::request& req,
53
67
  if (!writeFrame(stream.get(), reqDataMsg)) {
54
68
  std::cerr << "[forwarder] failed to write request body" << std::endl;
55
69
  stream->Close();
56
- writer.start({.mime = "text/plain", .status = 502});
57
- writer.finish();
70
+ sendError(writer, 502);
58
71
  return;
59
72
  }
60
73
  }
@@ -67,7 +80,7 @@ void SchemeForwarder::forward(const saucer::scheme::request& req,
67
80
  std::vector<uint8_t> frame;
68
81
  if (!readFrame(stream.get(), frame)) {
69
82
  if (!started) {
70
- writer.start({.mime = "text/plain", .status = 502});
83
+ sendError(writer, 502);
71
84
  }
72
85
  break;
73
86
  }
@@ -76,7 +89,7 @@ void SchemeForwarder::forward(const saucer::scheme::request& req,
76
89
  if (!proto::DecodeFetchResponse(frame.data(), frame.size(), resp)) {
77
90
  std::cerr << "[forwarder] failed to decode response" << std::endl;
78
91
  if (!started) {
79
- writer.start({.mime = "text/plain", .status = 502});
92
+ sendError(writer, 502);
80
93
  }
81
94
  break;
82
95
  }
@@ -85,20 +98,13 @@ void SchemeForwarder::forward(const saucer::scheme::request& req,
85
98
  if (resp.has_info && !started) {
86
99
  started = true;
87
100
 
88
- // Determine MIME type from Content-Type header.
101
+ // Extract Content-Type header (case-insensitive).
89
102
  std::string mime = "application/octet-stream";
90
- auto it = resp.info.headers.find("Content-Type");
91
- if (it == resp.info.headers.end()) {
92
- it = resp.info.headers.find("content-type");
93
- }
94
- if (it != resp.info.headers.end()) {
95
- mime = it->second;
96
- }
97
-
98
- // Build response headers for saucer (excluding Content-Type which goes in mime).
99
103
  std::map<std::string, std::string> hdrs;
100
104
  for (const auto& [key, val] : resp.info.headers) {
101
- if (key != "Content-Type" && key != "content-type") {
105
+ if (toLower(key) == "content-type") {
106
+ mime = val;
107
+ } else {
102
108
  hdrs[key] = val;
103
109
  }
104
110
  }
@@ -135,7 +141,7 @@ bool SchemeForwarder::writeFrame(yamux::Stream* stream, const std::vector<uint8_
135
141
  // Write LittleEndian uint32 length prefix.
136
142
  uint8_t lenBuf[4];
137
143
  uint32_t msgLen = static_cast<uint32_t>(data.size());
138
- std::memcpy(lenBuf, &msgLen, 4); // LE on LE platforms
144
+ std::memcpy(lenBuf, &msgLen, 4); // LE on LE platforms (x86_64, ARM64)
139
145
 
140
146
  auto err = stream->Write(lenBuf, 4);
141
147
  if (err != yamux::Error::OK) return false;
@@ -155,7 +161,7 @@ bool SchemeForwarder::readFrame(yamux::Stream* stream, std::vector<uint8_t>& out
155
161
  }
156
162
 
157
163
  uint32_t msgLen;
158
- std::memcpy(&msgLen, lenBuf, 4); // LE on LE platforms
164
+ std::memcpy(&msgLen, lenBuf, 4); // LE on LE platforms (x86_64, ARM64)
159
165
 
160
166
  if (msgLen > kMaxFrameSize) return false;
161
167