opal-up 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -21,14 +21,15 @@
21
21
  /* There is a new, huge bug scenario that needs to be fixed:
22
22
  * pub/sub does not support being in DEDICATED_COMPRESSOR-mode while having
23
23
  * some clients downgraded to SHARED_COMPRESSOR - we cannot allow the client to
24
- * demand a downgrade to SHARED_COMPRESSOR (yet) until we fix that scenario in pub/sub */
24
+ * demand a downgrade to SHARED_COMPRESSOR (yet) until we fix that scenario in
25
+ * pub/sub */
25
26
  // #define UWS_ALLOW_SHARED_AND_DEDICATED_COMPRESSOR_MIX
26
27
 
27
28
  /* We forbid negotiating 8 windowBits since Zlib has a bug with this */
28
29
  // #define UWS_ALLOW_8_WINDOW_BITS
29
30
 
30
- #include <climits>
31
31
  #include <cctype>
32
+ #include <climits>
32
33
  #include <string>
33
34
  #include <string_view>
34
35
  #include <tuple>
@@ -36,221 +37,236 @@
36
37
  namespace uWS {
37
38
 
38
39
  enum ExtensionTokens {
39
- /* Standard permessage-deflate tokens */
40
- TOK_PERMESSAGE_DEFLATE = 1838,
41
- TOK_SERVER_NO_CONTEXT_TAKEOVER = 2807,
42
- TOK_CLIENT_NO_CONTEXT_TAKEOVER = 2783,
43
- TOK_SERVER_MAX_WINDOW_BITS = 2372,
44
- TOK_CLIENT_MAX_WINDOW_BITS = 2348,
45
- /* Non-standard alias for Safari */
46
- TOK_X_WEBKIT_DEFLATE_FRAME = 2149,
47
- TOK_NO_CONTEXT_TAKEOVER = 2049,
48
- TOK_MAX_WINDOW_BITS = 1614
40
+ /* Standard permessage-deflate tokens */
41
+ TOK_PERMESSAGE_DEFLATE = 1838,
42
+ TOK_SERVER_NO_CONTEXT_TAKEOVER = 2807,
43
+ TOK_CLIENT_NO_CONTEXT_TAKEOVER = 2783,
44
+ TOK_SERVER_MAX_WINDOW_BITS = 2372,
45
+ TOK_CLIENT_MAX_WINDOW_BITS = 2348,
46
+ /* Non-standard alias for Safari */
47
+ TOK_X_WEBKIT_DEFLATE_FRAME = 2149,
48
+ TOK_NO_CONTEXT_TAKEOVER = 2049,
49
+ TOK_MAX_WINDOW_BITS = 1614
49
50
 
50
51
  };
51
52
 
52
53
  struct ExtensionsParser {
53
54
  private:
54
- int *lastInteger = nullptr;
55
+ int *lastInteger = nullptr;
55
56
 
56
57
  public:
57
- /* Standard */
58
- bool perMessageDeflate = false;
59
- bool serverNoContextTakeover = false;
60
- bool clientNoContextTakeover = false;
61
- int serverMaxWindowBits = 0;
62
- int clientMaxWindowBits = 0;
63
-
64
- /* Non-standard Safari */
65
- bool xWebKitDeflateFrame = false;
66
- bool noContextTakeover = false;
67
- int maxWindowBits = 0;
68
-
69
- int getToken(const char *&in, const char *stop) {
70
- while (in != stop && !isalnum(*in)) {
71
- in++;
72
- }
58
+ /* Standard */
59
+ bool perMessageDeflate = false;
60
+ bool serverNoContextTakeover = false;
61
+ bool clientNoContextTakeover = false;
62
+ int serverMaxWindowBits = 0;
63
+ int clientMaxWindowBits = 0;
64
+
65
+ /* Non-standard Safari */
66
+ bool xWebKitDeflateFrame = false;
67
+ bool noContextTakeover = false;
68
+ int maxWindowBits = 0;
69
+
70
+ int getToken(const char *&in, const char *stop) {
71
+ while (in != stop && !isalnum(*in)) {
72
+ in++;
73
+ }
73
74
 
74
- /* Don't care more than this for now */
75
- static_assert(SHRT_MIN > INT_MIN, "Integer overflow fix is invalid for this platform, report this as a bug!");
76
-
77
- int hashedToken = 0;
78
- while (in != stop && (isalnum(*in) || *in == '-' || *in == '_')) {
79
- if (isdigit(*in)) {
80
- /* This check is a quick and incorrect fix for integer overflow
81
- * in oss-fuzz but we don't care as it doesn't matter either way */
82
- if (hashedToken > SHRT_MIN && hashedToken < SHRT_MAX) {
83
- hashedToken = hashedToken * 10 - (*in - '0');
84
- }
85
- } else {
86
- hashedToken += *in;
87
- }
88
- in++;
75
+ /* Don't care more than this for now */
76
+ static_assert(SHRT_MIN > INT_MIN, "Integer overflow fix is invalid for "
77
+ "this platform, report this as a bug!");
78
+
79
+ int hashedToken = 0;
80
+ while (in != stop && (isalnum(*in) || *in == '-' || *in == '_')) {
81
+ if (isdigit(*in)) {
82
+ /* This check is a quick and incorrect fix for integer overflow
83
+ * in oss-fuzz but we don't care as it doesn't matter either way */
84
+ if (hashedToken > SHRT_MIN && hashedToken < SHRT_MAX) {
85
+ hashedToken = hashedToken * 10 - (*in - '0');
89
86
  }
90
- return hashedToken;
87
+ } else {
88
+ hashedToken += *in;
89
+ }
90
+ in++;
91
91
  }
92
-
93
- ExtensionsParser(const char *data, size_t length) {
94
- const char *stop = data + length;
95
- int token = 1;
96
-
97
- /* Ignore anything before permessage-deflate or x-webkit-deflate-frame */
98
- for (; token && token != TOK_PERMESSAGE_DEFLATE && token != TOK_X_WEBKIT_DEFLATE_FRAME; token = getToken(data, stop));
99
-
100
- /* What protocol are we going to use? */
101
- perMessageDeflate = (token == TOK_PERMESSAGE_DEFLATE);
102
- xWebKitDeflateFrame = (token == TOK_X_WEBKIT_DEFLATE_FRAME);
103
-
104
- while ((token = getToken(data, stop))) {
105
- switch (token) {
106
- case TOK_X_WEBKIT_DEFLATE_FRAME:
107
- /* Duplicates not allowed/supported */
108
- return;
109
- case TOK_NO_CONTEXT_TAKEOVER:
110
- noContextTakeover = true;
111
- break;
112
- case TOK_MAX_WINDOW_BITS:
113
- maxWindowBits = 1;
114
- lastInteger = &maxWindowBits;
115
- break;
116
- case TOK_PERMESSAGE_DEFLATE:
117
- /* Duplicates not allowed/supported */
118
- return;
119
- case TOK_SERVER_NO_CONTEXT_TAKEOVER:
120
- serverNoContextTakeover = true;
121
- break;
122
- case TOK_CLIENT_NO_CONTEXT_TAKEOVER:
123
- clientNoContextTakeover = true;
124
- break;
125
- case TOK_SERVER_MAX_WINDOW_BITS:
126
- serverMaxWindowBits = 1;
127
- lastInteger = &serverMaxWindowBits;
128
- break;
129
- case TOK_CLIENT_MAX_WINDOW_BITS:
130
- clientMaxWindowBits = 1;
131
- lastInteger = &clientMaxWindowBits;
132
- break;
133
- default:
134
- if (token < 0 && lastInteger) {
135
- *lastInteger = -token;
136
- }
137
- break;
138
- }
92
+ return hashedToken;
93
+ }
94
+
95
+ ExtensionsParser(const char *data, size_t length) {
96
+ const char *stop = data + length;
97
+ int token = 1;
98
+
99
+ /* Ignore anything before permessage-deflate or x-webkit-deflate-frame */
100
+ for (; token && token != TOK_PERMESSAGE_DEFLATE &&
101
+ token != TOK_X_WEBKIT_DEFLATE_FRAME;
102
+ token = getToken(data, stop))
103
+ ;
104
+
105
+ /* What protocol are we going to use? */
106
+ perMessageDeflate = (token == TOK_PERMESSAGE_DEFLATE);
107
+ xWebKitDeflateFrame = (token == TOK_X_WEBKIT_DEFLATE_FRAME);
108
+
109
+ while ((token = getToken(data, stop))) {
110
+ switch (token) {
111
+ case TOK_X_WEBKIT_DEFLATE_FRAME:
112
+ /* Duplicates not allowed/supported */
113
+ return;
114
+ case TOK_NO_CONTEXT_TAKEOVER:
115
+ noContextTakeover = true;
116
+ break;
117
+ case TOK_MAX_WINDOW_BITS:
118
+ maxWindowBits = 1;
119
+ lastInteger = &maxWindowBits;
120
+ break;
121
+ case TOK_PERMESSAGE_DEFLATE:
122
+ /* Duplicates not allowed/supported */
123
+ return;
124
+ case TOK_SERVER_NO_CONTEXT_TAKEOVER:
125
+ serverNoContextTakeover = true;
126
+ break;
127
+ case TOK_CLIENT_NO_CONTEXT_TAKEOVER:
128
+ clientNoContextTakeover = true;
129
+ break;
130
+ case TOK_SERVER_MAX_WINDOW_BITS:
131
+ serverMaxWindowBits = 1;
132
+ lastInteger = &serverMaxWindowBits;
133
+ break;
134
+ case TOK_CLIENT_MAX_WINDOW_BITS:
135
+ clientMaxWindowBits = 1;
136
+ lastInteger = &clientMaxWindowBits;
137
+ break;
138
+ default:
139
+ if (token < 0 && lastInteger) {
140
+ *lastInteger = -token;
139
141
  }
142
+ break;
143
+ }
140
144
  }
145
+ }
141
146
  };
142
147
 
143
148
  /* Takes what we (the server) wants, returns what we got */
144
- static inline std::tuple<bool, int, int, std::string_view> negotiateCompression(bool wantCompression, int wantedCompressionWindow, int wantedInflationWindow, std::string_view offer) {
149
+ static inline std::tuple<bool, int, int, std::string_view>
150
+ negotiateCompression(bool wantCompression, int wantedCompressionWindow,
151
+ int wantedInflationWindow, std::string_view offer) {
145
152
 
146
- /* If we don't want compression then we are done here */
147
- if (!wantCompression) {
148
- return {false, 0, 0, ""};
149
- }
153
+ /* If we don't want compression then we are done here */
154
+ if (!wantCompression) {
155
+ return {false, 0, 0, ""};
156
+ }
150
157
 
151
- ExtensionsParser ep(offer.data(), offer.length());
158
+ ExtensionsParser ep(offer.data(), offer.length());
152
159
 
153
- static thread_local std::string response;
154
- response = "";
160
+ static thread_local std::string response;
161
+ response = "";
155
162
 
156
- int compressionWindow = wantedCompressionWindow;
157
- int inflationWindow = wantedInflationWindow;
158
- bool compression = false;
163
+ int compressionWindow = wantedCompressionWindow;
164
+ int inflationWindow = wantedInflationWindow;
165
+ bool compression = false;
159
166
 
160
- if (ep.xWebKitDeflateFrame) {
161
- /* We now have compression */
162
- compression = true;
163
- response = "x-webkit-deflate-frame";
167
+ if (ep.xWebKitDeflateFrame) {
168
+ /* We now have compression */
169
+ compression = true;
170
+ response = "x-webkit-deflate-frame";
164
171
 
165
- /* If the other peer has DEMANDED us no sliding window,
166
- * we cannot compress with anything other than shared compressor */
167
- if (ep.noContextTakeover) {
168
- /* We must fail here right now (fix pub/sub) */
172
+ /* If the other peer has DEMANDED us no sliding window,
173
+ * we cannot compress with anything other than shared compressor */
174
+ if (ep.noContextTakeover) {
175
+ /* We must fail here right now (fix pub/sub) */
169
176
  #ifndef UWS_ALLOW_SHARED_AND_DEDICATED_COMPRESSOR_MIX
170
- if (wantedCompressionWindow != 0) {
171
- return {false, 0, 0, ""};
172
- }
177
+ if (wantedCompressionWindow != 0) {
178
+ return {false, 0, 0, ""};
179
+ }
173
180
  #endif
174
181
 
175
- compressionWindow = 0;
176
- }
182
+ compressionWindow = 0;
183
+ }
177
184
 
178
- /* If the other peer has DEMANDED us to use a limited sliding window,
179
- * we have to limit out compression sliding window */
180
- if (ep.maxWindowBits && ep.maxWindowBits < compressionWindow) {
181
- compressionWindow = ep.maxWindowBits;
185
+ /* If the other peer has DEMANDED us to use a limited sliding window,
186
+ * we have to limit out compression sliding window */
187
+ if (ep.maxWindowBits && ep.maxWindowBits < compressionWindow) {
188
+ compressionWindow = ep.maxWindowBits;
182
189
  #ifndef UWS_ALLOW_8_WINDOW_BITS
183
- /* We cannot really deny this, so we have to disable compression in this case */
184
- if (compressionWindow == 8) {
185
- return {false, 0, 0, ""};
186
- }
190
+ /* We cannot really deny this, so we have to disable compression in this
191
+ * case */
192
+ if (compressionWindow == 8) {
193
+ return {false, 0, 0, ""};
194
+ }
187
195
  #endif
188
- }
196
+ }
189
197
 
190
- /* We decide our own inflation sliding window (and their compression sliding window) */
191
- if (wantedInflationWindow < 15) {
192
- if (!wantedInflationWindow) {
193
- response += "; no_context_takeover";
194
- } else {
195
- response += "; max_window_bits=" + std::to_string(wantedInflationWindow);
196
- }
197
- }
198
- } else if (ep.perMessageDeflate) {
199
- /* We now have compression */
200
- compression = true;
201
- response = "permessage-deflate";
202
-
203
- if (ep.clientNoContextTakeover) {
204
- inflationWindow = 0;
205
- } else if (ep.clientMaxWindowBits && ep.clientMaxWindowBits != 1) {
206
- inflationWindow = std::min<int>(ep.clientMaxWindowBits, inflationWindow);
207
- }
198
+ /* We decide our own inflation sliding window (and their compression sliding
199
+ * window) */
200
+ if (wantedInflationWindow < 15) {
201
+ if (!wantedInflationWindow) {
202
+ response += "; no_context_takeover";
203
+ } else {
204
+ response +=
205
+ "; max_window_bits=" + std::to_string(wantedInflationWindow);
206
+ }
207
+ }
208
+ } else if (ep.perMessageDeflate) {
209
+ /* We now have compression */
210
+ compression = true;
211
+ response = "permessage-deflate";
212
+
213
+ if (ep.clientNoContextTakeover) {
214
+ inflationWindow = 0;
215
+ } else if (ep.clientMaxWindowBits && ep.clientMaxWindowBits != 1) {
216
+ inflationWindow = std::min<int>(ep.clientMaxWindowBits, inflationWindow);
217
+ }
208
218
 
209
- /* Whatever we have now, write */
210
- if (inflationWindow < 15) {
211
- if (!inflationWindow || !ep.clientMaxWindowBits) {
212
- response += "; client_no_context_takeover";
213
- inflationWindow = 0;
214
- } else {
215
- response += "; client_max_window_bits=" + std::to_string(inflationWindow);
216
- }
217
- }
219
+ /* Whatever we have now, write */
220
+ if (inflationWindow < 15) {
221
+ if (!inflationWindow || !ep.clientMaxWindowBits) {
222
+ response += "; client_no_context_takeover";
223
+ inflationWindow = 0;
224
+ } else {
225
+ response +=
226
+ "; client_max_window_bits=" + std::to_string(inflationWindow);
227
+ }
228
+ }
218
229
 
219
- /* This block basically lets the client lower it */
220
- if (ep.serverNoContextTakeover) {
221
- /* This is an important (temporary) fix since we haven't allowed
222
- * these two modes to mix, and pub/sub will not handle this case (yet) */
230
+ /* This block basically lets the client lower it */
231
+ if (ep.serverNoContextTakeover) {
232
+ /* This is an important (temporary) fix since we haven't allowed
233
+ * these two modes to mix, and pub/sub will not handle this case (yet) */
223
234
  #ifdef UWS_ALLOW_SHARED_AND_DEDICATED_COMPRESSOR_MIX
224
- compressionWindow = 0;
235
+ compressionWindow = 0;
225
236
  #endif
226
- } else if (ep.serverMaxWindowBits) {
227
- compressionWindow = std::min<int>(ep.serverMaxWindowBits, compressionWindow);
237
+ } else if (ep.serverMaxWindowBits) {
238
+ compressionWindow =
239
+ std::min<int>(ep.serverMaxWindowBits, compressionWindow);
228
240
  #ifndef UWS_ALLOW_8_WINDOW_BITS
229
- /* Zlib cannot do windowBits=8, memLevel=1 so we raise it up to 9 minimum */
230
- if (compressionWindow == 8) {
231
- compressionWindow = 9;
232
- }
241
+ /* Zlib cannot do windowBits=8, memLevel=1 so we raise it up to 9 minimum
242
+ */
243
+ if (compressionWindow == 8) {
244
+ compressionWindow = 9;
245
+ }
233
246
  #endif
234
- }
235
-
236
- /* Whatever we have now, write */
237
- if (compressionWindow < 15) {
238
- if (!compressionWindow) {
239
- response += "; server_no_context_takeover";
240
- } else {
241
- response += "; server_max_window_bits=" + std::to_string(compressionWindow);
242
- }
243
- }
244
247
  }
245
248
 
246
- /* A final sanity check (this check does not actually catch too high values!) */
247
- if ((compressionWindow && compressionWindow < 8) || compressionWindow > 15 || (inflationWindow && inflationWindow < 8) || inflationWindow > 15) {
248
- return {false, 0, 0, ""};
249
+ /* Whatever we have now, write */
250
+ if (compressionWindow < 15) {
251
+ if (!compressionWindow) {
252
+ response += "; server_no_context_takeover";
253
+ } else {
254
+ response +=
255
+ "; server_max_window_bits=" + std::to_string(compressionWindow);
256
+ }
249
257
  }
258
+ }
250
259
 
251
- return {compression, compressionWindow, inflationWindow, response};
252
- }
260
+ /* A final sanity check (this check does not actually catch too high values!)
261
+ */
262
+ if ((compressionWindow && compressionWindow < 8) || compressionWindow > 15 ||
263
+ (inflationWindow && inflationWindow < 8) || inflationWindow > 15) {
264
+ return {false, 0, 0, ""};
265
+ }
253
266
 
267
+ return {compression, compressionWindow, inflationWindow, response};
254
268
  }
255
269
 
270
+ } // namespace uWS
271
+
256
272
  #endif // UWS_WEBSOCKETEXTENSIONS_H