@@ -263,21 +263,31 @@ class FakeStream : public Http::RequestDecoder,
263
263
264
264
protected:
265
265
absl::Mutex lock_;
266
- // headers get updated in decodeHeaders() and accessed in headers() methods. Those methods can
267
- // be called from different threads, but we can rely on a few assumptions here :
266
+ // Headers get updated in decodeHeaders() and accessed in headers() methods. Those methods can
267
+ // be called from different threads, but we can rely on a few assumptions:
268
268
//
269
269
// 1. headers() method is only called from a single thread, which may or may not be different
270
- // from the thread that calls decodeHeaders
270
+ // from the thread that calls decodeHeaders()
271
271
// 2. headers can only be replaced completely - they are never modified in place.
272
272
//
273
273
// With those two assumptions, we can use a synchronization pattern with two header maps, that
274
274
// allows us to return an unprotected reference to the clients from the headers() method. The
275
- // reason why we want to return an unprotected reference is because historically that's what the
276
- // interface of the FakeStream was, and over time we accumulated quite a few tests that rely on
277
- // that.
275
+ // approach works as follows:
278
276
//
279
- // With that in mind we made a decision to preserve the interface and avoid migrating multiple
280
- // tests to a new interface when we addressed Clang thread sanitizer warnings.
277
+ // 1. When headers are updated in decodeHeaders(), we store them in the internal headers_ map
278
+ // 2. When headers() is called, we check if the internal headers_ and external client_headers_
279
+ // map point to different places, and if so, we update client_headers_ map to point to the
280
+ // same map as internal headers_.
281
+ //
282
+ // Because both internal headers_ and client_headers_ are shared pointers, the map will stay
283
+ // around as long as at least one of those pointers keeps a reference to the map and thus
284
+ // the returned reference stay valid as well. And because headers() is only called from a single
285
+ // thread, it's safe to return a reference to client_headers_ from headers() call.
286
+ //
287
+ // The reason why we want to return an unprotected reference is because historically that's what
288
+ // the interface of the FakeStream::headers() was, and over time we accumulated quite a few tests
289
+ // that rely on that. Changing the interface would require updating all the tests and we decided
290
+ // not to do that.
281
291
//
282
292
// That's why we have both headers_ and client_headers_ map below.
283
293
Http::RequestHeaderMapSharedPtr headers_ ABSL_GUARDED_BY (lock_);
@@ -286,6 +296,8 @@ class FakeStream : public Http::RequestDecoder,
286
296
287
297
private:
288
298
Http::ResponseEncoder& encoder_;
299
+ // See the comment for headers_ above that explains why we need both headers_ and
300
+ // client_headers_.
289
301
Http::RequestHeaderMapSharedPtr client_headers_;
290
302
Http::RequestTrailerMapSharedPtr trailers_ ABSL_GUARDED_BY (lock_);
291
303
bool end_stream_ ABSL_GUARDED_BY (lock_){};
0 commit comments