opal-up 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -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