iodine 0.8.1 → 0.8.2

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.
data/ext/iodine/fio-stl.h CHANGED
@@ -73,7 +73,7 @@ supports macros that will help detect and validate it's version.
73
73
  /** MINOR version: Deprecation, or significant features added. May break ABI. */
74
74
  #define FIO_VERSION_MINOR 8
75
75
  /** PATCH version: Bug fixes, minor features may be added. */
76
- #define FIO_VERSION_PATCH 0
76
+ #define FIO_VERSION_PATCH 2
77
77
  /** Build version: optional build info (string), i.e. "beta.02" */
78
78
  /* #define FIO_VERSION_BUILD */
79
79
 
@@ -2146,6 +2146,7 @@ FIO_IFUNC void fio_u2bufzu(void *buf, size_t i) { fio_u2buf32u(buf, i); }
2146
2146
  #warning \
2147
2147
  "Couldn't calculate local version for fio_buf2zu and fio_u2bufzu\n\tSIZE_T_MAX == "##SIZE_T_MAX
2148
2148
  #endif
2149
+
2149
2150
  /* *****************************************************************************
2150
2151
  Vector Math, Shuffle & Reduction on native types, for up to 2048 bits
2151
2152
  ***************************************************************************** */
@@ -5026,7 +5027,85 @@ FIO_IFUNC uint64_t fio_cycle_counter(void) {
5026
5027
  }
5027
5028
 
5028
5029
  /* *****************************************************************************
5029
- String and Buffer Information Containers + Helper Macros
5030
+ Finding first different byte
5031
+ ***************************************************************************** */
5032
+ #if FIO___DIFF_INDEX
5033
+ /**
5034
+ * Returns index of first different byte, or original length if none found.
5035
+ */
5036
+ FIO_SFUNC size_t fio___diff_index(const void *a_, const void *b_, size_t len) {
5037
+
5038
+ const uint8_t *a = a_, *b = b_;
5039
+ if (FIO_UNLIKELY(!len | (a == b)))
5040
+ return len;
5041
+ if (a[0] != b[0])
5042
+ return 0;
5043
+ if (len == 1)
5044
+ return len;
5045
+ size_t i = 0;
5046
+ while (len > 127) {
5047
+ uint64_t a1[16], b1[16], tst = 0;
5048
+ fio_memcpy128(a1, a + i);
5049
+ fio_memcpy128(b1, b + i);
5050
+ for (size_t j = 0; j < (sizeof(a1) / sizeof(a1[0])); ++j)
5051
+ tst |= (a1[j] ^ b1[j]);
5052
+ if (tst) {
5053
+ len |= 127;
5054
+ break;
5055
+ }
5056
+ i += 128;
5057
+ len -= 128;
5058
+ }
5059
+
5060
+ #define fio___diff_index_step(half) \
5061
+ do { \
5062
+ if ((len & half)) { \
5063
+ uint64_t a1[(half / 8)], b1[(half / 8)]; \
5064
+ for (size_t rounds = (len == half); 1; ++rounds) { \
5065
+ uint64_t tst = 0; \
5066
+ fio_memcpy##half(a1, a + i); \
5067
+ fio_memcpy##half(b1, b + i); \
5068
+ for (size_t j = 0; j < (sizeof(a1) / sizeof(a1[0])); ++j) { \
5069
+ a1[j] ^= b1[j]; \
5070
+ tst |= a1[j]; \
5071
+ } \
5072
+ if (tst) \
5073
+ break; \
5074
+ if (rounds) \
5075
+ return i + half; \
5076
+ i += (len & (half - 1)); \
5077
+ } \
5078
+ for (size_t j = 0; j < (sizeof(a1) / sizeof(a1[0])); ++j) \
5079
+ if (a1[j]) \
5080
+ return i + (j << 3) + \
5081
+ (fio_lsb_index_unsafe(fio_ltole64(a1[j])) >> 3); \
5082
+ return i; \
5083
+ } \
5084
+ } while (0)
5085
+
5086
+ fio___diff_index_step(64);
5087
+ fio___diff_index_step(32);
5088
+ fio___diff_index_step(16);
5089
+ fio___diff_index_step(8);
5090
+
5091
+ if ((len & 4)) {
5092
+ size_t tst = (fio_buf2u32u(a + i) == fio_buf2u32u(b + i));
5093
+ i += (tst << 2); /* should skip? */
5094
+ len |= (4 - (!tst)); /* should seek inside? */
5095
+ }
5096
+ if ((len & 2)) {
5097
+ size_t tst = (fio_buf2u16u(a + i) == fio_buf2u16u(b + i));
5098
+ i += (tst << 1); /* should skip? */
5099
+ len |= (2 - (!tst)); /* should seek inside? */
5100
+ }
5101
+
5102
+ if (len & 1)
5103
+ i += (a[i] == b[i]);
5104
+ return i;
5105
+ }
5106
+ #endif
5107
+ /* *****************************************************************************
5108
+ String and Buffer Information Containers
5030
5109
  ***************************************************************************** */
5031
5110
 
5032
5111
  /** An information type for reporting the string's state. */
@@ -5055,15 +5134,205 @@ typedef struct fio_ubuf_info_s {
5055
5134
  unsigned char *buf;
5056
5135
  } fio_ubuf_info_s;
5057
5136
 
5137
+ /* *****************************************************************************
5138
+ Case Sensitive and Insensitive Equality
5139
+ ***************************************************************************** */
5140
+
5141
+ /**
5142
+ * Returns true if equal, similar to:
5143
+ * (a.len == b.len && !memcmp(a.buf, b.buf, a.len))
5144
+ */
5145
+ FIO_SFUNC bool fio_buf_info_is_eq(const fio_buf_info_s a,
5146
+ const fio_buf_info_s b) {
5147
+ if (a.len != b.len)
5148
+ return false;
5149
+ size_t n = a.len;
5150
+ if (!n || a.buf == b.buf)
5151
+ return true;
5152
+ if (!a.buf || !b.buf)
5153
+ return false;
5154
+ const uint8_t *x = (const uint8_t *)a.buf, *y = (const uint8_t *)b.buf;
5155
+ if (x[0] != y[0])
5156
+ return false;
5157
+ if (n <= 32) {
5158
+ if (n > 24)
5159
+ return !((fio_buf2u64u(x) ^ fio_buf2u64u(y)) |
5160
+ (fio_buf2u64u(x + 8) ^ fio_buf2u64u(y + 8)) |
5161
+ (fio_buf2u64u(x + 16) ^ fio_buf2u64u(y + 16)) |
5162
+ (fio_buf2u64u(x + n - 8) ^ fio_buf2u64u(y + n - 8)));
5163
+ if (n > 16)
5164
+ return !((fio_buf2u64u(x) ^ fio_buf2u64u(y)) |
5165
+ (fio_buf2u64u(x + 8) ^ fio_buf2u64u(y + 8)) |
5166
+ (fio_buf2u64u(x + n - 8) ^ fio_buf2u64u(y + n - 8)));
5167
+ if (n >= 8)
5168
+ return !((fio_buf2u64u(x) ^ fio_buf2u64u(y)) |
5169
+ (fio_buf2u64u(x + n - 8) ^ fio_buf2u64u(y + n - 8)));
5170
+ if (n >= 4)
5171
+ return !((fio_buf2u32u(x) ^ fio_buf2u32u(y)) |
5172
+ (fio_buf2u32u(x + n - 4) ^ fio_buf2u32u(y + n - 4)));
5173
+ if (n >= 2)
5174
+ return !((fio_buf2u16u(x) ^ fio_buf2u16u(y)) | (x[n - 1] ^ y[n - 1]));
5175
+ return true;
5176
+ }
5177
+ /* test 32 byte tail */
5178
+ if (((fio_buf2u64u(x + n - 32) ^ fio_buf2u64u(y + n - 32)) |
5179
+ (fio_buf2u64u(x + n - 24) ^ fio_buf2u64u(y + n - 24)) |
5180
+ (fio_buf2u64u(x + n - 16) ^ fio_buf2u64u(y + n - 16)) |
5181
+ (fio_buf2u64u(x + n - 8) ^ fio_buf2u64u(y + n - 8))))
5182
+ return false;
5183
+ while (n >= 128) {
5184
+ uint8_t diff = 0;
5185
+ for (size_t j = 0; j < 128; ++j)
5186
+ diff |= (uint8_t)(x[j] ^ y[j]);
5187
+ if (diff)
5188
+ return false;
5189
+ x += 128;
5190
+ y += 128;
5191
+ n -= 128;
5192
+ }
5193
+ if (n > 64) {
5194
+ uint8_t diff = 0;
5195
+ for (size_t j = 0; j < 64; ++j)
5196
+ diff |= (uint8_t)(x[j] ^ y[j]);
5197
+ if (diff)
5198
+ return false;
5199
+ x += 64;
5200
+ y += 64;
5201
+ n -= 64;
5202
+ }
5203
+ if (n > 32)
5204
+ return !((fio_buf2u64u(x) ^ fio_buf2u64u(y)) |
5205
+ (fio_buf2u64u(x + 8) ^ fio_buf2u64u(y + 8)) |
5206
+ (fio_buf2u64u(x + 16) ^ fio_buf2u64u(y + 16)) |
5207
+ (fio_buf2u64u(x + 24) ^ fio_buf2u64u(y + 24)));
5208
+
5209
+ return true;
5210
+ }
5211
+
5212
+ /** An ASCII case insensitive compare for binary strings (not UTF-8). */
5213
+ FIO_SFUNC bool fio_buf_info_is_ieq(fio_buf_info_s a, fio_buf_info_s b) {
5214
+ if (a.len != b.len)
5215
+ return false;
5216
+ size_t n = a.len;
5217
+ if (!n || a.buf == b.buf)
5218
+ return true;
5219
+ const uint8_t *x = (const uint8_t *)a.buf;
5220
+ const uint8_t *y = (const uint8_t *)b.buf;
5221
+ uint8_t diff = 0;
5222
+ { /* fast path, testing first byte */
5223
+ unsigned letter = ((y[0] | 0x20U) - 'a') <= ('z' - 'a');
5224
+ if ((x[0] ^ y[0]) & ~(letter << 5))
5225
+ return false;
5226
+ }
5227
+ if (n == 1)
5228
+ return true;
5229
+ while (n >= 64) {
5230
+ for (size_t j = 0; j < 64; ++j) {
5231
+ unsigned letter = ((unsigned)(y[j] | 0x20U) - 'a') <= ('z' - 'a');
5232
+ diff |= (uint8_t)((x[j] ^ y[j]) & ~(letter << 5));
5233
+ }
5234
+ if (diff)
5235
+ return false;
5236
+ x += 64;
5237
+ y += 64;
5238
+ n -= 64;
5239
+ }
5240
+ while (n >= 16) {
5241
+ for (size_t j = 0; j < 16; ++j) {
5242
+ unsigned letter = ((unsigned)(y[j] | 0x20U) - 'a') <= ('z' - 'a');
5243
+ diff |= (uint8_t)((x[j] ^ y[j]) & ~(letter << 5));
5244
+ }
5245
+ if (diff)
5246
+ return false;
5247
+ x += 16;
5248
+ y += 16;
5249
+ n -= 16;
5250
+ }
5251
+ if (n & 8) {
5252
+ for (size_t j = 0; j < 8; ++j) {
5253
+ unsigned letter = ((unsigned)(y[j] | 0x20U) - 'a') <= ('z' - 'a');
5254
+ diff |= (uint8_t)((x[j] ^ y[j]) & ~(letter << 5));
5255
+ }
5256
+ n &= 7;
5257
+ x += n;
5258
+ y += n;
5259
+ for (size_t j = 0; j < 8; ++j) {
5260
+ unsigned letter = ((unsigned)(y[j] | 0x20U) - 'a') <= ('z' - 'a');
5261
+ diff |= (uint8_t)((x[j] ^ y[j]) & ~(letter << 5));
5262
+ }
5263
+ return !diff;
5264
+ }
5265
+ for (size_t j = 0; j < n; ++j) {
5266
+ unsigned letter = ((unsigned)(y[j] | 0x20U) - 'a') <= ('z' - 'a');
5267
+ diff |= (uint8_t)((x[j] ^ y[j]) & ~(letter << 5));
5268
+ }
5269
+ return !diff;
5270
+ }
5271
+
5272
+ /**
5273
+ * Returns true if equal, similar to:
5274
+ * (a.len == b.len && !memcmp(a.buf, b.buf, a.len))
5275
+ */
5276
+ FIO_IFUNC bool fio_ubuf_info_is_eq(const fio_ubuf_info_s a,
5277
+ const fio_ubuf_info_s b) {
5278
+ return fio_buf_info_is_eq(
5279
+ (fio_buf_info_s){.len = a.len, .buf = (char *)a.buf},
5280
+ (fio_buf_info_s){.len = b.len, .buf = (char *)b.buf});
5281
+ }
5282
+
5283
+ /** An ASCII case insensitive compare for binary strings (not UTF-8). */
5284
+ FIO_IFUNC bool fio_ubuf_info_is_ieq(const fio_ubuf_info_s a,
5285
+ const fio_ubuf_info_s b) {
5286
+ return fio_buf_info_is_ieq(
5287
+ (const fio_buf_info_s){.len = a.len, .buf = (char *)a.buf},
5288
+ (const fio_buf_info_s){.len = b.len, .buf = (char *)b.buf});
5289
+ }
5290
+
5291
+ /**
5292
+ * Returns true if equal, similar to:
5293
+ * (a.len == b.len && !memcmp(a.buf, b.buf, a.len))
5294
+ */
5295
+ FIO_IFUNC bool fio_str_info_is_eq(const fio_str_info_s a,
5296
+ const fio_str_info_s b) {
5297
+ return fio_buf_info_is_eq((const fio_buf_info_s){.len = a.len, .buf = a.buf},
5298
+ (const fio_buf_info_s){.len = b.len, .buf = b.buf});
5299
+ }
5300
+
5301
+ /** An ASCII case insensitive compare for binary strings (not UTF-8). */
5302
+ FIO_IFUNC bool fio_str_info_is_ieq(const fio_str_info_s a,
5303
+ const fio_str_info_s b) {
5304
+ return fio_buf_info_is_ieq(
5305
+ (const fio_buf_info_s){.len = a.len, .buf = a.buf},
5306
+ (const fio_buf_info_s){.len = b.len, .buf = b.buf});
5307
+ }
5308
+
5309
+ /* *****************************************************************************
5310
+ String and Buffer Information – Helper Macros
5311
+ ***************************************************************************** */
5312
+
5313
+ #ifdef FIO_MEMALT
5314
+ /** Compares two `fio_str_info_s` objects for content equality. */
5315
+ #define FIO_STR_INFO_IS_EQ(s1, s2) fio_str_info_is_eq(s1, s2)
5316
+ #else
5058
5317
  /** Compares two `fio_str_info_s` objects for content equality. */
5059
5318
  #define FIO_STR_INFO_IS_EQ(s1, s2) \
5060
5319
  ((s1).len == (s2).len && \
5061
5320
  (!(s1).len || (s1).buf == (s2).buf || \
5062
5321
  ((s1).buf && (s2).buf && (s1).buf[0] == (s2).buf[0] && \
5063
5322
  !FIO_MEMCMP((s1).buf, (s2).buf, (s1).len))))
5323
+ #endif
5064
5324
 
5325
+ #ifdef FIO_MEMALT
5326
+ /** Compares two `fio_buf_info_s` objects for content equality. */
5327
+ #define FIO_BUF_INFO_IS_EQ(s1, s2) fio_buf_info_is_eq((s1), (s2))
5065
5328
  /** Compares two `fio_buf_info_s` objects for content equality. */
5066
- #define FIO_BUF_INFO_IS_EQ(s1, s2) FIO_STR_INFO_IS_EQ((s1), (s2))
5329
+ #define FIO_UBUF_INFO_IS_EQ(s1, s2) fio_ubuf_info_is_eq((s1), (s2))
5330
+ #else
5331
+ /** Compares two `fio_buf_info_s` objects for content equality. */
5332
+ #define FIO_BUF_INFO_IS_EQ(s1, s2) FIO_STR_INFO_IS_EQ((s1), (s2))
5333
+ /** Compares two `fio_buf_info_s` objects for content equality. */
5334
+ #define FIO_UBUF_INFO_IS_EQ(s1, s2) FIO_STR_INFO_IS_EQ((s1), (s2))
5335
+ #endif
5067
5336
 
5068
5337
  /** A NULL fio_str_info_s. */
5069
5338
  #define FIO_STR_INFO0 ((fio_str_info_s){0})
@@ -9318,24 +9587,94 @@ SFUNC FIO___ASAN_AVOID size_t fio_strlen(const char *str) {
9318
9587
  fio_memcmp
9319
9588
  ***************************************************************************** */
9320
9589
 
9321
- /** Same as `memcmp`. Returns 1 if `a > b`, -1 if `a < b` and 0 if `a == b`. */
9590
+ FIO_SFUNC int fio___memcmp7x(const void *restrict a_,
9591
+ const void *restrict b_,
9592
+ size_t len) {
9593
+ unsigned r = 0;
9594
+ const uint8_t *a = a_, *b = b_;
9595
+ const size_t a4 = (len & 4), a3 = (len & 3);
9596
+ if (a4) {
9597
+ const uint64_t diff = (uint64_t)fio_buf2u32_be(a) - fio_buf2u32_be(b);
9598
+ const uint64_t ndiff = ~diff;
9599
+ r = (int)((ndiff & (ndiff + 1)) >> 63) - (int)(diff >> 63);
9600
+ }
9601
+ if (r | (!a3))
9602
+ return r;
9603
+ a += a4;
9604
+ b += a4;
9605
+ switch (a3) {
9606
+ case 0: return 0;
9607
+ case 1: return (int)((unsigned)*(uint8_t *)a - *(uint8_t *)b);
9608
+ case 2: return (int)((unsigned)fio_buf2u16_be(a) - fio_buf2u16_be(b));
9609
+ case 3: return (int)(fio_buf2u24_be(a) - fio_buf2u24_be(b)); ;
9610
+ }
9611
+ return (int)r;
9612
+ }
9613
+
9322
9614
  SFUNC int fio_memcmp(const void *a_, const void *b_, size_t len) {
9323
- if (FIO_UNLIKELY(a_ == b_ || !len))
9324
- return 0;
9325
- if (FIO_UNLIKELY(!a_))
9326
- return -1;
9327
- if (FIO_UNLIKELY(!b_))
9328
- return 1;
9329
- const uint8_t *a = (const uint8_t *)a_;
9330
- const uint8_t *b = (const uint8_t *)b_;
9331
- size_t since = 0;
9332
- #define FIO___MEMCMP_ACTION \
9333
- since += ((a[i] != b[i]) | (!!since)); /* runs inside loop */ \
9334
- if (since) /* runs outside loop */ \
9335
- return (int)1 - (int)((unsigned)(a[i - since] < b[i - since]) << 1);
9336
- FIO_FOR_UNROLL(len, 1, i, FIO___MEMCMP_ACTION);
9337
- #undef FIO___MEMCMP_ACTION
9338
- return 0;
9615
+ unsigned r = 0;
9616
+ if (!len)
9617
+ return r;
9618
+ if (a_ == b_)
9619
+ return r;
9620
+ const uint8_t *a = a_, *b = b_;
9621
+ uint64_t la, lb;
9622
+ r = *a - *b;
9623
+ if (r)
9624
+ return (int)r;
9625
+
9626
+ if (len > 255)
9627
+ while (len > 127) {
9628
+ uint64_t wa[16], wb[16], diff = 0;
9629
+ fio_memcpy128(wa, a);
9630
+ fio_memcpy128(wb, b);
9631
+ for (size_t i = 0; i < 16; ++i)
9632
+ diff |= (wa[i] ^ wb[i]);
9633
+ if (diff)
9634
+ goto stop;
9635
+ len -= 128;
9636
+ a += 128;
9637
+ b += 128;
9638
+ }
9639
+
9640
+ #define fio___memcmp_tst(bytes) \
9641
+ do \
9642
+ if ((len & bytes)) { \
9643
+ uint64_t a1[(bytes / 8)], b1[(bytes / 8)]; \
9644
+ for (size_t rounds = (len == bytes); 1; ++rounds) { \
9645
+ uint64_t tst = 0; \
9646
+ fio_memcpy##bytes(a1, a); \
9647
+ fio_memcpy##bytes(b1, b); \
9648
+ for (size_t j = 0; j < (sizeof(a1) / sizeof(a1[0])); ++j) { \
9649
+ a1[j] ^= b1[j]; \
9650
+ tst |= a1[j]; \
9651
+ } \
9652
+ if (tst) { \
9653
+ goto stop; \
9654
+ } \
9655
+ if (rounds) \
9656
+ return 0; \
9657
+ a += (len & (bytes - 1)); \
9658
+ b += (len & (bytes - 1)); \
9659
+ } \
9660
+ } \
9661
+ while (0)
9662
+
9663
+ fio___memcmp_tst(128);
9664
+ fio___memcmp_tst(64);
9665
+ fio___memcmp_tst(32);
9666
+ fio___memcmp_tst(16);
9667
+ fio___memcmp_tst(8);
9668
+ return fio___memcmp7x(a, b, len);
9669
+
9670
+ stop:
9671
+ while ((la = fio_buf2u64u(a)) == (lb = fio_buf2u64u(b))) {
9672
+ a += 8;
9673
+ b += 8;
9674
+ }
9675
+ la = fio_lton64(la);
9676
+ lb = fio_lton64(lb);
9677
+ return (int)(la > lb) - (la < lb);
9339
9678
  }
9340
9679
 
9341
9680
  /* *****************************************************************************
@@ -29695,7 +30034,7 @@ FIO_SFUNC int fio_bstr_is_greater(const char *a, const char *b) {
29695
30034
  FIO_SFUNC int fio_bstr_is_eq(const char *a_, const char *b_) {
29696
30035
  fio_buf_info_s a = fio_bstr_buf(a_);
29697
30036
  fio_buf_info_s b = fio_bstr_buf(b_);
29698
- return FIO_STR_INFO_IS_EQ(a, b);
30037
+ return FIO_BUF_INFO_IS_EQ(a, b);
29699
30038
  }
29700
30039
 
29701
30040
  /** Compares to see if fio_bstr a is equal to another String. */
@@ -54817,12 +55156,13 @@ FIO_IFUNC int fio___p256_scalar_gte_n(const fio___p256_scalar_s a) {
54817
55156
 
54818
55157
  /** Secret-safe check: returns 1 if scalar >= n (curve order). */
54819
55158
  FIO_IFUNC int fio___p256_scalar_ct_gte_n(const fio___p256_scalar_s a) {
54820
- uint64_t borrow = 0;
54821
- (void)fio_math_subc64(a[0], FIO___P256_N[0], 0, &borrow);
54822
- (void)fio_math_subc64(a[1], FIO___P256_N[1], borrow, &borrow);
54823
- (void)fio_math_subc64(a[2], FIO___P256_N[2], borrow, &borrow);
54824
- (void)fio_math_subc64(a[3], FIO___P256_N[3], borrow, &borrow);
55159
+ uint64_t borrow = 0, ignr;
55160
+ ignr = fio_math_subc64(a[0], FIO___P256_N[0], 0, &borrow);
55161
+ ignr = fio_math_subc64(a[1], FIO___P256_N[1], borrow, &borrow);
55162
+ ignr = fio_math_subc64(a[2], FIO___P256_N[2], borrow, &borrow);
55163
+ ignr = fio_math_subc64(a[3], FIO___P256_N[3], borrow, &borrow);
54825
55164
  return (int)(borrow ^ 1);
55165
+ (void)ignr;
54826
55166
  }
54827
55167
 
54828
55168
  /** Secret-safe conditional scalar subtraction: a = cond ? a - n : a. */
@@ -58997,7 +59337,7 @@ FIO_SFUNC void fio___rsa_mul_mod(uint64_t *result,
58997
59337
  FIO_SFUNC uint64_t fio___rsa_ct_lt(const uint64_t *a,
58998
59338
  const uint64_t *b,
58999
59339
  size_t word_count) {
59000
- uint64_t lt = 0;
59340
+ uint64_t lt = 0, ignr;
59001
59341
  uint64_t eq = (uint64_t)0 - 1; /* ~0 */
59002
59342
  for (size_t i = word_count; i > 0;) {
59003
59343
  --i;
@@ -59005,11 +59345,12 @@ FIO_SFUNC uint64_t fio___rsa_ct_lt(const uint64_t *a,
59005
59345
  uint64_t b_i = b[i];
59006
59346
  uint64_t diff = a_i ^ b_i;
59007
59347
  uint64_t borrow = 0;
59008
- (void)fio_math_subc64(a_i, b_i, 0, &borrow); /* borrow=1 iff a_i < b_i */
59348
+ ignr = fio_math_subc64(a_i, b_i, 0, &borrow); /* borrow=1 iff a_i < b_i */
59009
59349
  lt |= (eq & borrow);
59010
59350
  eq &= (uint64_t)0 - (diff == 0);
59011
59351
  }
59012
59352
  return lt & 1;
59353
+ (void)ignr;
59013
59354
  }
59014
59355
 
59015
59356
  /**
@@ -59037,15 +59378,15 @@ FIO_SFUNC void fio___rsa_reduce_mod(uint64_t *out,
59037
59378
  size_t high_words = full_word_count - mod_word_count;
59038
59379
  if (high_words > mod_word_count)
59039
59380
  high_words = mod_word_count;
59040
- FIO_MEMCPY(m_high, m_full + mod_word_count,
59041
- high_words * sizeof(uint64_t));
59381
+ FIO_MEMCPY(m_high, m_full + mod_word_count, high_words * sizeof(uint64_t));
59042
59382
  }
59043
59383
 
59044
59384
  /* Montgomery multiplication below expects operands in normal form (< mod).
59045
59385
  * Since mod has its top bit set for RSA primes, m_high < R < 2*mod, so one
59046
59386
  * branchless conditional subtraction is sufficient. */
59047
59387
  uint64_t m_high_sub[FIO_RSA_MAX_WORDS];
59048
- uint64_t m_high_borrow = fio_math_sub(m_high_sub, m_high, mod, mod_word_count);
59388
+ uint64_t m_high_borrow =
59389
+ fio_math_sub(m_high_sub, m_high, mod, mod_word_count);
59049
59390
  uint64_t use_m_high_sub = (uint64_t)0 - (m_high_borrow ^ 1);
59050
59391
  uint64_t use_m_high = (uint64_t)0 - m_high_borrow;
59051
59392
  for (size_t i = 0; i < mod_word_count; ++i)
@@ -59072,7 +59413,7 @@ FIO_SFUNC void fio___rsa_reduce_mod(uint64_t *out,
59072
59413
  uint64_t carry_add[FIO_RSA_MAX_WORDS];
59073
59414
  for (size_t i = 0; i < mod_word_count; ++i)
59074
59415
  carry_add[i] = R_mod_mod[i] & carry_mask;
59075
- (void)fio_math_add(out, out, carry_add, mod_word_count);
59416
+ uint64_t ignr_ = fio_math_add(out, out, carry_add, mod_word_count);
59076
59417
 
59077
59418
  /* For RSA primes R < 2*mod, so the value is < 2*mod after carry handling.
59078
59419
  * Two conditional subtractions are kept for conservative normalization. */
@@ -59092,6 +59433,7 @@ FIO_SFUNC void fio___rsa_reduce_mod(uint64_t *out,
59092
59433
  fio_secure_zero(m_high, sizeof(m_high));
59093
59434
  fio_secure_zero(m_high_sub, sizeof(m_high_sub));
59094
59435
  fio_secure_zero(carry_add, sizeof(carry_add));
59436
+ (void)ignr_;
59095
59437
  }
59096
59438
 
59097
59439
  /**
@@ -59179,11 +59521,11 @@ FIO_SFUNC void fio___rsa_mul_mod(uint64_t *result,
59179
59521
  * where R = 2^(64 * word_count).
59180
59522
  */
59181
59523
  FIO_SFUNC void fio___rsa_mont_mul(uint64_t *result,
59182
- const uint64_t *a,
59183
- const uint64_t *b,
59184
- const uint64_t *n,
59185
- const uint64_t *n_prime,
59186
- size_t word_count) {
59524
+ const uint64_t *a,
59525
+ const uint64_t *b,
59526
+ const uint64_t *n,
59527
+ const uint64_t *n_prime,
59528
+ size_t word_count) {
59187
59529
  uint64_t t[FIO_RSA_MAX_WORDS * 2];
59188
59530
  uint64_t m_full[FIO_RSA_MAX_WORDS * 2];
59189
59531
  uint64_t mn[FIO_RSA_MAX_WORDS * 2];
@@ -59221,9 +59563,9 @@ FIO_SFUNC void fio___rsa_mont_mul(uint64_t *result,
59221
59563
  * r2modn is R^2 mod n.
59222
59564
  */
59223
59565
  FIO_SFUNC void fio___rsa_mont_setup(const uint64_t *n,
59224
- size_t word_count,
59225
- uint64_t *n_prime,
59226
- uint64_t *r2modn) {
59566
+ size_t word_count,
59567
+ uint64_t *n_prime,
59568
+ uint64_t *r2modn) {
59227
59569
  uint64_t n_ext[FIO_RSA_MAX_WORDS * 2];
59228
59570
  uint64_t tmp[FIO_RSA_MAX_WORDS * 2];
59229
59571
  uint64_t prod[FIO_RSA_MAX_WORDS * 2];
@@ -59234,7 +59576,8 @@ FIO_SFUNC void fio___rsa_mont_setup(const uint64_t *n,
59234
59576
  n_prime[0] = (uint64_t)0 - n0_inv;
59235
59577
 
59236
59578
  for (int iter = 0; iter < 16; ++iter) {
59237
- /* prod = n * n_prime + 2 (Newton step for n' satisfying n*n' == -1 mod R) */
59579
+ /* prod = n * n_prime + 2 (Newton step for n' satisfying n*n' == -1 mod R)
59580
+ */
59238
59581
  fio_math_mul(prod, n, n_prime, word_count);
59239
59582
  uint64_t c = 0;
59240
59583
  prod[0] = fio_math_addc64(prod[0], 2, 0, &c);
@@ -59786,6 +60129,7 @@ FIO_SFUNC int fio___rsa_private_op_crt(uint64_t *result_words,
59786
60129
  const uint64_t *m_words,
59787
60130
  const fio_rsa_privkey_s *key,
59788
60131
  size_t word_count) {
60132
+ uint64_t ignr_ = 0;
59789
60133
  const uint8_t *n_be = key->n;
59790
60134
  const uint8_t *p_be = key->p;
59791
60135
  const uint8_t *q_be = key->q;
@@ -59811,8 +60155,8 @@ FIO_SFUNC int fio___rsa_private_op_crt(uint64_t *result_words,
59811
60155
  size_t p_word_count = (p_len + 7) / 8;
59812
60156
  size_t q_word_count = (q_len + 7) / 8;
59813
60157
 
59814
- if (!p_word_count || p_word_count > FIO_RSA_MAX_WORDS / 2 ||
59815
- !q_word_count || q_word_count > FIO_RSA_MAX_WORDS / 2)
60158
+ if (!p_word_count || p_word_count > FIO_RSA_MAX_WORDS / 2 || !q_word_count ||
60159
+ q_word_count > FIO_RSA_MAX_WORDS / 2)
59816
60160
  return -1;
59817
60161
 
59818
60162
  uint64_t n_words[FIO_RSA_MAX_WORDS];
@@ -59881,10 +60225,10 @@ FIO_SFUNC int fio___rsa_private_op_crt(uint64_t *result_words,
59881
60225
  FIO_MEMSET(q_minus_2, 0, sizeof(q_minus_2));
59882
60226
  FIO_MEMCPY(p_minus_2, p, p_word_count * sizeof(uint64_t));
59883
60227
  FIO_MEMCPY(q_minus_2, q, q_word_count * sizeof(uint64_t));
59884
- (void)fio_math_sub(p_minus_2, p_minus_2, one, p_word_count); /* p-1 */
59885
- (void)fio_math_sub(p_minus_2, p_minus_2, one, p_word_count); /* p-2 */
59886
- (void)fio_math_sub(q_minus_2, q_minus_2, one, q_word_count); /* q-1 */
59887
- (void)fio_math_sub(q_minus_2, q_minus_2, one, q_word_count); /* q-2 */
60228
+ ignr_ = fio_math_sub(p_minus_2, p_minus_2, one, p_word_count); /* p-1 */
60229
+ ignr_ = fio_math_sub(p_minus_2, p_minus_2, one, p_word_count); /* p-2 */
60230
+ ignr_ = fio_math_sub(q_minus_2, q_minus_2, one, q_word_count); /* q-1 */
60231
+ ignr_ = fio_math_sub(q_minus_2, q_minus_2, one, q_word_count); /* q-2 */
59888
60232
 
59889
60233
  uint64_t r_inv_p[FIO_RSA_MAX_WORDS];
59890
60234
  uint64_t r_inv_q[FIO_RSA_MAX_WORDS];
@@ -59904,7 +60248,7 @@ FIO_SFUNC int fio___rsa_private_op_crt(uint64_t *result_words,
59904
60248
  uint64_t use_add = (uint64_t)0 - borrow;
59905
60249
  for (size_t i = 0; i < p_word_count; ++i)
59906
60250
  p_mask[i] = p[i] & use_add;
59907
- (void)fio_math_add(diff, diff, p_mask, p_word_count);
60251
+ ignr_ = fio_math_add(diff, diff, p_mask, p_word_count);
59908
60252
  fio___rsa_mul_mod(h, qInv, diff, p, p_word_count);
59909
60253
 
59910
60254
  /* q * h mod n (zero-extend q and h to word_count) */
@@ -59920,7 +60264,7 @@ FIO_SFUNC int fio___rsa_private_op_crt(uint64_t *result_words,
59920
60264
 
59921
60265
  uint64_t qh[FIO_RSA_MAX_WORDS];
59922
60266
  fio___rsa_mul_mod(qh, q_ext, h_ext, n_words, word_count);
59923
- (void)fio_math_add(result_words, qh, s_q_ext, word_count);
60267
+ ignr_ = fio_math_add(result_words, qh, s_q_ext, word_count);
59924
60268
 
59925
60269
  /* result may be in [0, 2*n); reduce once. */
59926
60270
  uint64_t sub_n[FIO_RSA_MAX_WORDS];
@@ -59960,6 +60304,7 @@ FIO_SFUNC int fio___rsa_private_op_crt(uint64_t *result_words,
59960
60304
  fio_secure_zero(n_words, sizeof(n_words));
59961
60305
 
59962
60306
  return 0;
60307
+ (void)ignr_;
59963
60308
  }
59964
60309
 
59965
60310
  /**
@@ -60007,9 +60352,9 @@ FIO_SFUNC int fio___rsa_private_op(uint8_t *result,
60007
60352
  fio___rsa_bytes_to_words(d_words, word_count, d, d_len);
60008
60353
  fio___rsa_bytes_to_words(msg_words, word_count, message, msg_len);
60009
60354
 
60010
- int have_crt = (key->p && key->p_len && key->q && key->q_len &&
60011
- key->dP && key->dP_len && key->dQ && key->dQ_len &&
60012
- key->qInv && key->qInv_len && key->e && key->e_len);
60355
+ int have_crt = (key->p && key->p_len && key->q && key->q_len && key->dP &&
60356
+ key->dP_len && key->dQ && key->dQ_len && key->qInv &&
60357
+ key->qInv_len && key->e && key->e_len);
60013
60358
  int rc = -1;
60014
60359
 
60015
60360
  /* Verify message < modulus (constant-time). */
@@ -60022,8 +60367,11 @@ FIO_SFUNC int fio___rsa_private_op(uint8_t *result,
60022
60367
  /* No CRT parameters: fall back to the plain constant-time Montgomery
60023
60368
  * ladder. Production signing keys should supply CRT parameters so the
60024
60369
  * CRT+blinding path above is used. */
60025
- rc = fio___rsa_private_op_non_crt(
60026
- result_words, msg_words, d_words, n_words, word_count);
60370
+ rc = fio___rsa_private_op_non_crt(result_words,
60371
+ msg_words,
60372
+ d_words,
60373
+ n_words,
60374
+ word_count);
60027
60375
  }
60028
60376
 
60029
60377
  if (rc == 0)
@@ -60186,8 +60534,12 @@ SFUNC int fio_rsa_sign_pss(uint8_t *signature,
60186
60534
 
60187
60535
  /* Step 1: EMSA-PSS-ENCODE */
60188
60536
  uint8_t em[FIO_RSA_MAX_BYTES];
60189
- if (fio___rsa_emsa_pss_encode(
60190
- em, n_len, msg_hash, hash_len, hash_alg, top_mask) != 0) {
60537
+ if (fio___rsa_emsa_pss_encode(em,
60538
+ n_len,
60539
+ msg_hash,
60540
+ hash_len,
60541
+ hash_alg,
60542
+ top_mask) != 0) {
60191
60543
  return -1;
60192
60544
  }
60193
60545
 
@@ -62255,6 +62607,7 @@ no memcmp, no call) after building the value once with fio___der_oid_value.
62255
62607
  Generated by `bun ./ai-tools/oid-table.js c` - do not edit by hand.
62256
62608
  ***************************************************************************** */
62257
62609
 
62610
+ /* clang-format off */
62258
62611
  /* Signature Algorithms */
62259
62612
  #define FIO_X509_OID_SHA256_WITH_RSA \
62260
62613
  ((fio_u128){.u8 = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, [15] = 9}}) /* 1.2.840.113549.1.1.11 */
@@ -62331,6 +62684,8 @@ Generated by `bun ./ai-tools/oid-table.js c` - do not edit by hand.
62331
62684
  #define FIO_X509_OID_ORG_UNIT \
62332
62685
  ((fio_u128){.u8 = {0x55, 0x04, 0x0B, [15] = 3}}) /* 2.5.4.11 */
62333
62686
 
62687
+ /* clang-format on */
62688
+
62334
62689
  /* *****************************************************************************
62335
62690
  X.509 Parser API
62336
62691
  ***************************************************************************** */
@@ -62544,9 +62899,9 @@ typedef struct {
62544
62899
  int64_t not_before; /**< Validity start (Unix timestamp, 0 = now) */
62545
62900
  int64_t not_after; /**< Validity end (Unix timestamp, 0 = +1 year) */
62546
62901
  const fio_buf_info_s *san_dns; /**< Subject Alternative Names (DNS) */
62547
- size_t san_dns_count; /**< Number of SAN DNS entries */
62548
- int is_ca; /**< Set CA:TRUE in BasicConstraints */
62549
- uint16_t key_usage; /**< Key Usage bits (0 = default for type) */
62902
+ size_t san_dns_count; /**< Number of SAN DNS entries */
62903
+ int is_ca; /**< Set CA:TRUE in BasicConstraints */
62904
+ uint16_t key_usage; /**< Key Usage bits (0 = default for type) */
62550
62905
  } fio_x509_cert_options_s;
62551
62906
 
62552
62907
  /**
@@ -63244,9 +63599,7 @@ SFUNC int fio_x509_match_hostname(const fio_x509_cert_s *cert,
63244
63599
  cert->san_ext.len);
63245
63600
  /* Re-parse the SAN extension to iterate through all DNS names */
63246
63601
  fio_der_element_s san_seq;
63247
- if (fio_der_parse(&san_seq,
63248
- cert->san_ext.buf,
63249
- cert->san_ext.len)) {
63602
+ if (fio_der_parse(&san_seq, cert->san_ext.buf, cert->san_ext.len)) {
63250
63603
  if (fio_der_is_tag(&san_seq, FIO_DER_SEQUENCE)) {
63251
63604
  fio_der_iterator_s san_it;
63252
63605
  fio_der_element_s gn;
@@ -63497,12 +63850,12 @@ SFUNC int fio_x509_is_trusted(const fio_x509_cert_s *cert,
63497
63850
  continue;
63498
63851
 
63499
63852
  /* Compare subject DNs (the cert's issuer should match root's subject) */
63500
- if (FIO_BUF_INFO_IS_EQ(cert->issuer, root.subject)) {
63853
+ if (FIO_UBUF_INFO_IS_EQ(cert->issuer, root.subject)) {
63501
63854
  return 0; /* Found trusted root */
63502
63855
  }
63503
63856
 
63504
63857
  /* Also check if the cert itself is a trusted root */
63505
- if (FIO_BUF_INFO_IS_EQ(cert->subject, root.subject)) {
63858
+ if (FIO_UBUF_INFO_IS_EQ(cert->subject, root.subject)) {
63506
63859
  return 0; /* Cert is in trust store */
63507
63860
  }
63508
63861
  }
@@ -63533,7 +63886,7 @@ FIO_SFUNC int fio___x509_find_issuer_in_trust_store(
63533
63886
  continue;
63534
63887
 
63535
63888
  /* Check if this root's subject matches cert's issuer */
63536
- if (FIO_BUF_INFO_IS_EQ(cert->issuer, issuer->subject)) {
63889
+ if (FIO_UBUF_INFO_IS_EQ(cert->issuer, issuer->subject)) {
63537
63890
  return 0; /* Found issuer */
63538
63891
  }
63539
63892
  }
@@ -63591,7 +63944,7 @@ SFUNC int fio_x509_verify_chain(const fio_ubuf_info_s *certs,
63591
63944
  /* Verify chain signatures and issuer relationships */
63592
63945
  for (size_t i = 0; i < cert_count - 1; ++i) {
63593
63946
  /* Verify issuer DN of cert[i] matches subject DN of cert[i+1] */
63594
- if (!FIO_BUF_INFO_IS_EQ(chain[i].issuer, chain[i + 1].subject)) {
63947
+ if (!FIO_UBUF_INFO_IS_EQ(chain[i].issuer, chain[i + 1].subject)) {
63595
63948
  FIO_LOG_DEBUG("X.509 chain: issuer mismatch at position %zu", i);
63596
63949
  return FIO_X509_ERR_ISSUER_MISMATCH;
63597
63950
  }
@@ -63600,7 +63953,7 @@ SFUNC int fio_x509_verify_chain(const fio_ubuf_info_s *certs,
63600
63953
  if (!chain[i + 1].is_ca) {
63601
63954
  /* Check if it's a self-signed root (may not have BasicConstraints) */
63602
63955
  int is_self_signed =
63603
- FIO_BUF_INFO_IS_EQ(chain[i + 1].issuer, chain[i + 1].subject);
63956
+ FIO_UBUF_INFO_IS_EQ(chain[i + 1].issuer, chain[i + 1].subject);
63604
63957
  /* Allow self-signed certs even without CA flag for compatibility */
63605
63958
  if (!is_self_signed) {
63606
63959
  FIO_LOG_DEBUG("X.509 chain: certificate %zu is not a CA", i + 1);
@@ -63620,7 +63973,7 @@ SFUNC int fio_x509_verify_chain(const fio_ubuf_info_s *certs,
63620
63973
 
63621
63974
  /* Check if the last certificate is self-signed */
63622
63975
  int is_self_signed =
63623
- FIO_BUF_INFO_IS_EQ(chain[last].issuer, chain[last].subject);
63976
+ FIO_UBUF_INFO_IS_EQ(chain[last].issuer, chain[last].subject);
63624
63977
 
63625
63978
  if (is_self_signed) {
63626
63979
  /* Self-signed: verify its own signature (well-formedness check) */
@@ -63824,8 +64177,7 @@ FIO_SFUNC size_t fio___x509_encode_name(uint8_t *buf,
63824
64177
 
63825
64178
  /* Organizational Unit (OU) */
63826
64179
  if (opts->ou.len)
63827
- content_len +=
63828
- fio___x509_encode_rdn(NULL, FIO_X509_OID_ORG_UNIT, opts->ou);
64180
+ content_len += fio___x509_encode_rdn(NULL, FIO_X509_OID_ORG_UNIT, opts->ou);
63829
64181
 
63830
64182
  /* Common Name (CN) - required */
63831
64183
  content_len +=
@@ -63943,8 +64295,7 @@ FIO_SFUNC size_t fio___x509_encode_ext_basic_constraints(uint8_t *buf,
63943
64295
  int is_ca) {
63944
64296
  /* BasicConstraints ::= SEQUENCE { cA BOOLEAN DEFAULT FALSE } */
63945
64297
  size_t bc_content = is_ca ? fio_der_encode_boolean(NULL, 1) : 0;
63946
- size_t bc_len =
63947
- fio_der_encode_sequence_header(NULL, bc_content) + bc_content;
64298
+ size_t bc_len = fio_der_encode_sequence_header(NULL, bc_content) + bc_content;
63948
64299
 
63949
64300
  /* Wrap in OCTET STRING */
63950
64301
  size_t octet_len = fio_der_encode_octet_string(NULL, NULL, bc_len);
@@ -64073,8 +64424,7 @@ FIO_SFUNC size_t fio___x509_encode_ext_san(uint8_t *buf,
64073
64424
  offset += fio___der_encode_oid(buf + offset, FIO_X509_OID_SUBJECT_ALT_NAME);
64074
64425
 
64075
64426
  /* OCTET STRING containing SAN */
64076
- size_t octet_hdr =
64077
- fio_der_encode_octet_string(buf + offset, NULL, san_len);
64427
+ size_t octet_hdr = fio_der_encode_octet_string(buf + offset, NULL, san_len);
64078
64428
  uint8_t *san_buf = buf + offset + octet_hdr - san_len;
64079
64429
  size_t san_off = 0;
64080
64430
  san_off += fio_der_encode_sequence_header(san_buf + san_off, san_content);
@@ -64125,8 +64475,7 @@ FIO_SFUNC size_t fio___x509_encode_ext_eku(uint8_t *buf, int is_ca) {
64125
64475
  offset += fio___der_encode_oid(buf + offset, FIO_X509_OID_EXT_KEY_USAGE);
64126
64476
 
64127
64477
  /* OCTET STRING containing EKU SEQUENCE */
64128
- size_t octet_hdr =
64129
- fio_der_encode_octet_string(buf + offset, NULL, eku_len);
64478
+ size_t octet_hdr = fio_der_encode_octet_string(buf + offset, NULL, eku_len);
64130
64479
  uint8_t *eku_buf = buf + offset + octet_hdr - eku_len;
64131
64480
  size_t eku_off = 0;
64132
64481
  eku_off += fio_der_encode_sequence_header(eku_buf + eku_off, eku_content);
@@ -64182,8 +64531,7 @@ fio___x509_encode_extensions(uint8_t *buf,
64182
64531
  fio_der_encode_sequence_header(NULL, ext_content) + ext_content;
64183
64532
 
64184
64533
  /* Wrap in context tag [3] */
64185
- size_t total =
64186
- fio_der_encode_context_header(NULL, 3, exts_len, 1) + exts_len;
64534
+ size_t total = fio_der_encode_context_header(NULL, 3, exts_len, 1) + exts_len;
64187
64535
 
64188
64536
  if (buf) {
64189
64537
  size_t offset = 0;
@@ -64205,8 +64553,8 @@ fio___x509_encode_extensions(uint8_t *buf,
64205
64553
  }
64206
64554
 
64207
64555
  /** Helper: encode AlgorithmIdentifier for signature */
64208
- FIO_SFUNC size_t fio___x509_encode_signature_algo(uint8_t *buf,
64209
- fio_x509_keypair_type_e type) {
64556
+ FIO_SFUNC size_t
64557
+ fio___x509_encode_signature_algo(uint8_t *buf, fio_x509_keypair_type_e type) {
64210
64558
  fio_u128 oid;
64211
64559
  int has_params;
64212
64560
 
@@ -64277,7 +64625,8 @@ SFUNC size_t fio_x509_self_signed_cert(uint8_t *buf,
64277
64625
  tbs_content += serial_len;
64278
64626
 
64279
64627
  /* Signature algorithm */
64280
- size_t signature_algo_len = fio___x509_encode_signature_algo(NULL, keypair->type);
64628
+ size_t signature_algo_len =
64629
+ fio___x509_encode_signature_algo(NULL, keypair->type);
64281
64630
  tbs_content += signature_algo_len;
64282
64631
 
64283
64632
  /* Issuer (same as subject for self-signed) */
@@ -64314,7 +64663,8 @@ SFUNC size_t fio_x509_self_signed_cert(uint8_t *buf,
64314
64663
  fio_der_encode_sequence_header(NULL, tbs_content) + tbs_content;
64315
64664
 
64316
64665
  /* Signature algorithm (again, in outer Certificate) */
64317
- size_t outer_signature_algo_len = fio___x509_encode_signature_algo(NULL, keypair->type);
64666
+ size_t outer_signature_algo_len =
64667
+ fio___x509_encode_signature_algo(NULL, keypair->type);
64318
64668
 
64319
64669
  /* Signature value (BIT STRING) */
64320
64670
  size_t sig_value_len;
@@ -64357,8 +64707,7 @@ SFUNC size_t fio_x509_self_signed_cert(uint8_t *buf,
64357
64707
 
64358
64708
  /* We need to encode TBS first to sign it, but we don't know the final
64359
64709
  * certificate length yet. Encode TBS to a temporary location. */
64360
- uint8_t *tbs_start =
64361
- buf + fio_der_encode_sequence_header(NULL, cert_content);
64710
+ uint8_t *tbs_start = buf + fio_der_encode_sequence_header(NULL, cert_content);
64362
64711
 
64363
64712
  /* Encode TBSCertificate */
64364
64713
  size_t tbs_offset = 0;
@@ -108861,6 +109210,32 @@ SFUNC void fio_ipc_cluster_connect(const char *url);
108861
109210
  * */
108862
109211
  SFUNC uint16_t fio_ipc_cluster_port(void);
108863
109212
 
109213
+ /* At most 32 independent lifecycle subscriptions per process. */
109214
+ #define FIO_IPC_CLUSTER_PEER_MAX_SUBSCRIBERS 32
109215
+
109216
+ /** Lifecycle events are synthetic, reference-counted fio_ipc_s objects.
109217
+ * data[0..15] contains the peer UUID in UDP-discovery byte order. The
109218
+ * attached event owns a reference to the peer IO in event->from; the detached
109219
+ * event has from == NULL. Never reply to or send an event itself. Instead,
109220
+ * author a normal opcode message and fio_ipc_send_to(event->from, message)
109221
+ * during on_attached. Callbacks borrow each event; fio_ipc_dup retains it.
109222
+ * Retaining attached events may delay on_detached until their IO is freed.
109223
+ * udata is borrowed and must outlive all callbacks using it.
109224
+ */
109225
+ typedef struct fio_ipc_cluster_on_peer_s {
109226
+ void (*on_attached)(fio_ipc_s *event); /* optional */
109227
+ void (*on_detached)(fio_ipc_s *event); /* optional */
109228
+ void *udata; /* callback context; borrowed */
109229
+ } fio_ipc_cluster_on_peer_s;
109230
+
109231
+ /** Append a subscriber on the master before fio_io_start. At least one
109232
+ * callback is required. Returns 0 on success, -1 for invalid callbacks,
109233
+ * worker/running IO, or exhausted capacity. No partial registration occurs.
109234
+ */
109235
+ SFUNC int fio_ipc_cluster_on_peer(fio_ipc_cluster_on_peer_s args);
109236
+ #define fio_ipc_cluster_on_peer(...) \
109237
+ fio_ipc_cluster_on_peer((fio_ipc_cluster_on_peer_s){__VA_ARGS__})
109238
+
108864
109239
  /* *****************************************************************************
108865
109240
  IPC Flags - Used for message routing, settable in routing_flags
108866
109241
 
@@ -109027,6 +109402,8 @@ static struct {
109027
109402
  fio___ipc_cluster_filter_s received; /* messages recently received */
109028
109403
  fio___ipc_cluster_filter_s peers; /* connected peers */
109029
109404
  fio_u128 uuid; /* instance ID peers */
109405
+ fio_ipc_cluster_on_peer_s on_peer[FIO_IPC_CLUSTER_PEER_MAX_SUBSCRIBERS];
109406
+ size_t on_peer_count;
109030
109407
  uint16_t cluster_port; /* last port number in cluster_listen */
109031
109408
  char ipc_url[FIO_IPC_URL_MAX_LENGTH]; /* IPC socket path */
109032
109409
  } FIO___IPC;
@@ -109556,11 +109933,12 @@ typedef struct {
109556
109933
  char buffer[]; /* FIO_IPC_BUFFER_LEN for small messages */
109557
109934
  } fio___ipc_parser_s;
109558
109935
 
109559
- FIO_IFUNC fio_u128 *fio___ipc_cluster_uuid(fio_io_s *io) {
109560
- return (fio_u128 *)fio_io_buffer(io);
109936
+ /* The IO buffer need not have fio_u128's 16-byte alignment. */
109937
+ FIO_IFUNC uint8_t *fio___ipc_cluster_uuid(fio_io_s *io) {
109938
+ return (uint8_t *)fio_io_buffer(io);
109561
109939
  }
109562
109940
  FIO_IFUNC fio___ipc_parser_s *fio___ipc_cluster_parser(fio_io_s *io) {
109563
- return (fio___ipc_parser_s *)(fio___ipc_cluster_uuid(io) + 1);
109941
+ return (fio___ipc_parser_s *)(fio___ipc_cluster_uuid(io) + 16);
109564
109942
  }
109565
109943
 
109566
109944
  /** Get parser from IO buffer */
@@ -109721,30 +110099,70 @@ decrypt_error:
109721
110099
  fio___ipc_free(ipc);
109722
110100
  }
109723
110101
 
110102
+ /* Allocate a separate borrowed event per subscriber: retaining one event
110103
+ * must not change another subscriber's callback context or ownership. */
110104
+ FIO_SFUNC void fio___ipc_lifecycle_emit(fio_io_s *io,
110105
+ const fio_u128 *uuid,
110106
+ bool attached) {
110107
+ if (!fio_io_is_master())
110108
+ return;
110109
+ for (size_t i = 0; i < FIO___IPC.on_peer_count; ++i) {
110110
+ const fio_ipc_cluster_on_peer_s *sub = &FIO___IPC.on_peer[i];
110111
+ void (*fn)(fio_ipc_s *) = attached ? sub->on_attached : sub->on_detached;
110112
+ if (!fn)
110113
+ continue;
110114
+ fio_ipc_s *event =
110115
+ fio_ipc_new(.data = FIO_IPC_DATA(FIO_BUF_INFO2((char *)uuid->u8, 16)));
110116
+ if (!event) {
110117
+ FIO_LOG_ERROR("(%d) couldn't allocate IPC peer lifecycle event",
110118
+ fio_io_pid());
110119
+ continue;
110120
+ }
110121
+ event->from = attached ? fio_io_dup(io) : NULL;
110122
+ event->udata = sub->udata;
110123
+ fn(event);
110124
+ fio_ipc_free(event);
110125
+ }
110126
+ }
110127
+
110128
+ void fio_ipc_cluster_on_peer___(void); /* IDE marker */
110129
+ SFUNC int fio_ipc_cluster_on_peer FIO_NOOP(fio_ipc_cluster_on_peer_s args) {
110130
+ if (!fio_io_is_master() || fio_io_is_running() ||
110131
+ (!args.on_attached && !args.on_detached) ||
110132
+ FIO___IPC.on_peer_count >= FIO_IPC_CLUSTER_PEER_MAX_SUBSCRIBERS)
110133
+ return -1;
110134
+ FIO___IPC.on_peer[FIO___IPC.on_peer_count++] = args;
110135
+ return 0;
110136
+ }
110137
+
109724
110138
  /** Wrapper that manages request vs response states */
110139
+
109725
110140
  FIO_SFUNC void fio___ipc_on_rpc_master(void *ipc_, void *io_) {
109726
110141
  fio_ipc_s *ipc = (fio_ipc_s *)ipc_;
109727
110142
  ipc->from = io_;
109728
- fio_u128 *uuid = fio_io_buffer(io_);
110143
+ uint8_t *uuid = fio___ipc_cluster_uuid(io_);
109729
110144
  fio_u128 peer_uuid = {0};
110145
+ fio_u128 old_uuid;
110146
+ fio_memcpy16(old_uuid.u8, uuid);
109730
110147
 
109731
110148
  if (fio_ipc_decrypt(ipc))
109732
110149
  goto peer_error;
109733
- /* Handle internal ping/pong for cluster connections */
109734
- if (fio___ipc_handle_ping(ipc, fio___ipc_cluster_parser(io_)))
109735
- return;
109736
110150
  if (!FIO_IPC_FLAG_TEST(ipc, FIO_IPC_FLAG_CLUSTER) ||
109737
110151
  !FIO_IPC_FLAG_TEST(ipc, FIO_IPC_FLAG_OPCODE))
109738
110152
  goto peer_error;
109739
-
110153
+ /* Nothing, not even a ping, is dispatched before a validated handshake. */
110154
+ if (ipc->opcode == (uint32_t)0xFFFFFFFF)
110155
+ goto uuid_msg;
110156
+ if (!old_uuid.u64[0] && !old_uuid.u64[1])
110157
+ goto peer_error;
109740
110158
  if (fio___ipc_cluster_filter_window(fio_ltole64(ipc->timestamp)) ||
109741
110159
  fio___ipc_cluster_filter(&FIO___IPC.received,
109742
110160
  fio_ltole64(ipc->timestamp),
109743
110161
  ipc->id))
109744
110162
  goto filtered;
109745
-
109746
- if (ipc->opcode == (uint32_t)0xFFFFFFFF)
109747
- goto uuid_msg;
110163
+ /* Handle internal ping/pong for established cluster connections. */
110164
+ if (fio___ipc_handle_ping(ipc, fio___ipc_cluster_parser(io_)))
110165
+ return;
109748
110166
 
109749
110167
  if (FIO_IPC_FLAG_TEST(ipc, FIO_IPC_FLAG_WORKERS)) {
109750
110168
  fio_ipc_send(ipc);
@@ -109754,8 +110172,15 @@ FIO_SFUNC void fio___ipc_on_rpc_master(void *ipc_, void *io_) {
109754
110172
  return;
109755
110173
 
109756
110174
  uuid_msg:
109757
- if (uuid->u64[0] || uuid->u64[1])
109758
- goto peer_error; /* Already received UUID from this connection */
110175
+ if (old_uuid.u64[0] || old_uuid.u64[1] || ipc->len ||
110176
+ FIO_IPC_FLAG_TEST(ipc, FIO_IPC_FLAG_REPLY) ||
110177
+ FIO_IPC_FLAG_TEST(ipc, FIO_IPC_FLAG_PING))
110178
+ goto peer_error;
110179
+ if (fio___ipc_cluster_filter_window(fio_ltole64(ipc->timestamp)) ||
110180
+ fio___ipc_cluster_filter(&FIO___IPC.received,
110181
+ fio_ltole64(ipc->timestamp),
110182
+ ipc->id))
110183
+ goto filtered;
109759
110184
  if (sizeof(ipc->on_reply) >= 8) {
109760
110185
  fio_memcpy8(&peer_uuid, (char *)(void *)(&ipc->on_reply));
109761
110186
  fio_memcpy8(&peer_uuid.u8[8], (char *)(void *)(&ipc->on_done));
@@ -109763,13 +110188,18 @@ uuid_msg:
109763
110188
  fio_memcpy4(&peer_uuid, (char *)(void *)(&ipc->on_reply));
109764
110189
  fio_memcpy4(&peer_uuid.u8[4], (char *)(void *)(&ipc->on_done));
109765
110190
  }
110191
+ /* Reject self, zero and duplicate identities before announcing this peer. */
110192
+ if (!peer_uuid.u64[0] || !peer_uuid.u64[1] ||
110193
+ FIO_MEMCMP(peer_uuid.u8, FIO___IPC.uuid.u8, 16) == 0)
110194
+ goto peer_error;
109766
110195
  /* test if we already connected to peer previously */
109767
110196
  if (fio___ipc_cluster_filter(&FIO___IPC.peers,
109768
110197
  peer_uuid.u64[0],
109769
110198
  peer_uuid.u64[1]))
109770
110199
  goto peer_error;
109771
110200
  /* set peer uuid */
109772
- *uuid = peer_uuid;
110201
+ fio_memcpy16(uuid, peer_uuid.u8);
110202
+ fio___ipc_lifecycle_emit(io_, &peer_uuid, true);
109773
110203
  fio___ipc_free(ipc);
109774
110204
  return;
109775
110205
  peer_error:
@@ -110101,12 +110531,12 @@ FIO_SFUNC void fio___ipc_udp_broadcast_task_done(void *io_, void *ignr_) {
110101
110531
  FIO_SFUNC void fio___ipc_udp_on_attach(fio_io_s *io) {
110102
110532
  /* Send initial broadcast */
110103
110533
  fio___ipc_udp_broadcast_hello(io);
110104
- /* Schedule periodic broadcasts (every 1-2 seconds with jitter) */
110534
+ /* Schedule periodic broadcasts (every 4-5 seconds with jitter) */
110105
110535
  fio_io_run_every(.fn = fio___ipc_udp_broadcast_task,
110106
110536
  .udata1 = fio_io_dup(io),
110107
- .every = (uint32_t)(2048 | (1023 & FIO___IPC.uuid.u64[0])),
110537
+ .every = (uint32_t)(4096 | (1023 & FIO___IPC.uuid.u64[0])),
110108
110538
  .on_finish = fio___ipc_udp_broadcast_task_done,
110109
- .repetitions = 0); /* Repeat indefinitely */
110539
+ .repetitions = -1); /* Repeat indefinitely */
110110
110540
  }
110111
110541
 
110112
110542
  /** Called when UDP socket is closed */
@@ -110247,7 +110677,7 @@ FIO_ASSERT_STATIC((sizeof(void (*)(void *)) >= 4),
110247
110677
  "function pointers MUST be 4 bytes or more");
110248
110678
  SFUNC void fio___ipc_on_attach_cluster(fio_io_s *io) {
110249
110679
  /* set peer UUID to zero and initialize parser */
110250
- *fio___ipc_cluster_uuid(io) = fio_u128_init64(0, 0);
110680
+ FIO_MEMSET(fio___ipc_cluster_uuid(io), 0, 16);
110251
110681
  fio___ipc_parser_init(fio___ipc_cluster_parser(io));
110252
110682
  /* inform peer about our UUID */
110253
110683
  fio_ipc_s *ipc = fio_ipc_new(0);
@@ -110268,13 +110698,16 @@ SFUNC void fio___ipc_on_attach_cluster(fio_io_s *io) {
110268
110698
 
110269
110699
  /** Called when IPC socket is closed */
110270
110700
  FIO_SFUNC void fio___ipc_on_close_cluster(void *buffer, void *udata) {
110271
- fio___ipc_parser_s *p =
110272
- (fio___ipc_parser_s *)((char *)buffer + sizeof(fio_u128));
110701
+ fio___ipc_parser_s *p = (fio___ipc_parser_s *)((char *)buffer + 16);
110273
110702
  fio___ipc_parser_destroy(p);
110274
- fio___ipc_cluster_filter_remove(
110275
- &FIO___IPC.peers,
110276
- (fio___ipc_msg_id_s){fio_buf2u64u(buffer),
110277
- fio_buf2u64u(((char *)buffer + sizeof(uint64_t)))});
110703
+ fio_u128 uuid;
110704
+ fio_memcpy16(uuid.u8, buffer);
110705
+ if (fio_io_is_master() && uuid.u64[0] && uuid.u64[1]) {
110706
+ fio___ipc_cluster_filter_remove(
110707
+ &FIO___IPC.peers,
110708
+ (fio___ipc_msg_id_s){uuid.u64[0], uuid.u64[1]});
110709
+ fio___ipc_lifecycle_emit(NULL, &uuid, false);
110710
+ }
110278
110711
  (void)udata;
110279
110712
  }
110280
110713
 
@@ -110374,6 +110807,8 @@ FIO_SFUNC void fio___ipc_destroy(void *ignr_) {
110374
110807
  fio___ipc_cluster_filter_destroy(&FIO___IPC.received);
110375
110808
  fio___ipc_cluster_filter_destroy(&FIO___IPC.peers);
110376
110809
  fio___ipc_cluster_ops_destroy(&FIO___IPC.opcodes);
110810
+ FIO_MEMSET(FIO___IPC.on_peer, 0, sizeof(FIO___IPC.on_peer));
110811
+ FIO___IPC.on_peer_count = 0;
110377
110812
  (void)ignr_;
110378
110813
  }
110379
110814
 
@@ -110383,6 +110818,9 @@ FIO_SFUNC void fio___ipc_on_fork(void *ignr_) {
110383
110818
  /* Cleanup master's resources - except opcodes (clients may use) */
110384
110819
  fio___ipc_cluster_filter_destroy(&FIO___IPC.received);
110385
110820
  fio___ipc_cluster_filter_destroy(&FIO___IPC.peers);
110821
+ /* Child never owns master's lifecycle subscriptions or their udata. */
110822
+ FIO_MEMSET(FIO___IPC.on_peer, 0, sizeof(FIO___IPC.on_peer));
110823
+ FIO___IPC.on_peer_count = 0;
110386
110824
 
110387
110825
  FIO___IPC.protocol_ipc.on_data = fio___ipc_on_data_worker;
110388
110826
  FIO___IPC.protocol_ipc.on_shutdown = fio___ipc_on_shutdown_worker;
@@ -110419,13 +110857,14 @@ FIO_CONSTRUCTOR(fio___ipc_init) {
110419
110857
  .on_data = fio___ipc_on_data_cluster,
110420
110858
  .on_close = fio___ipc_on_close_cluster,
110421
110859
  .on_timeout = fio___ipc_on_timeout_rpc,
110422
- .buffer_size =
110423
- sizeof(fio_u128) + sizeof(fio___ipc_parser_s) + FIO_IPC_BUFFER_LEN,
110860
+ .buffer_size = 16 + sizeof(fio___ipc_parser_s) + FIO_IPC_BUFFER_LEN,
110424
110861
  .timeout = (55 * 1024), /* RPC (remote) timeout: ~55 sec */
110425
110862
  };
110426
110863
  fio_io_protocol_set(NULL, &FIO___IPC.protocol_ipc); /* initialize - safety */
110427
110864
  fio_io_protocol_set(NULL, &FIO___IPC.protocol_rpc); /* initialize - safety */
110428
- FIO___IPC.uuid = fio_u128_init64(fio_rand64(), fio_rand64());
110865
+ do {
110866
+ FIO___IPC.uuid = fio_rand128();
110867
+ } while (!FIO___IPC.uuid.u64[0] || !FIO___IPC.uuid.u64[1]);
110429
110868
  fio_ipc_url_set(NULL);
110430
110869
  fio_state_callback_add(FIO_CALL_BEFORE_FORK, fio___ipc_listen, NULL);
110431
110870
  fio_state_callback_add(FIO_CALL_IN_CHILD, fio___ipc_on_fork, NULL);
@@ -110784,7 +111223,7 @@ static X509 *fio_io_tls_create_self_signed(const char *server_name) {
110784
111223
  }
110785
111224
 
110786
111225
  /* Set subject name with Organization and Common Name */
110787
- name = X509_get_subject_name(cert);
111226
+ name = (X509_NAME *)X509_get_subject_name(cert);
110788
111227
  if (!name) {
110789
111228
  FIO_LOG_ERROR("OpenSSL: X509_get_subject_name failed");
110790
111229
  goto error;
@@ -118851,6 +119290,7 @@ HTTP Handle Settings
118851
119290
  #endif
118852
119291
 
118853
119292
  #ifndef FIO_HTTP_LOG_X_REQUEST_START
119293
+ /** Logs request wait time using x-request-start header */
118854
119294
  #define FIO_HTTP_LOG_X_REQUEST_START 1
118855
119295
  #endif
118856
119296
 
@@ -119041,11 +119481,12 @@ typedef struct fio_http_settings_s {
119041
119481
  * recommended.
119042
119482
  *
119043
119483
  * Note: per-route (read from the matching route's settings; routes
119044
- * inherit the listener's root value at route-creation). The value is a
119045
- * failure-memoization shift register, atomically shared by the IO
119046
- * threads - see `fio_http_static_file_response`. Detached handles (no
119047
- * settings) gate on the `FIO_HTTP_CFLAG_COMPRESS_STATIC` handle cflag
119048
- * instead, with no memoization state.
119484
+ * inherit the listener's root value at route-creation). Handles without
119485
+ * settings (created with `fio_http_new`) never create variants.
119486
+ *
119487
+ * Note: on-demand creation disables itself (the value drops to 0) after
119488
+ * repeated failures or a filesystem-full / permission error, until the
119489
+ * settings are re-applied.
119049
119490
  */
119050
119491
  uint8_t compress_static;
119051
119492
  /**
@@ -119294,7 +119735,7 @@ FIO_IFUNC void *fio_http_udata2_set(fio_http_s *, void *);
119294
119735
  /** Gets the HTTP Controller associated with the HTTP handle. */
119295
119736
  FIO_IFUNC fio_http_controller_s *fio_http_controller(fio_http_s *h);
119296
119737
 
119297
- /** Gets the HTTP Controller associated with the HTTP handle. */
119738
+ /** Sets the HTTP Controller associated with the HTTP handle. */
119298
119739
  FIO_IFUNC fio_http_controller_s *fio_http_controller_set(
119299
119740
  fio_http_s *h,
119300
119741
  fio_http_controller_s *controller);
@@ -119318,6 +119759,43 @@ SFUNC size_t fio_http_status_set(fio_http_s *, size_t status);
119318
119759
  /** Gets the method information associated with the HTTP handle. */
119319
119760
  SFUNC fio_str_info_s fio_http_method(fio_http_s *);
119320
119761
 
119762
+ /** Tests for GET, case-insensitively; requires a non-NULL HTTP handle. */
119763
+ SFUNC int fio_http_method_is_get(fio_http_s *h);
119764
+ /** Tests for HEAD, case-insensitively; requires a non-NULL HTTP handle. */
119765
+ SFUNC int fio_http_method_is_head(fio_http_s *h);
119766
+ /** Tests for POST, case-insensitively; requires a non-NULL HTTP handle. */
119767
+ SFUNC int fio_http_method_is_post(fio_http_s *h);
119768
+ /** Tests for PUT, case-insensitively; requires a non-NULL HTTP handle. */
119769
+ SFUNC int fio_http_method_is_put(fio_http_s *h);
119770
+ /** Tests for DELETE, case-insensitively; requires a non-NULL HTTP handle. */
119771
+ SFUNC int fio_http_method_is_delete(fio_http_s *h);
119772
+ /** Tests for CONNECT, case-insensitively; requires a non-NULL HTTP handle. */
119773
+ SFUNC int fio_http_method_is_connect(fio_http_s *h);
119774
+ /** Tests for OPTIONS, case-insensitively; requires a non-NULL HTTP handle. */
119775
+ SFUNC int fio_http_method_is_options(fio_http_s *h);
119776
+ /** Tests for TRACE, case-insensitively; requires a non-NULL HTTP handle. */
119777
+ SFUNC int fio_http_method_is_trace(fio_http_s *h);
119778
+ /** Tests for PATCH, case-insensitively; requires a non-NULL HTTP handle. */
119779
+ SFUNC int fio_http_method_is_patch(fio_http_s *h);
119780
+ /** Tests for QUERY, case-insensitively; requires a non-NULL HTTP handle. */
119781
+ SFUNC int fio_http_method_is_query(fio_http_s *h);
119782
+ /** Tests for PROPFIND, case-insensitively; requires a non-NULL HTTP handle. */
119783
+ SFUNC int fio_http_method_is_propfind(fio_http_s *h);
119784
+ /** Tests for PROPPATCH, case-insensitively; requires a non-NULL HTTP handle. */
119785
+ SFUNC int fio_http_method_is_proppatch(fio_http_s *h);
119786
+ /** Tests for MKCOL, case-insensitively; requires a non-NULL HTTP handle. */
119787
+ SFUNC int fio_http_method_is_mkcol(fio_http_s *h);
119788
+ /** Tests for COPY, case-insensitively; requires a non-NULL HTTP handle. */
119789
+ SFUNC int fio_http_method_is_copy(fio_http_s *h);
119790
+ /** Tests for MOVE, case-insensitively; requires a non-NULL HTTP handle. */
119791
+ SFUNC int fio_http_method_is_move(fio_http_s *h);
119792
+ /** Tests for LOCK, case-insensitively; requires a non-NULL HTTP handle. */
119793
+ SFUNC int fio_http_method_is_lock(fio_http_s *h);
119794
+ /** Tests for UNLOCK, case-insensitively; requires a non-NULL HTTP handle. */
119795
+ SFUNC int fio_http_method_is_unlock(fio_http_s *h);
119796
+ /** Tests for SEARCH, case-insensitively; requires a non-NULL HTTP handle. */
119797
+ SFUNC int fio_http_method_is_search(fio_http_s *h);
119798
+
119321
119799
  /** Sets the method information associated with the HTTP handle. */
119322
119800
  SFUNC fio_str_info_s fio_http_method_set(fio_http_s *, fio_str_info_s);
119323
119801
 
@@ -119908,9 +120386,8 @@ SFUNC int fio_http_etag_is_match(fio_http_s *h);
119908
120386
  *
119909
120387
  * Pre-compressed variants (`file.br`, `file.zstd`, `file.gz`, `file.zip`,
119910
120388
  * in this preference order) are served when accepted by the client,
119911
- * present on disk, and fresh; with `compress_static` enabled (the matching
119912
- * route's settings, or the `FIO_HTTP_CFLAG_COMPRESS_STATIC` cflag on
119913
- * detached handles), missing `.br` / `.gz` variants are also created on
120389
+ * present on disk, and fresh; with `compress_static` enabled in the matching
120390
+ * route's settings, missing `.br` / `.gz` variants are also created on
119914
120391
  * demand.
119915
120392
  *
119916
120393
  * On success the response is complete and 0 is returned. On failure -1 is
@@ -119952,7 +120429,7 @@ The HTTP Controller
119952
120429
  * order for HTTP responses and requests to be sent.
119953
120430
  */
119954
120431
  struct fio_http_controller_s {
119955
- /* MUST be initialized to zero, used internally by the HTTP Handle. */
120432
+ /** Reserved. MUST be initialized to zero. */
119956
120433
  uintptr_t private_flags;
119957
120434
  /** Called when an HTTP handle is freed. */
119958
120435
  void (*on_destroyed)(fio_http_s *h);
@@ -119996,23 +120473,6 @@ SFUNC void fio_http_upgrade_sse(fio_http_s *);
119996
120473
  /** Sets request data to request an EventSource (SSE) Upgrade.*/
119997
120474
  SFUNC void fio_http_sse_set_request(fio_http_s *);
119998
120475
 
119999
- /* *****************************************************************************
120000
- HTTP Handle State and Controller Flags
120001
- ***************************************************************************** */
120002
-
120003
- #define FIO_HTTP_STATE_STREAMING 1
120004
- #define FIO_HTTP_STATE_FINISHED 2
120005
- #define FIO_HTTP_STATE_UPGRADED 4
120006
- #define FIO_HTTP_STATE_WEBSOCKET 8
120007
- #define FIO_HTTP_STATE_SSE 16
120008
- #define FIO_HTTP_STATE_COOKIES_PARSED 32
120009
- #define FIO_HTTP_STATE_FREEING 64
120010
-
120011
- /** Controller flags (cflags) for opt-in compression features. */
120012
- #define FIO_HTTP_CFLAG_COMPRESS_DYNAMIC 1
120013
- #define FIO_HTTP_CFLAG_COMPRESS_WS 2
120014
- #define FIO_HTTP_CFLAG_COMPRESS_STATIC 4
120015
-
120016
120476
  /* *****************************************************************************
120017
120477
  WebSocket Helpers - HTTP Upgraded Connections
120018
120478
  ***************************************************************************** */
@@ -120072,6 +120532,24 @@ HTTP Settings Resolver
120072
120532
  SFUNC fio_http_settings_s *fio_http_settings(fio_http_s *);
120073
120533
 
120074
120534
  /* *****************************************************************************
120535
+
120536
+
120537
+
120538
+
120539
+
120540
+
120541
+
120542
+ Inline / Macro Implementations
120543
+
120544
+
120545
+
120546
+
120547
+
120548
+
120549
+
120550
+ ***************************************************************************** */
120551
+
120552
+ /* *****************************************************************************
120075
120553
  Header Value / Property Iterator - Inline Implementation
120076
120554
  ***************************************************************************** */
120077
120555
 
@@ -120239,47 +120717,16 @@ fio_http_header_each_property_first(const fio_buf_info_s *properties) {
120239
120717
  return pos;
120240
120718
  }
120241
120719
 
120242
- /* *****************************************************************************
120243
- HTTP API Finish
120244
- ***************************************************************************** */
120245
- #endif /* FIO_HTTP */
120246
- /* ************************************************************************* */
120247
- #if !defined(FIO_INCLUDE_FILE) /* Dev test - ignore line */
120248
- #define FIO___DEV___ /* Development inclusion - ignore line */
120249
- #define FIO_HTTP /* Development inclusion - ignore line */
120250
- #include "./include.h" /* Development inclusion - ignore line */
120251
- #endif /* Development inclusion - ignore line */
120252
- /* *****************************************************************************
120253
-
120254
-
120255
-
120256
-
120257
- HTTP Types - Internal Types, Handle and Core Implementation
120258
-
120259
- See also:
120260
- https://www.rfc-editor.org/rfc/rfc9110.html
120261
-
120262
-
120263
-
120264
- Copyright and License: see header file (000 copyright.h) or top of file
120265
- ***************************************************************************** */
120266
- #if defined(FIO_HTTP) && !defined(FIO___RECURSIVE_INCLUDE) && \
120267
- !defined(H___FIO_HTTP_TYPES___H) && \
120268
- (defined(FIO_EXTERN_COMPLETE) || !defined(FIO_EXTERN))
120269
- #define H___FIO_HTTP_TYPES___H
120270
-
120271
120720
  /* *****************************************************************************
120272
120721
  HTTP Handle Implementation - inlined static functions
120273
120722
  ***************************************************************************** */
120274
120723
 
120275
120724
  #define FIO___HTTP_GETSET_PTR(type, name, index_, pre_set_code) \
120276
- /** Used internally to set / get the propecrty at its known pointer index. \
120277
- */ \
120725
+ /** Get the name property at its known pointer index. */ \
120278
120726
  FIO_IFUNC type *fio_http_##name(fio_http_s *h) { \
120279
120727
  return ((type **)h)[index_]; \
120280
120728
  } \
120281
- /** Used internally to set / get the propercty at its known pointer index. \
120282
- */ \
120729
+ /** Set the name property at its known pointer index. */ \
120283
120730
  FIO_IFUNC type *fio_http_##name##_set(fio_http_s *h, type *ptr) { \
120284
120731
  pre_set_code; \
120285
120732
  return (((type **)h)[index_] = ptr); \
@@ -120288,28 +120735,19 @@ HTTP Handle Implementation - inlined static functions
120288
120735
  SFUNC fio_http_controller_s *fio___http_controller_validate(
120289
120736
  fio_http_controller_s *c);
120290
120737
 
120291
- /* Create fio_http_udata_(get|set) functions */
120738
+ /** fio_http_udata / fio_http_udata_set */
120292
120739
  FIO___HTTP_GETSET_PTR(void, udata, 0, (void)0)
120293
- /* Create fio_http_pdata_(get|set) functions */
120740
+ /** fio_http_udata2 / fio_http_udata2_set */
120294
120741
  FIO___HTTP_GETSET_PTR(void, udata2, 1, (void)0)
120295
- /* Create fio_http_cdata_(get|set) functions */
120742
+ /** fio_http_cdata / fio_http_cdata_set */
120296
120743
  FIO___HTTP_GETSET_PTR(void, cdata, 2, (void)0)
120297
- /* Create fio_http_controller_(get|set) functions */
120744
+ /** fio_http_controller / fio_http_controller_set */
120298
120745
  FIO___HTTP_GETSET_PTR(fio_http_controller_s,
120299
120746
  controller,
120300
120747
  3,
120301
120748
  ptr = fio___http_controller_validate(ptr))
120302
120749
 
120303
120750
  #undef FIO___HTTP_GETSET_PTR
120304
- /*
120305
- REMEMBER:
120306
- ========
120307
-
120308
- All memory allocations should use:
120309
- * FIO_MEM_REALLOC_(ptr, old_size, new_size, copy_len)
120310
- * FIO_MEM_FREE_(ptr, size)
120311
-
120312
- */
120313
120751
 
120314
120752
  /* *****************************************************************************
120315
120753
  Path Section Looping
@@ -120435,6 +120873,35 @@ FIO_IFUNC fio_http_resource_action_e fio_http_resource_action(fio_http_s *h) {
120435
120873
  return r;
120436
120874
  }
120437
120875
 
120876
+ /* *****************************************************************************
120877
+ HTTP API Finish
120878
+ ***************************************************************************** */
120879
+ #endif /* FIO_HTTP */
120880
+ /* ************************************************************************* */
120881
+ #if !defined(FIO_INCLUDE_FILE) /* Dev test - ignore line */
120882
+ #define FIO___DEV___ /* Development inclusion - ignore line */
120883
+ #define FIO_HTTP /* Development inclusion - ignore line */
120884
+ #include "./include.h" /* Development inclusion - ignore line */
120885
+ #endif /* Development inclusion - ignore line */
120886
+ /* *****************************************************************************
120887
+
120888
+
120889
+
120890
+
120891
+ HTTP Types - Internal Types, Handle and Core Implementation
120892
+
120893
+ See also:
120894
+ https://www.rfc-editor.org/rfc/rfc9110.html
120895
+
120896
+
120897
+
120898
+ Copyright and License: see header file (000 copyright.h) or top of file
120899
+ ***************************************************************************** */
120900
+ #if defined(FIO_HTTP) && !defined(FIO___RECURSIVE_INCLUDE) && \
120901
+ !defined(H___FIO_HTTP_TYPES___H) && \
120902
+ (defined(FIO_EXTERN_COMPLETE) || !defined(FIO_EXTERN))
120903
+ #define H___FIO_HTTP_TYPES___H
120904
+
120438
120905
  /*
120439
120906
  REMEMBER:
120440
120907
  ========
@@ -120445,6 +120912,23 @@ All memory allocations should use:
120445
120912
 
120446
120913
  */
120447
120914
 
120915
+ /* *****************************************************************************
120916
+ HTTP Handle State and Controller Flags
120917
+ ***************************************************************************** */
120918
+
120919
+ #define FIO___HTTP_STATE_STREAMING 1
120920
+ #define FIO___HTTP_STATE_FINISHED 2
120921
+ #define FIO___HTTP_STATE_UPGRADED 4
120922
+ #define FIO___HTTP_STATE_WEBSOCKET 8
120923
+ #define FIO___HTTP_STATE_SSE 16
120924
+ #define FIO___HTTP_STATE_COOKIES_PARSED 32
120925
+ #define FIO___HTTP_STATE_FREEING 64
120926
+
120927
+ /** Controller flags (cflags) for opt-in compression features. */
120928
+ #define FIO___HTTP_CFLAG_COMPRESS_DYNAMIC 1
120929
+ #define FIO___HTTP_CFLAG_COMPRESS_WS 2
120930
+ #define FIO___HTTP_CFLAG_COMPRESS_STATIC 4
120931
+
120448
120932
  /* *****************************************************************************
120449
120933
  HTTP Settings Validation
120450
120934
  ***************************************************************************** */
@@ -121550,10 +122034,9 @@ struct fio_http_s {
121550
122034
  int (*writer)(fio_http_s *, fio_http_write_args_s *);
121551
122035
  int64_t received_at;
121552
122036
  size_t sent;
122037
+ uint32_t cflags;
121553
122038
  uint16_t state;
121554
122039
  uint16_t status;
121555
- uint16_t cflags;
121556
- uint16_t uflags;
121557
122040
  fio_keystr_s method;
121558
122041
  fio_keystr_s opath;
121559
122042
  fio_keystr_s path;
@@ -121582,7 +122065,7 @@ struct fio_http_s {
121582
122065
  SFUNC fio_http_s *fio_http_destroy(fio_http_s *h) {
121583
122066
  if (!h)
121584
122067
  return h;
121585
- h->state |= FIO_HTTP_STATE_FREEING;
122068
+ h->state |= FIO___HTTP_STATE_FREEING;
121586
122069
  h->controller->on_destroyed(h);
121587
122070
 
121588
122071
  fio_keystr_destroy(&h->method, fio___http_keystr_free);
@@ -121676,12 +122159,16 @@ Simple Property Set / Get
121676
122159
  #define FIO___HTTP_MAKE_GET_SET(property) \
121677
122160
  SFUNC fio_str_info_s fio_http_##property(fio_http_s *h) { \
121678
122161
  FIO_ASSERT_DEBUG(h, "NULL HTTP handler!"); \
122162
+ if (!h) \
122163
+ return FIO_STR_INFO0; \
121679
122164
  return fio_keystr_info(&h->property); \
121680
122165
  } \
121681
122166
  \
121682
122167
  SFUNC fio_str_info_s fio_http_##property##_set(fio_http_s *h, \
121683
122168
  fio_str_info_s value) { \
121684
122169
  FIO_ASSERT_DEBUG(h, "NULL HTTP handler!"); \
122170
+ if (!h) \
122171
+ return FIO_STR_INFO0; \
121685
122172
  fio_keystr_s old = h->property; /* delay destroy in case of copy/edit. */ \
121686
122173
  h->property = fio_keystr_init(value, fio___http_keystr_alloc); \
121687
122174
  fio_keystr_destroy(&old, fio___http_keystr_free); \
@@ -121717,32 +122204,43 @@ Controller / User Flags Set / Test / Flip
121717
122204
 
121718
122205
  #define FIO___HTTP_MAKE_GET_SET(flags) \
121719
122206
  /** Returns all set flags */ \
121720
- FIO_IFUNC uint16_t fio_http_##flags(fio_http_s *h) { \
122207
+ FIO_IFUNC uint16_t fio___http_##flags(fio_http_s *h) { \
121721
122208
  FIO_ASSERT_DEBUG(h, "NULL HTTP handler!"); \
121722
122209
  return h->flags; \
121723
122210
  } \
121724
- FIO_IFUNC uint16_t fio_http_##flags##_flip(fio_http_s *h, uint16_t flg) { \
122211
+ FIO_IFUNC uint16_t fio___http_##flags##_flip(fio_http_s *h, uint16_t flg) { \
121725
122212
  FIO_ASSERT_DEBUG(h, "NULL HTTP handler!"); \
121726
122213
  h->flags ^= flg; \
121727
122214
  return h->flags & flg; \
121728
122215
  } \
121729
- FIO_IFUNC uint16_t fio_http_##flags##_set(fio_http_s *h, uint16_t flg) { \
122216
+ FIO_IFUNC uint16_t fio___http_##flags##_set(fio_http_s *h, uint16_t flg) { \
121730
122217
  FIO_ASSERT_DEBUG(h, "NULL HTTP handler!"); \
121731
122218
  h->flags |= flg; \
121732
122219
  return h->flags & flg; \
121733
122220
  } \
121734
- FIO_IFUNC uint16_t fio_http_##flags##_unset(fio_http_s *h, uint16_t flg) { \
122221
+ FIO_IFUNC uint16_t fio___http_##flags##_unset(fio_http_s *h, uint16_t flg) { \
121735
122222
  FIO_ASSERT_DEBUG(h, "NULL HTTP handler!"); \
121736
122223
  h->flags &= ~flg; \
121737
122224
  return h->flags & flg; \
121738
122225
  } \
121739
- FIO_IFUNC uint16_t fio_http_##flags##_is_set(fio_http_s *h, uint16_t flg) { \
122226
+ FIO_IFUNC uint16_t fio___http_##flags##_is_set(fio_http_s *h, \
122227
+ uint16_t flg) { \
121740
122228
  FIO_ASSERT_DEBUG(h, "NULL HTTP handler!"); \
121741
122229
  return h->flags & flg; \
121742
122230
  }
121743
122231
 
121744
122232
  FIO___HTTP_MAKE_GET_SET(cflags)
121745
- FIO___HTTP_MAKE_GET_SET(uflags)
122233
+
122234
+ /* Test-only seam for detached handles: production callers configure
122235
+ * compression via listener/route settings, not controller flags. */
122236
+ #if defined(FIO_HTTP_TEST_COMPRESSION_FLAGS)
122237
+ FIO_IFUNC void fio___http_test_enable_compression(fio_http_s *h,
122238
+ int is_static) {
122239
+ fio___http_cflags_set(h,
122240
+ is_static ? FIO___HTTP_CFLAG_COMPRESS_STATIC
122241
+ : FIO___HTTP_CFLAG_COMPRESS_DYNAMIC);
122242
+ }
122243
+ #endif
121746
122244
 
121747
122245
  #undef FIO___HTTP_MAKE_GET_SET
121748
122246
  /* *****************************************************************************
@@ -121751,45 +122249,147 @@ Handler State
121751
122249
 
121752
122250
  SFUNC int fio_http_is_clean(fio_http_s *h) {
121753
122251
  FIO_ASSERT_DEBUG(h, "NULL HTTP handler!");
121754
- return !(h->state & (~FIO_HTTP_STATE_COOKIES_PARSED));
122252
+ return !(h->state & (~FIO___HTTP_STATE_COOKIES_PARSED));
121755
122253
  }
121756
122254
 
121757
122255
  /** Returns true if the HTTP handle's response was sent. */
121758
122256
  SFUNC int fio_http_is_finished(fio_http_s *h) {
121759
122257
  FIO_ASSERT_DEBUG(h, "NULL HTTP handler!");
121760
- return (!!(h->state & FIO_HTTP_STATE_FINISHED));
122258
+ return (!!(h->state & FIO___HTTP_STATE_FINISHED));
121761
122259
  }
121762
122260
 
121763
122261
  /** Returns true if handle is in the process of freeing itself. */
121764
122262
  SFUNC int fio_http_is_freeing(fio_http_s *h) {
121765
122263
  FIO_ASSERT_DEBUG(h, "NULL HTTP handler!");
121766
- return (!!(h->state & FIO_HTTP_STATE_FREEING));
122264
+ return (!!(h->state & FIO___HTTP_STATE_FREEING));
121767
122265
  }
121768
122266
 
121769
122267
  /** Returns true if the HTTP handle's response is streaming. */
121770
122268
  SFUNC int fio_http_is_streaming(fio_http_s *h) {
121771
122269
  FIO_ASSERT_DEBUG(h, "NULL HTTP handler!");
121772
- return (!!(h->state & FIO_HTTP_STATE_STREAMING));
122270
+ return (!!(h->state & FIO___HTTP_STATE_STREAMING));
121773
122271
  }
121774
122272
 
121775
122273
  /** Returns true if the HTTP connection was (or should have been) upgraded. */
121776
122274
  SFUNC int fio_http_is_upgraded(fio_http_s *h) {
121777
122275
  FIO_ASSERT_DEBUG(h, "NULL HTTP handler!");
121778
- return (!!(h->state & FIO_HTTP_STATE_UPGRADED));
122276
+ return (!!(h->state & FIO___HTTP_STATE_UPGRADED));
121779
122277
  }
121780
122278
 
121781
122279
  /** Returns true if the HTTP handle establishes a WebSocket Upgrade. */
121782
122280
  SFUNC int fio_http_is_websocket(fio_http_s *h) {
121783
122281
  FIO_ASSERT_DEBUG(h, "NULL HTTP handler!");
121784
- return (!!(h->state & FIO_HTTP_STATE_WEBSOCKET));
122282
+ return (!!(h->state & FIO___HTTP_STATE_WEBSOCKET));
121785
122283
  }
121786
122284
 
121787
122285
  /** Returns true if the HTTP handle establishes an EventSource connection. */
121788
122286
  SFUNC int fio_http_is_sse(fio_http_s *h) {
121789
122287
  FIO_ASSERT_DEBUG(h, "NULL HTTP handler!");
121790
- return (!!(h->state & FIO_HTTP_STATE_SSE));
122288
+ return (!!(h->state & FIO___HTTP_STATE_SSE));
121791
122289
  }
121792
122290
 
122291
+ /* *****************************************************************************
122292
+ Method Name Matching
122293
+ ***************************************************************************** */
122294
+
122295
+ SFUNC int fio_http_method_is_get(fio_http_s *h); /* IDE Marker*/
122296
+ SFUNC int fio_http_method_is_post(fio_http_s *h); /* IDE Marker*/
122297
+ SFUNC int fio_http_method_is_head(fio_http_s *h); /* IDE Marker*/
122298
+ SFUNC int fio_http_method_is_put(fio_http_s *h); /* IDE Marker*/
122299
+
122300
+ /* Define test for lengths 3 and 4 */
122301
+ #define FIO___HTTP_DEF_METHOD_TEST(m, l) \
122302
+ /** Tests if fio_http_method is m (case insensitive). */ \
122303
+ SFUNC int fio_http_method_is_##m(fio_http_s *h) { \
122304
+ FIO_ASSERT_DEBUG(h, "NULL HTTP handler!"); \
122305
+ fio_str_info_s method = fio_http_method(h); \
122306
+ if (method.len != l) \
122307
+ return 0; \
122308
+ const uint32_t tst = fio_buf2u32u(#m) | 0x20202020U; \
122309
+ const uint32_t is = fio_buf2u32u(method.buf) | 0x20202020U; \
122310
+ return (tst == is); \
122311
+ }
122312
+
122313
+ FIO___HTTP_DEF_METHOD_TEST(copy, 4)
122314
+ FIO___HTTP_DEF_METHOD_TEST(get, 3)
122315
+ FIO___HTTP_DEF_METHOD_TEST(head, 4)
122316
+ FIO___HTTP_DEF_METHOD_TEST(lock, 4)
122317
+ FIO___HTTP_DEF_METHOD_TEST(move, 4)
122318
+ FIO___HTTP_DEF_METHOD_TEST(post, 4)
122319
+ FIO___HTTP_DEF_METHOD_TEST(put, 3)
122320
+
122321
+ #undef FIO___HTTP_DEF_METHOD_TEST
122322
+
122323
+ /* Define test for length 5 */
122324
+ #define FIO___HTTP_DEF_METHOD_TEST(m, l) \
122325
+ /** Returns 1 if fio_http_method is m (case insensitive). */ \
122326
+ SFUNC int fio_http_method_is_##m(fio_http_s *h) { \
122327
+ static const char *name = #m; \
122328
+ FIO_ASSERT_DEBUG(h, "NULL HTTP handler!"); \
122329
+ fio_str_info_s method = fio_http_method(h); \
122330
+ if (method.len != l) \
122331
+ return 0; \
122332
+ if ((method.buf[0] | 0x20) != name[0]) \
122333
+ return 0; \
122334
+ const uint32_t tst = fio_buf2u32u(name + 1) | 0x20202020U; \
122335
+ const uint32_t is = fio_buf2u32u(method.buf + 1) | 0x20202020U; \
122336
+ return (tst == is); \
122337
+ }
122338
+
122339
+ FIO___HTTP_DEF_METHOD_TEST(patch, 5)
122340
+ FIO___HTTP_DEF_METHOD_TEST(query, 5)
122341
+ FIO___HTTP_DEF_METHOD_TEST(trace, 5)
122342
+ FIO___HTTP_DEF_METHOD_TEST(mkcol, 5)
122343
+
122344
+ #undef FIO___HTTP_DEF_METHOD_TEST
122345
+
122346
+ /* Define test for lengths 5-8 */
122347
+ #define FIO___HTTP_DEF_METHOD_TEST(m, l) \
122348
+ /** Returns 1 if fio_http_method is m (case insensitive). */ \
122349
+ SFUNC int fio_http_method_is_##m(fio_http_s *h) { \
122350
+ static const char *name = #m; \
122351
+ FIO_ASSERT_DEBUG(h, "NULL HTTP handler!"); \
122352
+ fio_str_info_s method = fio_http_method(h); \
122353
+ if (method.len != l) \
122354
+ return 0; \
122355
+ const uint32_t tst1 = fio_buf2u32u(name) | 0x20202020U; \
122356
+ const uint32_t is1 = fio_buf2u32u(method.buf) | 0x20202020U; \
122357
+ const uint32_t tst2 = fio_buf2u32u(name + (l - 4)) | 0x20202020U; \
122358
+ const uint32_t is2 = fio_buf2u32u(method.buf + (l - 4)) | 0x20202020U; \
122359
+ return !((tst1 ^ is1) | (tst2 ^ is2)); \
122360
+ }
122361
+
122362
+ FIO___HTTP_DEF_METHOD_TEST(search, 6)
122363
+ FIO___HTTP_DEF_METHOD_TEST(delete, 6)
122364
+ FIO___HTTP_DEF_METHOD_TEST(options, 7)
122365
+ FIO___HTTP_DEF_METHOD_TEST(connect, 7)
122366
+ FIO___HTTP_DEF_METHOD_TEST(unlock, 6)
122367
+ FIO___HTTP_DEF_METHOD_TEST(propfind, 8)
122368
+
122369
+ #undef FIO___HTTP_DEF_METHOD_TEST
122370
+
122371
+ /* Define test for lengths 9-16 */
122372
+ #define FIO___HTTP_DEF_METHOD_TEST(m, l) \
122373
+ /** Returns 1 if fio_http_method is m (case insensitive). */ \
122374
+ SFUNC int fio_http_method_is_##m(fio_http_s *h) { \
122375
+ static const char *name = #m; \
122376
+ FIO_ASSERT_DEBUG(h, "NULL HTTP handler!"); \
122377
+ fio_str_info_s method = fio_http_method(h); \
122378
+ if (method.len != l) \
122379
+ return 0; \
122380
+ const uint64_t tst1 = \
122381
+ fio_buf2u64u(name) | (uint64_t)0x2020202020202020ULL; \
122382
+ const uint64_t is1 = \
122383
+ fio_buf2u64u(method.buf) | (uint64_t)0x2020202020202020ULL; \
122384
+ const uint32_t tst2 = fio_buf2u32u(name + (l - 8)) | 0x20202020U; \
122385
+ const uint32_t is2 = fio_buf2u32u(method.buf + (l - 8)) | 0x20202020U; \
122386
+ return !((tst1 ^ is1) | (uint64_t)(tst2 ^ is2)); \
122387
+ }
122388
+
122389
+ FIO___HTTP_DEF_METHOD_TEST(proppatch, 9)
122390
+
122391
+ #undef FIO___HTTP_DEF_METHOD_TEST
122392
+
121793
122393
  /* *****************************************************************************
121794
122394
  Header Data Management
121795
122395
  ***************************************************************************** */
@@ -122017,8 +122617,9 @@ int fio_http_cookie_set___(void); /* IDE Marker */
122017
122617
  SFUNC int fio_http_cookie_set FIO_NOOP(fio_http_s *h,
122018
122618
  fio_http_cookie_args_s cookie) {
122019
122619
  FIO_ASSERT_DEBUG(h, "Can't set cookie for NULL HTTP handler!");
122020
- if (!h || ((h->state & (FIO_HTTP_STATE_FINISHED | FIO_HTTP_STATE_STREAMING)) |
122021
- (h->writer != fio____http_write_start)))
122620
+ if (!h ||
122621
+ ((h->state & (FIO___HTTP_STATE_FINISHED | FIO___HTTP_STATE_STREAMING)) |
122622
+ (h->writer != fio____http_write_start)))
122022
122623
  return -1;
122023
122624
  /* promises that some warnings print only once. */
122024
122625
  static unsigned int warn_illegal = 0;
@@ -122219,8 +122820,8 @@ SFUNC int fio_http_cookie_set FIO_NOOP(fio_http_s *h,
122219
122820
  SFUNC fio_str_info_s fio_http_cookie(fio_http_s *h,
122220
122821
  const char *name,
122221
122822
  size_t name_len) {
122222
- if (!(fio_atomic_or(&h->state, FIO_HTTP_STATE_COOKIES_PARSED) &
122223
- FIO_HTTP_STATE_COOKIES_PARSED))
122823
+ if (!(fio_atomic_or(&h->state, FIO___HTTP_STATE_COOKIES_PARSED) &
122824
+ FIO___HTTP_STATE_COOKIES_PARSED))
122224
122825
  fio___http_cookie_collect(h);
122225
122826
  fio_str_info_s r =
122226
122827
  fio___http_cmap_get(h->cookies, FIO_STR_INFO2((char *)name, name_len));
@@ -122234,8 +122835,8 @@ SFUNC size_t fio_http_cookie_each(fio_http_s *h,
122234
122835
  fio_str_info_s value,
122235
122836
  void *udata),
122236
122837
  void *udata) {
122237
- if (!(fio_atomic_or(&h->state, FIO_HTTP_STATE_COOKIES_PARSED) &
122238
- FIO_HTTP_STATE_COOKIES_PARSED))
122838
+ if (!(fio_atomic_or(&h->state, FIO___HTTP_STATE_COOKIES_PARSED) &
122839
+ FIO___HTTP_STATE_COOKIES_PARSED))
122239
122840
  fio___http_cookie_collect(h);
122240
122841
  size_t i = 0;
122241
122842
  FIO_MAP_EACH(fio___http_cmap, h->cookies, pos) {
@@ -122485,7 +123086,7 @@ SFUNC fio_str_info_s fio_http_body_read(fio_http_s *h, size_t length) {
122485
123086
  fio_str_info_s r = {0};
122486
123087
  if (h->body.pos == h->body.len)
122487
123088
  return r;
122488
- if (h->body.pos + length > h->body.len)
123089
+ if (length > h->body.len - h->body.pos)
122489
123090
  length = h->body.len - h->body.pos;
122490
123091
  r = ((h->body.fd == -1) ? fio___http_body_read_buf
122491
123092
  : fio___http_body_read_fd)(h, length);
@@ -122616,7 +123217,8 @@ FIO_SFUNC int fio____http_write_start(fio_http_s *h,
122616
123217
  }
122617
123218
  #if 1
122618
123219
  if (args->finish &&
122619
- FIO_LIKELY(fio_http_cflags_is_set(h, FIO_HTTP_CFLAG_COMPRESS_DYNAMIC)) &&
123220
+ FIO_LIKELY(
123221
+ fio___http_cflags_is_set(h, FIO___HTTP_CFLAG_COMPRESS_DYNAMIC)) &&
122620
123222
  args->len > 1024 && args->buf) {
122621
123223
  /* Never double-compress: the application already encoded this response. */
122622
123224
  if (fio___http_hmap_get_ptr(hdrs,
@@ -122735,7 +123337,7 @@ FIO_SFUNC int fio____http_write_start(fio_http_s *h,
122735
123337
  fio_ltoa10u(v.buf, args->len, v.len);
122736
123338
  fio___http_hmap_set2(hdrs, k, v, -1);
122737
123339
  } else if (!(h->state & FIO___HTTP_STATE_NO_CONTENT)) {
122738
- h->state |= FIO_HTTP_STATE_STREAMING;
123340
+ h->state |= FIO___HTTP_STATE_STREAMING;
122739
123341
  }
122740
123342
  }
122741
123343
  send_headers:
@@ -122752,8 +123354,8 @@ FIO_SFUNC int fio____http_write_cont(fio_http_s *h,
122752
123354
  h->sent += args->len;
122753
123355
  }
122754
123356
  if (args->finish) {
122755
- h->state |= FIO_HTTP_STATE_FINISHED;
122756
- h->writer = (h->state & FIO_HTTP_STATE_UPGRADED)
123357
+ h->state |= FIO___HTTP_STATE_FINISHED;
123358
+ h->writer = (h->state & FIO___HTTP_STATE_UPGRADED)
122757
123359
  ? fio____http_write_upgraded
122758
123360
  : fio____http_write_done;
122759
123361
  h->controller->on_finish(h);
@@ -122791,7 +123393,7 @@ FIO_IFUNC int fio___http_response_etag_if_none_match(fio_http_s *h) {
122791
123393
  -1);
122792
123394
 
122793
123395
  h->controller->send_headers(h);
122794
- h->state |= FIO_HTTP_STATE_FINISHED;
123396
+ h->state |= FIO___HTTP_STATE_FINISHED;
122795
123397
  h->writer = fio____http_write_done;
122796
123398
  h->controller->on_finish(h);
122797
123399
  return -1;
@@ -122881,7 +123483,7 @@ SFUNC void fio_http_upgrade_websocket(fio_http_s *h) {
122881
123483
  accept_val);
122882
123484
  }
122883
123485
  { /* finish up */
122884
- h->state |= FIO_HTTP_STATE_UPGRADED | FIO_HTTP_STATE_WEBSOCKET;
123486
+ h->state |= FIO___HTTP_STATE_UPGRADED | FIO___HTTP_STATE_WEBSOCKET;
122885
123487
  fio_http_write_args_s args = {.finish = 1};
122886
123488
  fio_http_write FIO_NOOP(h, args);
122887
123489
  }
@@ -122983,8 +123585,8 @@ SFUNC int fio_http_websocket_accepted(fio_http_s *h) {
122983
123585
  return 0;
122984
123586
  }
122985
123587
  }
122986
- h->state |= (FIO_HTTP_STATE_UPGRADED | FIO_HTTP_STATE_WEBSOCKET |
122987
- FIO_HTTP_STATE_FINISHED);
123588
+ h->state |= (FIO___HTTP_STATE_UPGRADED | FIO___HTTP_STATE_WEBSOCKET |
123589
+ FIO___HTTP_STATE_FINISHED);
122988
123590
  h->writer = fio____http_write_upgraded;
122989
123591
  return 1;
122990
123592
  }
@@ -123027,8 +123629,8 @@ SFUNC int fio_http_sse_accepted(fio_http_s *h) {
123027
123629
  FIO_STR_INFO2((char *)"content-type", 12),
123028
123630
  0);
123029
123631
  }
123030
- h->state |=
123031
- (FIO_HTTP_STATE_UPGRADED | FIO_HTTP_STATE_SSE | FIO_HTTP_STATE_FINISHED);
123632
+ h->state |= (FIO___HTTP_STATE_UPGRADED | FIO___HTTP_STATE_SSE |
123633
+ FIO___HTTP_STATE_FINISHED);
123032
123634
  h->writer = fio____http_write_upgraded;
123033
123635
  FIO_LOG_DDEBUG2("EventSource connection accepted.");
123034
123636
  return 1;
@@ -123047,8 +123649,8 @@ SFUNC void fio_http_upgrade_sse(fio_http_s *h) {
123047
123649
  fio___http_hmap_remove(HTTP_HDR_RESPONSE(h),
123048
123650
  FIO_STR_INFO2((char *)"content-length", 14),
123049
123651
  NULL);
123050
- h->state |=
123051
- FIO_HTTP_STATE_FINISHED | FIO_HTTP_STATE_UPGRADED | FIO_HTTP_STATE_SSE;
123652
+ h->state |= FIO___HTTP_STATE_FINISHED | FIO___HTTP_STATE_UPGRADED |
123653
+ FIO___HTTP_STATE_SSE;
123052
123654
  h->controller->send_headers(h);
123053
123655
  h->writer = fio____http_write_upgraded;
123054
123656
  h->controller->on_finish(h);
@@ -124454,7 +125056,7 @@ FIO_SFUNC void fio___http_static_compress_note_result(
124454
125056
  * EACCES, EROFS, EDQUOT — `value = 0`). Once 0, creation stays disabled
124455
125057
  * until the settings are re-applied. Routes inherit the value from the
124456
125058
  * listener settings at route-creation. Detached handles (no settings)
124457
- * gate on the `FIO_HTTP_CFLAG_COMPRESS_STATIC` cflag instead, with no
125059
+ * gate on the `FIO___HTTP_CFLAG_COMPRESS_STATIC` cflag instead, with no
124458
125060
  * memoization state.
124459
125061
  */
124460
125062
  SFUNC int fio_http_static_file_response(fio_http_s *h,
@@ -124577,7 +125179,7 @@ SFUNC int fio_http_static_file_response(fio_http_s *h,
124577
125179
  int can_create =
124578
125180
  have_orig_st &&
124579
125181
  (st ? settings_may_compress
124580
- : fio_http_cflags_is_set(h, FIO_HTTP_CFLAG_COMPRESS_STATIC)) &&
125182
+ : fio___http_cflags_is_set(h, FIO___HTTP_CFLAG_COMPRESS_STATIC)) &&
124581
125183
  fio___http_mime_is_compressible(mime_type) &&
124582
125184
  (size_t)orig_st.st_size >= 1024 &&
124583
125185
  (size_t)orig_st.st_size <= FIO_HTTP_STATIC_FILE_COMPRESS_LIMIT;
@@ -125591,9 +126193,9 @@ FIO_IFUNC void fio_http1_attach_handle(fio___http_connection_s *c) {
125591
126193
  fio_http_udata_set(c->h, c->udata);
125592
126194
  fio_http_cdata_set(c->h, fio___http_connection_dup(c));
125593
126195
  if (c->settings->compress_dynamic)
125594
- fio_http_cflags_set(c->h, FIO_HTTP_CFLAG_COMPRESS_DYNAMIC);
126196
+ fio___http_cflags_set(c->h, FIO___HTTP_CFLAG_COMPRESS_DYNAMIC);
125595
126197
  if (c->settings->compress_ws)
125596
- fio_http_cflags_set(c->h, FIO_HTTP_CFLAG_COMPRESS_WS);
126198
+ fio___http_cflags_set(c->h, FIO___HTTP_CFLAG_COMPRESS_WS);
125597
126199
  }
125598
126200
 
125599
126201
  /** called when a request method is parsed. */
@@ -125940,7 +126542,7 @@ FIO_SFUNC void fio___http1_send_request(fio_http_s *h) {
125940
126542
  fio_io_write2(c->io,
125941
126543
  .buf = (char *)fio_http_dup(h),
125942
126544
  .len = buf.len,
125943
- .offset = (size_t)((char *)h - buf.buf),
126545
+ .offset = (size_t)(buf.buf - (char *)h),
125944
126546
  .dealloc = (void (*)(void *))fio_http_free);
125945
126547
  } else {
125946
126548
  fio_io_write2(c->io,
@@ -126028,10 +126630,7 @@ FIO_SFUNC void fio___http_controller_http1_send_headers(fio_http_s *h) {
126028
126630
  FIO_STR_INFO2((char *)"connection", 10),
126029
126631
  0)
126030
126632
  .buf)
126031
- fio_string_write(&buf,
126032
- FIO_STRING_REALLOC,
126033
- "connection:keep-alive\r\n",
126034
- 23);
126633
+ fio_string_write(&buf, FIO_STRING_REALLOC, "connection:keep-alive\r\n", 23);
126035
126634
  fio_string_write(&buf, FIO_STRING_REALLOC, "\r\n", 2);
126036
126635
  /* send data (move memory ownership)? */
126037
126636
  c->state.http.buf = buf;
@@ -126677,7 +127276,7 @@ FIO_SFUNC void fio___http_perform_user_upgrade_callback_websocket(void *cb_,
126677
127276
  if (c->h) /* request after WebSocket Upgrade? an attack vector? */
126678
127277
  goto refuse_upgrade;
126679
127278
  /* RFC 7692: permessage-deflate extension negotiation (no-takeover only) */
126680
- if (FIO_LIKELY(fio_http_cflags_is_set(h, FIO_HTTP_CFLAG_COMPRESS_WS))) {
127279
+ if (FIO_LIKELY(fio___http_cflags_is_set(h, FIO___HTTP_CFLAG_COMPRESS_WS))) {
126681
127280
  FIO_HTTP_HEADER_EACH_VALUE(
126682
127281
  h,
126683
127282
  1,
@@ -126686,9 +127285,8 @@ FIO_SFUNC void fio___http_perform_user_upgrade_callback_websocket(void *cb_,
126686
127285
  FIO_LOG_DDEBUG2("WebSocket extension requested: %.*s",
126687
127286
  (int)val.value.len,
126688
127287
  val.value.buf);
126689
- if (!FIO_BUF_INFO_IS_EQ(
126690
- val.value,
126691
- FIO_BUF_INFO2((char *)"permessage-deflate", 18)))
127288
+ if (!FIO_BUF_INFO_IS_EQ(val.value,
127289
+ FIO_BUF_INFO2((char *)"permessage-deflate", 18)))
126692
127290
  continue;
126693
127291
  /* Negotiate: ALWAYS force both no_context_takeover flags (persistent
126694
127292
  * compression state stays ~0 per connection); honor
@@ -126698,8 +127296,8 @@ FIO_SFUNC void fio___http_perform_user_upgrade_callback_websocket(void *cb_,
126698
127296
  size_t ext_len = fio___http_ws_deflate_negotiate(
126699
127297
  FIO_STR_INFO2(val.value.buf, val.value.len),
126700
127298
  ext_resp,
126701
- sizeof(ext_resp),
126702
- &server_bits);
127299
+ sizeof(ext_resp),
127300
+ &server_bits);
126703
127301
  if (!ext_len)
126704
127302
  continue;
126705
127303
  fio_http_response_header_set(
@@ -127305,34 +127903,36 @@ FIO_SFUNC void fio___http_controller_ws_write_body(fio_http_s *h,
127305
127903
  const size_t framed_len = fio_websocket_write_len(args.len, 1);
127306
127904
  char *frame = NULL;
127307
127905
  if (args.len <= SIZE_MAX - args.offset && framed_len <= UINT32_MAX &&
127308
- (args.buf ||
127309
- ((off_t)args.offset >= 0 &&
127310
- (uintmax_t)(off_t)args.offset == (uintmax_t)args.offset &&
127311
- (off_t)(args.offset + args.len) >= 0 &&
127312
- (uintmax_t)(off_t)(args.offset + args.len) ==
127313
- (uintmax_t)(args.offset + args.len))))
127906
+ (args.buf || ((off_t)args.offset >= 0 &&
127907
+ (uintmax_t)(off_t)args.offset == (uintmax_t)args.offset &&
127908
+ (off_t)(args.offset + args.len) >= 0 &&
127909
+ (uintmax_t)(off_t)(args.offset + args.len) ==
127910
+ (uintmax_t)(args.offset + args.len))))
127314
127911
  frame = fio_bstr_reserve(NULL, framed_len);
127315
127912
  if (!frame)
127316
127913
  goto client_write_error;
127317
127914
  if (args.buf) {
127318
127915
  fio_websocket_write_message_client(
127319
- frame, FIO_BUF_INFO2((char *)args.buf + args.offset, args.len), 0, 0, 0);
127916
+ frame,
127917
+ FIO_BUF_INFO2((char *)args.buf + args.offset, args.len),
127918
+ 0,
127919
+ 0,
127920
+ 0);
127320
127921
  } else {
127321
127922
  uint32_t mask = (uint32_t)(fio_rand64() | 0x01020408U);
127322
127923
  size_t head = fio___websocket_hdr((uint8_t *)frame,
127323
- args.len,
127324
- mask,
127325
- FIO_WEBSOCKET_OP_BINARY,
127326
- 0);
127924
+ args.len,
127925
+ mask,
127926
+ FIO_WEBSOCKET_OP_BINARY,
127927
+ 0);
127327
127928
  if (fio_fd_read(args.fd, frame + head, args.len, (off_t)args.offset) !=
127328
127929
  args.len) {
127329
127930
  fio_bstr_free(frame);
127330
127931
  goto client_write_error;
127331
127932
  }
127332
- fio_xmask_cpy(frame + head,
127333
- frame + head,
127334
- args.len,
127335
- ((uint64_t)mask << 32) | (uint64_t)mask);
127933
+ fio_xmask(frame + head,
127934
+ args.len,
127935
+ ((uint64_t)mask << 32) | (uint64_t)mask);
127336
127936
  }
127337
127937
  if (!args.buf && (unsigned)(args.fd + 1) > 1)
127338
127938
  close(args.fd);
@@ -127981,6 +128581,17 @@ once per template instantiation pass.
127981
128581
  Copyright and License: see header file (000 copyright.h) or top of file
127982
128582
  ***************************************************************************** */
127983
128583
  #if !defined(FIO___RECURSIVE_INCLUDE) && defined(FIO_HTTP)
128584
+ #undef FIO___HTTP_STATE_STREAMING
128585
+ #undef FIO___HTTP_STATE_FINISHED
128586
+ #undef FIO___HTTP_STATE_UPGRADED
128587
+ #undef FIO___HTTP_STATE_WEBSOCKET
128588
+ #undef FIO___HTTP_STATE_SSE
128589
+ #undef FIO___HTTP_STATE_COOKIES_PARSED
128590
+ #undef FIO___HTTP_STATE_FREEING
128591
+ #undef FIO___HTTP_STATE_NO_CONTENT
128592
+ #undef FIO___HTTP_CFLAG_COMPRESS_DYNAMIC
128593
+ #undef FIO___HTTP_CFLAG_COMPRESS_WS
128594
+ #undef FIO___HTTP_CFLAG_COMPRESS_STATIC
127984
128595
  #undef FIO_HTTP
127985
128596
  #endif
127986
128597
  /* *****************************************************************************