Skip to content
File

Blob: src/workerd/util/uuid.c++

4.3 KB
1// Copyright (c) 2017-2022 Cloudflare, Inc.
2// Licensed under the Apache 2.0 license found in the LICENSE file or at:
3// https://opensource.org/licenses/Apache-2.0
4 
5#include "uuid.h"
6 
7#include <workerd/util/entropy.h>
8 
9#include <kj/compat/http.h>
10#include <kj/debug.h>
11 
12#include <cstdlib>
13 
14namespace workerd {
15namespace {
16constexpr char HEX_DIGITS[] = "0123456789abcdef";
17} // namespace
18 
19kj::String randomUUID(kj::Maybe<kj::EntropySource&> optionalEntropySource) {
20 kj::FixedArray<kj::byte, 16> buffer;
21 
22 KJ_IF_SOME(entropySource, optionalEntropySource) {
23 entropySource.generate(buffer);
24 } else {
25 getEntropy(buffer);
26 }
27 buffer[6] = static_cast<kj::byte>((buffer[6] & 0x0f) | 0x40);
28 buffer[8] = static_cast<kj::byte>((buffer[8] & 0x3f) | 0x80);
29 
30#define HEX(b) (char)(HEX_DIGITS[(b >> 4) & 0xf]), (char)(HEX_DIGITS[b & 0xf])
31 
32 // The format for Random UUID's is established in
33 // https://www.rfc-editor.org/rfc/rfc4122.txt
34 // xxxxxxxx-xxxx-Axxx-Bxxx-xxxxxxxxxxxx
35 //
36 // The sequence is 16 hex-encoded random bytes
37 // divided into 1 4-byte, 3 2-byte, and 1 6-byte
38 // groups. The four most significant bits of the
39 // 7th byte (A) are set to 0100xxxx (0x40), while
40 // the two most significant bits of the 9th byte (B)
41 // are set to 10xxxxxx (0x80). These are the key bits
42 // that identify the type and version of the uuid.
43 // All other bits are random. That ends up meaning
44 // that in the serialized uuid, the first character
45 // of the third grouping is always a 4, and the first
46 // character of the fourth grouping is always either
47 // an a, b, 8, or 9.
48 
49 // clang-format off
50 return kj::String(kj::arr<char>(
51 HEX(buffer[0]),
52 HEX(buffer[1]),
53 HEX(buffer[2]),
54 HEX(buffer[3]),
55 '-',
56 HEX(buffer[4]),
57 HEX(buffer[5]),
58 '-',
59 HEX(buffer[6]),
60 HEX(buffer[7]),
61 '-',
62 HEX(buffer[8]),
63 HEX(buffer[9]),
64 '-',
65 HEX(buffer[10]),
66 HEX(buffer[11]),
67 HEX(buffer[12]),
68 HEX(buffer[13]),
69 HEX(buffer[14]),
70 HEX(buffer[15]),
71 '\0'
72 ));
73 // clang-format on
74 
75#undef HEX
76}
77 
78kj::Maybe<UUID> UUID::fromUpperLower(uint64_t upper, uint64_t lower) {
79 if (upper == 0 && lower == 0) {
80 return kj::none;
81 }
82 return UUID(upper, lower);
83}
84 
85kj::Maybe<UUID> UUID::fromString(kj::StringPtr str) {
86 if (str.size() != 36u) {
87 return kj::none;
88 }
89 uint64_t upper = 0;
90 uint64_t lower = 0;
91 auto begin = str.cStr();
92 char* p;
93 upper += (strtoull(begin, &p, 16) << 32u);
94 if (p - begin != 8 || *p != '-') {
95 return kj::none;
96 }
97 upper += (strtoull(++p, &p, 16) << 16u);
98 if (p - begin != 13 || *p != '-') {
99 return kj::none;
100 }
101 upper += (strtoull(++p, &p, 16));
102 if (p - begin != 18 || *p != '-') {
103 return kj::none;
104 }
105 lower += (strtoull(++p, &p, 16) << 48u);
106 if (p - begin != 23 || *p != '-') {
107 return kj::none;
108 }
109 lower += (strtoull(++p, &p, 16));
110 if (p - begin != 36) {
111 return kj::none;
112 }
113 if (upper == 0 && lower == 0) {
114 return kj::none;
115 }
116 return UUID(upper, lower);
117}
118 
119kj::String UUID::toString() const {
120 // clang-format off
121 return kj::str(
122 HEX_DIGITS[(upper >> 60u) & 0xf],
123 HEX_DIGITS[(upper >> 56u) & 0xf],
124 HEX_DIGITS[(upper >> 52u) & 0xf],
125 HEX_DIGITS[(upper >> 48u) & 0xf],
126 HEX_DIGITS[(upper >> 44u) & 0xf],
127 HEX_DIGITS[(upper >> 40u) & 0xf],
128 HEX_DIGITS[(upper >> 36u) & 0xf],
129 HEX_DIGITS[(upper >> 32u) & 0xf],
130 '-',
131 HEX_DIGITS[(upper >> 28u) & 0xf],
132 HEX_DIGITS[(upper >> 24u) & 0xf],
133 HEX_DIGITS[(upper >> 20u) & 0xf],
134 HEX_DIGITS[(upper >> 16u) & 0xf],
135 '-',
136 HEX_DIGITS[(upper >> 12u) & 0xf],
137 HEX_DIGITS[(upper >> 8u) & 0xf],
138 HEX_DIGITS[(upper >> 4u) & 0xf],
139 HEX_DIGITS[(upper >> 0u) & 0xf],
140 '-',
141 HEX_DIGITS[(lower >> 60u) & 0xf],
142 HEX_DIGITS[(lower >> 56u) & 0xf],
143 HEX_DIGITS[(lower >> 52u) & 0xf],
144 HEX_DIGITS[(lower >> 48u) & 0xf],
145 '-',
146 HEX_DIGITS[(lower >> 44u) & 0xf],
147 HEX_DIGITS[(lower >> 40u) & 0xf],
148 HEX_DIGITS[(lower >> 36u) & 0xf],
149 HEX_DIGITS[(lower >> 32u) & 0xf],
150 HEX_DIGITS[(lower >> 28u) & 0xf],
151 HEX_DIGITS[(lower >> 24u) & 0xf],
152 HEX_DIGITS[(lower >> 20u) & 0xf],
153 HEX_DIGITS[(lower >> 16u) & 0xf],
154 HEX_DIGITS[(lower >> 12u) & 0xf],
155 HEX_DIGITS[(lower >> 8u) & 0xf],
156 HEX_DIGITS[(lower >> 4u) & 0xf],
157 HEX_DIGITS[(lower >> 0u) & 0xf]
158 );
159 // clang-format on
160}
161 
162} // namespace workerd