@samitouri / QOS-React-1 / commits / 08a39539fc

[Flight][Reply] Close Response after creating root chunk (#27634)

creating the root after closing the response can lead to a promise that never rejects. This is not intended use of the decodeReply API but if pathalogical cases where you pass a raw FormData into this fucntion with no zero chunk it can hang forever. This reordering causes a connection error instead --------- Co-authored-by: Zack Tanner <zacktanner@gmail.com>

Josh Story committed Oct 31, 2023 at 18:31 UTC 08a39539fc6922cdb9e2405029127a1911b1b809
8 files changed +24 -7
packages/react-server-dom-esm/src/ReactFlightDOMServerNode.js
+2 -1
@@ -162,8 +162,9 @@ function decodeReply<T>(
162 body = form;
163 }
164 const response = createResponse(moduleBasePath, '', body);
165 + const root = getRoot<T>(response);
166 close(response);
166 - return getRoot(response);
167 + return root;
168 }
169
170 export {
packages/react-server-dom-turbopack/src/ReactFlightDOMServerBrowser.js
+2 -1
@@ -93,8 +93,9 @@ function decodeReply<T>(
93 body = form;
94 }
95 const response = createResponse(turbopackMap, '', body);
96 + const root = getRoot<T>(response);
97 close(response);
97 - return getRoot(response);
98 + return root;
99 }
100
101 export {renderToReadableStream, decodeReply, decodeAction};
packages/react-server-dom-turbopack/src/ReactFlightDOMServerEdge.js
+2 -1
@@ -93,8 +93,9 @@ function decodeReply<T>(
93 body = form;
94 }
95 const response = createResponse(turbopackMap, '', body);
96 + const root = getRoot<T>(response);
97 close(response);
97 - return getRoot(response);
98 + return root;
99 }
100
101 export {renderToReadableStream, decodeReply, decodeAction};
packages/react-server-dom-turbopack/src/ReactFlightDOMServerNode.js
+2 -1
@@ -158,8 +158,9 @@ function decodeReply<T>(
158 body = form;
159 }
160 const response = createResponse(turbopackMap, '', body);
161 + const root = getRoot<T>(response);
162 close(response);
162 - return getRoot(response);
163 + return root;
164 }
165
166 export {
packages/react-server-dom-webpack/src/ReactFlightDOMServerBrowser.js
+2 -1
@@ -100,8 +100,9 @@ function decodeReply<T>(
100 body = form;
101 }
102 const response = createResponse(webpackMap, '', body);
103 + const root = getRoot<T>(response);
104 close(response);
104 - return getRoot(response);
105 + return root;
106 }
107
108 export {renderToReadableStream, decodeReply, decodeAction, decodeFormState};
packages/react-server-dom-webpack/src/ReactFlightDOMServerEdge.js
+2 -1
@@ -100,8 +100,9 @@ function decodeReply<T>(
100 body = form;
101 }
102 const response = createResponse(webpackMap, '', body);
103 + const root = getRoot<T>(response);
104 close(response);
104 - return getRoot(response);
105 + return root;
106 }
107
108 export {renderToReadableStream, decodeReply, decodeAction, decodeFormState};
packages/react-server-dom-webpack/src/ReactFlightDOMServerNode.js
+2 -1
@@ -181,8 +181,9 @@ function decodeReply<T>(
181 body = form;
182 }
183 const response = createResponse(webpackMap, '', body);
184 + const root = getRoot<T>(response);
185 close(response);
185 - return getRoot(response);
186 + return root;
187 }
188
189 export {
packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMReply-test.js
+10
@@ -231,4 +231,14 @@ describe('ReactFlightDOMReply', () => {
231 expect(s2.has('hi')).toBe(true);
232 expect(s2).toEqual(s);
233 });
234 +
235 + it('does not hang indefinitely when calling decodeReply with FormData', async () => {
236 + let error;
237 + try {
238 + await ReactServerDOMServer.decodeReply(new FormData(), webpackServerMap);
239 + } catch (e) {
240 + error = e;
241 + }
242 + expect(error.message).toBe('Connection closed.');
243 + });
244 });