Coverage Report

Created: 2026-04-29 06:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/uWebSockets/src/WebSocketExtensions.h
Line
Count
Source
1
/*
2
 * Authored by Alex Hultman, 2018-2021.
3
 * Intellectual property of third-party.
4
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
9
 *     http://www.apache.org/licenses/LICENSE-2.0
10
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
18
#ifndef UWS_WEBSOCKETEXTENSIONS_H
19
#define UWS_WEBSOCKETEXTENSIONS_H
20
21
/* There is a new, huge bug scenario that needs to be fixed:
22
 * pub/sub does not support being in DEDICATED_COMPRESSOR-mode while having
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 */
25
// #define UWS_ALLOW_SHARED_AND_DEDICATED_COMPRESSOR_MIX
26
27
/* We forbid negotiating 8 windowBits since Zlib has a bug with this */
28
// #define UWS_ALLOW_8_WINDOW_BITS
29
30
#include <climits>
31
#include <cctype>
32
#include <string>
33
#include <string_view>
34
#include <tuple>
35
36
namespace uWS {
37
38
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
49
50
};
51
52
struct ExtensionsParser {
53
private:
54
    int *lastInteger = nullptr;
55
56
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
66.1k
    int getToken(const char *&in, const char *stop) {
70
142k
        while (in != stop && !isalnum(*in)) {
71
76.5k
            in++;
72
76.5k
        }
73
74
        /* Don't care more than this for now */
75
66.1k
        static_assert(SHRT_MIN > INT_MIN, "Integer overflow fix is invalid for this platform, report this as a bug!");
76
77
66.1k
        int hashedToken = 0;
78
6.87M
        while (in != stop && (isalnum(*in) || *in == '-' || *in == '_')) {
79
6.81M
            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
38.8k
                if (hashedToken > SHRT_MIN && hashedToken < SHRT_MAX) {
83
35.5k
                    hashedToken = hashedToken * 10 - (*in - '0');
84
35.5k
                }
85
6.77M
            } else {
86
6.77M
                hashedToken += *in;
87
6.77M
            }
88
6.81M
            in++;
89
6.81M
        }
90
66.1k
        return hashedToken;
91
66.1k
    }
92
93
13.4k
    ExtensionsParser(const char *data, size_t length) {
94
13.4k
        const char *stop = data + length;
95
13.4k
        int token = 1;
96
97
        /* Ignore anything before permessage-deflate or x-webkit-deflate-frame */
98
36.9k
        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
13.4k
        perMessageDeflate = (token == TOK_PERMESSAGE_DEFLATE);
102
13.4k
        xWebKitDeflateFrame = (token == TOK_X_WEBKIT_DEFLATE_FRAME);
103
104
42.7k
        while ((token = getToken(data, stop))) {
105
32.1k
            switch (token) {
106
620
            case TOK_X_WEBKIT_DEFLATE_FRAME:
107
                /* Duplicates not allowed/supported */
108
620
                return;
109
1.43k
            case TOK_NO_CONTEXT_TAKEOVER:
110
1.43k
                noContextTakeover = true;
111
1.43k
                break;
112
1.65k
            case TOK_MAX_WINDOW_BITS:
113
1.65k
                maxWindowBits = 1;
114
1.65k
                lastInteger = &maxWindowBits;
115
1.65k
                break;
116
2.35k
            case TOK_PERMESSAGE_DEFLATE:
117
                /* Duplicates not allowed/supported */
118
2.35k
                return;
119
959
            case TOK_SERVER_NO_CONTEXT_TAKEOVER:
120
959
                serverNoContextTakeover = true;
121
959
                break;
122
851
            case TOK_CLIENT_NO_CONTEXT_TAKEOVER:
123
851
                clientNoContextTakeover = true;
124
851
                break;
125
1.99k
            case TOK_SERVER_MAX_WINDOW_BITS:
126
1.99k
                serverMaxWindowBits = 1;
127
1.99k
                lastInteger = &serverMaxWindowBits;
128
1.99k
                break;
129
1.82k
            case TOK_CLIENT_MAX_WINDOW_BITS:
130
1.82k
                clientMaxWindowBits = 1;
131
1.82k
                lastInteger = &clientMaxWindowBits;
132
1.82k
                break;
133
20.4k
            default:
134
20.4k
                if (token < 0 && lastInteger) {
135
4.23k
                    *lastInteger = -token;
136
4.23k
                }
137
20.4k
                break;
138
32.1k
            }
139
32.1k
        }
140
13.4k
    }
141
};
142
143
/* Takes what we (the server) wants, returns what we got */
144
14.1k
static inline std::tuple<bool, int, int, std::string_view> negotiateCompression(bool wantCompression, int wantedCompressionWindow, int wantedInflationWindow, std::string_view offer) {
145
146
    /* If we don't want compression then we are done here */
147
14.1k
    if (!wantCompression) {
148
678
        return {false, 0, 0, ""};
149
678
    }
150
151
13.4k
    ExtensionsParser ep(offer.data(), offer.length());
152
153
13.4k
    static thread_local std::string response;
154
13.4k
    response = "";
155
156
13.4k
    int compressionWindow = wantedCompressionWindow;
157
13.4k
    int inflationWindow = wantedInflationWindow;
158
13.4k
    bool compression = false;
159
160
13.4k
    if (ep.xWebKitDeflateFrame) {
161
        /* We now have compression */
162
2.53k
        compression = true;
163
2.53k
        response = "x-webkit-deflate-frame";
164
165
        /* If the other peer has DEMANDED us no sliding window,
166
         * we cannot compress with anything other than shared compressor */
167
2.53k
        if (ep.noContextTakeover) {
168
            /* We must fail here right now (fix pub/sub) */
169
986
#ifndef UWS_ALLOW_SHARED_AND_DEDICATED_COMPRESSOR_MIX
170
986
            if (wantedCompressionWindow != 0) {
171
368
                return {false, 0, 0, ""};
172
368
            }
173
618
#endif
174
175
618
            compressionWindow = 0;
176
618
        }
177
178
        /* If the other peer has DEMANDED us to use a limited sliding window,
179
         * we have to limit out compression sliding window */
180
2.16k
        if (ep.maxWindowBits && ep.maxWindowBits < compressionWindow) {
181
540
            compressionWindow = ep.maxWindowBits;
182
540
#ifndef UWS_ALLOW_8_WINDOW_BITS
183
            /* We cannot really deny this, so we have to disable compression in this case */
184
540
            if (compressionWindow == 8) {
185
267
                return {false, 0, 0, ""};
186
267
            }
187
540
#endif
188
540
        }
189
190
        /* We decide our own inflation sliding window (and their compression sliding window) */
191
1.89k
        if (wantedInflationWindow < 15) {
192
1.89k
            if (!wantedInflationWindow) {
193
1.89k
                response += "; no_context_takeover";
194
1.89k
            } else {
195
0
                response += "; max_window_bits=" + std::to_string(wantedInflationWindow);
196
0
            }
197
1.89k
        }
198
10.9k
    } else if (ep.perMessageDeflate) {
199
        /* We now have compression */
200
4.79k
        compression = true;
201
4.79k
        response = "permessage-deflate";
202
203
4.79k
        if (ep.clientNoContextTakeover) {
204
398
            inflationWindow = 0;
205
4.39k
        } else if (ep.clientMaxWindowBits && ep.clientMaxWindowBits != 1) {
206
783
            inflationWindow = std::min<int>(ep.clientMaxWindowBits, inflationWindow);
207
783
        }
208
209
        /* Whatever we have now, write */
210
4.79k
        if (inflationWindow < 15) {
211
4.79k
            if (!inflationWindow || !ep.clientMaxWindowBits) {
212
4.79k
                response += "; client_no_context_takeover";
213
4.79k
                inflationWindow = 0;
214
4.79k
            } else {
215
0
                response += "; client_max_window_bits=" + std::to_string(inflationWindow);
216
0
            }
217
4.79k
        }
218
219
        /* This block basically lets the client lower it */
220
4.79k
        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) */
223
#ifdef UWS_ALLOW_SHARED_AND_DEDICATED_COMPRESSOR_MIX
224
            compressionWindow = 0;
225
#endif
226
4.36k
        } else if (ep.serverMaxWindowBits) {
227
1.39k
            compressionWindow = std::min<int>(ep.serverMaxWindowBits, compressionWindow);
228
1.39k
#ifndef UWS_ALLOW_8_WINDOW_BITS
229
            /* Zlib cannot do windowBits=8, memLevel=1 so we raise it up to 9 minimum */
230
1.39k
            if (compressionWindow == 8) {
231
587
                compressionWindow = 9;
232
587
            }
233
1.39k
#endif
234
1.39k
        }
235
236
        /* Whatever we have now, write */
237
4.79k
        if (compressionWindow < 15) {
238
4.43k
            if (!compressionWindow) {
239
2.73k
                response += "; server_no_context_takeover";
240
2.73k
            } else {
241
1.69k
                response += "; server_max_window_bits=" + std::to_string(compressionWindow);
242
1.69k
            }
243
4.43k
        }
244
4.79k
    }
245
246
    /* A final sanity check (this check does not actually catch too high values!) */
247
12.8k
    if ((compressionWindow && compressionWindow < 8) || compressionWindow > 15 || (inflationWindow && inflationWindow < 8) || inflationWindow > 15) {
248
323
        return {false, 0, 0, ""};
249
323
    }
250
251
12.5k
    return {compression, compressionWindow, inflationWindow, response};
252
12.8k
}
Extensions.cpp:uWS::negotiateCompression(bool, int, int, std::__1::basic_string_view<char, std::__1::char_traits<char> >)
Line
Count
Source
144
2.03k
static inline std::tuple<bool, int, int, std::string_view> negotiateCompression(bool wantCompression, int wantedCompressionWindow, int wantedInflationWindow, std::string_view offer) {
145
146
    /* If we don't want compression then we are done here */
147
2.03k
    if (!wantCompression) {
148
678
        return {false, 0, 0, ""};
149
678
    }
150
151
1.35k
    ExtensionsParser ep(offer.data(), offer.length());
152
153
1.35k
    static thread_local std::string response;
154
1.35k
    response = "";
155
156
1.35k
    int compressionWindow = wantedCompressionWindow;
157
1.35k
    int inflationWindow = wantedInflationWindow;
158
1.35k
    bool compression = false;
159
160
1.35k
    if (ep.xWebKitDeflateFrame) {
161
        /* We now have compression */
162
70
        compression = true;
163
70
        response = "x-webkit-deflate-frame";
164
165
        /* If the other peer has DEMANDED us no sliding window,
166
         * we cannot compress with anything other than shared compressor */
167
70
        if (ep.noContextTakeover) {
168
            /* We must fail here right now (fix pub/sub) */
169
2
#ifndef UWS_ALLOW_SHARED_AND_DEDICATED_COMPRESSOR_MIX
170
2
            if (wantedCompressionWindow != 0) {
171
1
                return {false, 0, 0, ""};
172
1
            }
173
1
#endif
174
175
1
            compressionWindow = 0;
176
1
        }
177
178
        /* If the other peer has DEMANDED us to use a limited sliding window,
179
         * we have to limit out compression sliding window */
180
69
        if (ep.maxWindowBits && ep.maxWindowBits < compressionWindow) {
181
8
            compressionWindow = ep.maxWindowBits;
182
8
#ifndef UWS_ALLOW_8_WINDOW_BITS
183
            /* We cannot really deny this, so we have to disable compression in this case */
184
8
            if (compressionWindow == 8) {
185
1
                return {false, 0, 0, ""};
186
1
            }
187
8
#endif
188
8
        }
189
190
        /* We decide our own inflation sliding window (and their compression sliding window) */
191
68
        if (wantedInflationWindow < 15) {
192
68
            if (!wantedInflationWindow) {
193
68
                response += "; no_context_takeover";
194
68
            } else {
195
0
                response += "; max_window_bits=" + std::to_string(wantedInflationWindow);
196
0
            }
197
68
        }
198
1.28k
    } else if (ep.perMessageDeflate) {
199
        /* We now have compression */
200
112
        compression = true;
201
112
        response = "permessage-deflate";
202
203
112
        if (ep.clientNoContextTakeover) {
204
2
            inflationWindow = 0;
205
110
        } else if (ep.clientMaxWindowBits && ep.clientMaxWindowBits != 1) {
206
52
            inflationWindow = std::min<int>(ep.clientMaxWindowBits, inflationWindow);
207
52
        }
208
209
        /* Whatever we have now, write */
210
112
        if (inflationWindow < 15) {
211
112
            if (!inflationWindow || !ep.clientMaxWindowBits) {
212
112
                response += "; client_no_context_takeover";
213
112
                inflationWindow = 0;
214
112
            } else {
215
0
                response += "; client_max_window_bits=" + std::to_string(inflationWindow);
216
0
            }
217
112
        }
218
219
        /* This block basically lets the client lower it */
220
112
        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) */
223
#ifdef UWS_ALLOW_SHARED_AND_DEDICATED_COMPRESSOR_MIX
224
            compressionWindow = 0;
225
#endif
226
110
        } else if (ep.serverMaxWindowBits) {
227
52
            compressionWindow = std::min<int>(ep.serverMaxWindowBits, compressionWindow);
228
52
#ifndef UWS_ALLOW_8_WINDOW_BITS
229
            /* Zlib cannot do windowBits=8, memLevel=1 so we raise it up to 9 minimum */
230
52
            if (compressionWindow == 8) {
231
1
                compressionWindow = 9;
232
1
            }
233
52
#endif
234
52
        }
235
236
        /* Whatever we have now, write */
237
112
        if (compressionWindow < 15) {
238
112
            if (!compressionWindow) {
239
56
                response += "; server_no_context_takeover";
240
56
            } else {
241
56
                response += "; server_max_window_bits=" + std::to_string(compressionWindow);
242
56
            }
243
112
        }
244
112
    }
245
246
    /* A final sanity check (this check does not actually catch too high values!) */
247
1.35k
    if ((compressionWindow && compressionWindow < 8) || compressionWindow > 15 || (inflationWindow && inflationWindow < 8) || inflationWindow > 15) {
248
8
        return {false, 0, 0, ""};
249
8
    }
250
251
1.34k
    return {compression, compressionWindow, inflationWindow, response};
252
1.35k
}
Unexecuted instantiation: EpollEchoServerPubSub.cpp:uWS::negotiateCompression(bool, int, int, std::__1::basic_string_view<char, std::__1::char_traits<char> >)
EpollHelloWorld.cpp:uWS::negotiateCompression(bool, int, int, std::__1::basic_string_view<char, std::__1::char_traits<char> >)
Line
Count
Source
144
6.08k
static inline std::tuple<bool, int, int, std::string_view> negotiateCompression(bool wantCompression, int wantedCompressionWindow, int wantedInflationWindow, std::string_view offer) {
145
146
    /* If we don't want compression then we are done here */
147
6.08k
    if (!wantCompression) {
148
0
        return {false, 0, 0, ""};
149
0
    }
150
151
6.08k
    ExtensionsParser ep(offer.data(), offer.length());
152
153
6.08k
    static thread_local std::string response;
154
6.08k
    response = "";
155
156
6.08k
    int compressionWindow = wantedCompressionWindow;
157
6.08k
    int inflationWindow = wantedInflationWindow;
158
6.08k
    bool compression = false;
159
160
6.08k
    if (ep.xWebKitDeflateFrame) {
161
        /* We now have compression */
162
669
        compression = true;
163
669
        response = "x-webkit-deflate-frame";
164
165
        /* If the other peer has DEMANDED us no sliding window,
166
         * we cannot compress with anything other than shared compressor */
167
669
        if (ep.noContextTakeover) {
168
            /* We must fail here right now (fix pub/sub) */
169
319
#ifndef UWS_ALLOW_SHARED_AND_DEDICATED_COMPRESSOR_MIX
170
319
            if (wantedCompressionWindow != 0) {
171
0
                return {false, 0, 0, ""};
172
0
            }
173
319
#endif
174
175
319
            compressionWindow = 0;
176
319
        }
177
178
        /* If the other peer has DEMANDED us to use a limited sliding window,
179
         * we have to limit out compression sliding window */
180
669
        if (ep.maxWindowBits && ep.maxWindowBits < compressionWindow) {
181
0
            compressionWindow = ep.maxWindowBits;
182
0
#ifndef UWS_ALLOW_8_WINDOW_BITS
183
            /* We cannot really deny this, so we have to disable compression in this case */
184
0
            if (compressionWindow == 8) {
185
0
                return {false, 0, 0, ""};
186
0
            }
187
0
#endif
188
0
        }
189
190
        /* We decide our own inflation sliding window (and their compression sliding window) */
191
669
        if (wantedInflationWindow < 15) {
192
669
            if (!wantedInflationWindow) {
193
669
                response += "; no_context_takeover";
194
669
            } else {
195
0
                response += "; max_window_bits=" + std::to_string(wantedInflationWindow);
196
0
            }
197
669
        }
198
5.41k
    } else if (ep.perMessageDeflate) {
199
        /* We now have compression */
200
1.80k
        compression = true;
201
1.80k
        response = "permessage-deflate";
202
203
1.80k
        if (ep.clientNoContextTakeover) {
204
200
            inflationWindow = 0;
205
1.60k
        } else if (ep.clientMaxWindowBits && ep.clientMaxWindowBits != 1) {
206
431
            inflationWindow = std::min<int>(ep.clientMaxWindowBits, inflationWindow);
207
431
        }
208
209
        /* Whatever we have now, write */
210
1.80k
        if (inflationWindow < 15) {
211
1.80k
            if (!inflationWindow || !ep.clientMaxWindowBits) {
212
1.80k
                response += "; client_no_context_takeover";
213
1.80k
                inflationWindow = 0;
214
1.80k
            } else {
215
0
                response += "; client_max_window_bits=" + std::to_string(inflationWindow);
216
0
            }
217
1.80k
        }
218
219
        /* This block basically lets the client lower it */
220
1.80k
        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) */
223
#ifdef UWS_ALLOW_SHARED_AND_DEDICATED_COMPRESSOR_MIX
224
            compressionWindow = 0;
225
#endif
226
1.60k
        } else if (ep.serverMaxWindowBits) {
227
407
            compressionWindow = std::min<int>(ep.serverMaxWindowBits, compressionWindow);
228
407
#ifndef UWS_ALLOW_8_WINDOW_BITS
229
            /* Zlib cannot do windowBits=8, memLevel=1 so we raise it up to 9 minimum */
230
407
            if (compressionWindow == 8) {
231
0
                compressionWindow = 9;
232
0
            }
233
407
#endif
234
407
        }
235
236
        /* Whatever we have now, write */
237
1.80k
        if (compressionWindow < 15) {
238
1.80k
            if (!compressionWindow) {
239
1.80k
                response += "; server_no_context_takeover";
240
1.80k
            } else {
241
0
                response += "; server_max_window_bits=" + std::to_string(compressionWindow);
242
0
            }
243
1.80k
        }
244
1.80k
    }
245
246
    /* A final sanity check (this check does not actually catch too high values!) */
247
6.08k
    if ((compressionWindow && compressionWindow < 8) || compressionWindow > 15 || (inflationWindow && inflationWindow < 8) || inflationWindow > 15) {
248
0
        return {false, 0, 0, ""};
249
0
    }
250
251
6.08k
    return {compression, compressionWindow, inflationWindow, response};
252
6.08k
}
EpollEchoServer.cpp:uWS::negotiateCompression(bool, int, int, std::__1::basic_string_view<char, std::__1::char_traits<char> >)
Line
Count
Source
144
6.05k
static inline std::tuple<bool, int, int, std::string_view> negotiateCompression(bool wantCompression, int wantedCompressionWindow, int wantedInflationWindow, std::string_view offer) {
145
146
    /* If we don't want compression then we are done here */
147
6.05k
    if (!wantCompression) {
148
0
        return {false, 0, 0, ""};
149
0
    }
150
151
6.05k
    ExtensionsParser ep(offer.data(), offer.length());
152
153
6.05k
    static thread_local std::string response;
154
6.05k
    response = "";
155
156
6.05k
    int compressionWindow = wantedCompressionWindow;
157
6.05k
    int inflationWindow = wantedInflationWindow;
158
6.05k
    bool compression = false;
159
160
6.05k
    if (ep.xWebKitDeflateFrame) {
161
        /* We now have compression */
162
1.79k
        compression = true;
163
1.79k
        response = "x-webkit-deflate-frame";
164
165
        /* If the other peer has DEMANDED us no sliding window,
166
         * we cannot compress with anything other than shared compressor */
167
1.79k
        if (ep.noContextTakeover) {
168
            /* We must fail here right now (fix pub/sub) */
169
665
#ifndef UWS_ALLOW_SHARED_AND_DEDICATED_COMPRESSOR_MIX
170
665
            if (wantedCompressionWindow != 0) {
171
367
                return {false, 0, 0, ""};
172
367
            }
173
298
#endif
174
175
298
            compressionWindow = 0;
176
298
        }
177
178
        /* If the other peer has DEMANDED us to use a limited sliding window,
179
         * we have to limit out compression sliding window */
180
1.42k
        if (ep.maxWindowBits && ep.maxWindowBits < compressionWindow) {
181
532
            compressionWindow = ep.maxWindowBits;
182
532
#ifndef UWS_ALLOW_8_WINDOW_BITS
183
            /* We cannot really deny this, so we have to disable compression in this case */
184
532
            if (compressionWindow == 8) {
185
266
                return {false, 0, 0, ""};
186
266
            }
187
532
#endif
188
532
        }
189
190
        /* We decide our own inflation sliding window (and their compression sliding window) */
191
1.16k
        if (wantedInflationWindow < 15) {
192
1.16k
            if (!wantedInflationWindow) {
193
1.16k
                response += "; no_context_takeover";
194
1.16k
            } else {
195
0
                response += "; max_window_bits=" + std::to_string(wantedInflationWindow);
196
0
            }
197
1.16k
        }
198
4.26k
    } else if (ep.perMessageDeflate) {
199
        /* We now have compression */
200
2.88k
        compression = true;
201
2.88k
        response = "permessage-deflate";
202
203
2.88k
        if (ep.clientNoContextTakeover) {
204
196
            inflationWindow = 0;
205
2.68k
        } else if (ep.clientMaxWindowBits && ep.clientMaxWindowBits != 1) {
206
300
            inflationWindow = std::min<int>(ep.clientMaxWindowBits, inflationWindow);
207
300
        }
208
209
        /* Whatever we have now, write */
210
2.88k
        if (inflationWindow < 15) {
211
2.88k
            if (!inflationWindow || !ep.clientMaxWindowBits) {
212
2.88k
                response += "; client_no_context_takeover";
213
2.88k
                inflationWindow = 0;
214
2.88k
            } else {
215
0
                response += "; client_max_window_bits=" + std::to_string(inflationWindow);
216
0
            }
217
2.88k
        }
218
219
        /* This block basically lets the client lower it */
220
2.88k
        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) */
223
#ifdef UWS_ALLOW_SHARED_AND_DEDICATED_COMPRESSOR_MIX
224
            compressionWindow = 0;
225
#endif
226
2.65k
        } else if (ep.serverMaxWindowBits) {
227
938
            compressionWindow = std::min<int>(ep.serverMaxWindowBits, compressionWindow);
228
938
#ifndef UWS_ALLOW_8_WINDOW_BITS
229
            /* Zlib cannot do windowBits=8, memLevel=1 so we raise it up to 9 minimum */
230
938
            if (compressionWindow == 8) {
231
586
                compressionWindow = 9;
232
586
            }
233
938
#endif
234
938
        }
235
236
        /* Whatever we have now, write */
237
2.88k
        if (compressionWindow < 15) {
238
2.51k
            if (!compressionWindow) {
239
881
                response += "; server_no_context_takeover";
240
1.63k
            } else {
241
1.63k
                response += "; server_max_window_bits=" + std::to_string(compressionWindow);
242
1.63k
            }
243
2.51k
        }
244
2.88k
    }
245
246
    /* A final sanity check (this check does not actually catch too high values!) */
247
5.42k
    if ((compressionWindow && compressionWindow < 8) || compressionWindow > 15 || (inflationWindow && inflationWindow < 8) || inflationWindow > 15) {
248
315
        return {false, 0, 0, ""};
249
315
    }
250
251
5.11k
    return {compression, compressionWindow, inflationWindow, response};
252
5.42k
}
Unexecuted instantiation: AsyncEpollHelloWorld.cpp:uWS::negotiateCompression(bool, int, int, std::__1::basic_string_view<char, std::__1::char_traits<char> >)
253
254
}
255
256
#endif // UWS_WEBSOCKETEXTENSIONS_H