1
use crate::EnvoyHttpFilter;
2

            
3
fn get_body_content<EHF: EnvoyHttpFilter>(envoy_filter: &mut EHF, request: bool) -> Vec<u8> {
4
  // If the received body is the same as the buffered body (a previous filter did StopAndBuffer
5
  // and resumed), skip the received body to avoid duplicating data.
6
  let is_buffered = if request {
7
    envoy_filter.received_buffered_request_body()
8
  } else {
9
    envoy_filter.received_buffered_response_body()
10
  };
11

            
12
  let buffered_size = if request {
13
    envoy_filter.get_buffered_request_body_size()
14
  } else {
15
    envoy_filter.get_buffered_response_body_size()
16
  };
17

            
18
  let received_size = if is_buffered {
19
    0
20
  } else if request {
21
    envoy_filter.get_received_request_body_size()
22
  } else {
23
    envoy_filter.get_received_response_body_size()
24
  };
25

            
26
  let mut result = Vec::with_capacity(buffered_size + received_size);
27

            
28
  let buffered = if request {
29
    envoy_filter.get_buffered_request_body()
30
  } else {
31
    envoy_filter.get_buffered_response_body()
32
  };
33
  if let Some(chunks) = buffered {
34
    for chunk in &chunks {
35
      result.extend_from_slice(chunk.as_slice());
36
    }
37
  }
38

            
39
  if !is_buffered {
40
    let received = if request {
41
      envoy_filter.get_received_request_body()
42
    } else {
43
      envoy_filter.get_received_response_body()
44
    };
45
    if let Some(chunks) = received {
46
      for chunk in &chunks {
47
        result.extend_from_slice(chunk.as_slice());
48
      }
49
    }
50
  }
51

            
52
  result
53
}
54

            
55
/// Reads the whole request body by combining the buffered body and the latest received body.
56
/// This will copy all request body content into a module owned `Vec<u8>`.
57
///
58
/// This should only be called after we see the end of the request, which means the
59
/// `end_of_stream` flag is true in the `on_request_body` callback or we are in the
60
/// `on_request_trailers` callback.
61
pub fn read_whole_request_body<EHF: EnvoyHttpFilter>(envoy_filter: &mut EHF) -> Vec<u8> {
62
  get_body_content(envoy_filter, true)
63
}
64

            
65
/// Reads the whole response body by combining the buffered body and the latest received body.
66
/// This will copy all response body content into a module owned `Vec<u8>`.
67
///
68
/// This should only be called after we see the end of the response, which means the
69
/// `end_of_stream` flag is true in the `on_response_body` callback or we are in the
70
/// `on_response_trailers` callback.
71
pub fn read_whole_response_body<EHF: EnvoyHttpFilter>(envoy_filter: &mut EHF) -> Vec<u8> {
72
  get_body_content(envoy_filter, false)
73
}
74

            
75
pub(crate) struct HeaderPairSlice(
76
  pub(crate) *const crate::abi::envoy_dynamic_module_type_module_http_header,
77
  pub(crate) usize,
78
);
79

            
80
const _: () = {
81
  type HeaderPair<'a> = (&'a str, &'a [u8]);
82
  assert!(
83
    std::mem::size_of::<HeaderPair>()
84
      == std::mem::size_of::<crate::abi::envoy_dynamic_module_type_module_http_header>()
85
  );
86
  assert!(
87
    std::mem::align_of::<HeaderPair>()
88
      == std::mem::align_of::<crate::abi::envoy_dynamic_module_type_module_http_header>()
89
  );
90

            
91
  assert!(
92
    std::mem::offset_of!(HeaderPair, 0)
93
      == std::mem::offset_of!(
94
        crate::abi::envoy_dynamic_module_type_module_http_header,
95
        key_ptr
96
      )
97
  );
98
  assert!(
99
    std::mem::offset_of!(HeaderPair, 1)
100
      == std::mem::offset_of!(
101
        crate::abi::envoy_dynamic_module_type_module_http_header,
102
        value_ptr
103
      )
104
  );
105
};
106

            
107
impl<'a> From<&[(&'a str, &'a [u8])]> for HeaderPairSlice {
108
  fn from(headers: &[(&'a str, &'a [u8])]) -> Self {
109
    // Note: Casting a (&str, &[u8]) to an abi::envoy_dynamic_module_type_module_http_header works
110
    // not because of any formal layout guarantees but because:
111
    // 1) tuples _in practice_ are laid out packed and in order
112
    // 2) &str and &[u8] are fat pointers (pointers to DSTs), whose layouts _in practice_ are a
113
    //    pointer and length
114
    // If these assumptions change, this will break, so we assert on them here in debug builds.
115
    type HeaderPair<'a> = (&'a str, &'a [u8]);
116

            
117
    debug_assert!({
118
      let pair: HeaderPair<'_> = ("test", b"value");
119
      let constructed = crate::abi::envoy_dynamic_module_type_module_http_header {
120
        key_ptr: pair.0.as_ptr() as *const _,
121
        key_length: pair.0.len(),
122
        value_ptr: pair.1.as_ptr() as *const _,
123
        value_length: pair.1.len(),
124
      };
125
      let punned = unsafe {
126
        std::mem::transmute::<HeaderPair, crate::abi::envoy_dynamic_module_type_module_http_header>(
127
          pair,
128
        )
129
      };
130
      constructed == punned
131
    });
132

            
133
    let ptr = headers.as_ptr() as *const crate::abi::envoy_dynamic_module_type_module_http_header;
134
    HeaderPairSlice(ptr, headers.len())
135
  }
136
}
137

            
138
#[cfg(test)]
139
#[allow(static_mut_refs)]
140
mod tests {
141
  use super::*;
142
  use crate::{EnvoyMutBuffer, MockEnvoyHttpFilter};
143

            
144
  #[test]
145
  fn test_read_whole_request_body_received_is_buffered() {
146
    // When received_buffered_request_body() returns true (previous filter did StopAndBuffer and
147
    // resumed), only the buffered body should be read to avoid duplicating data.
148
    static mut BUFFER: [u8; 11] = *b"hello world";
149
    let mut mock = MockEnvoyHttpFilter::default();
150
    mock
151
      .expect_received_buffered_request_body()
152
      .times(1)
153
      .returning(|| true);
154
    mock
155
      .expect_get_buffered_request_body_size()
156
      .times(1)
157
      .returning(|| 11);
158
    mock
159
      .expect_get_buffered_request_body()
160
      .times(1)
161
      .returning(|| Some(vec![unsafe { EnvoyMutBuffer::new(&raw mut BUFFER) }]));
162
    // get_received_request_body_size and get_received_request_body should NOT be called.
163

            
164
    assert_eq!(read_whole_request_body(&mut mock), b"hello world");
165
  }
166

            
167
  #[test]
168
  fn test_read_whole_request_body_different_chunks() {
169
    // When received_buffered_request_body() returns false, both buffered and received are combined.
170
    static mut BUFFERED: [u8; 6] = *b"hello ";
171
    static mut RECEIVED: [u8; 5] = *b"world";
172
    let mut mock = MockEnvoyHttpFilter::default();
173
    mock
174
      .expect_received_buffered_request_body()
175
      .times(1)
176
      .returning(|| false);
177
    mock
178
      .expect_get_buffered_request_body_size()
179
      .times(1)
180
      .returning(|| 6);
181
    mock
182
      .expect_get_received_request_body_size()
183
      .times(1)
184
      .returning(|| 5);
185
    mock
186
      .expect_get_buffered_request_body()
187
      .times(1)
188
      .returning(|| Some(vec![unsafe { EnvoyMutBuffer::new(&raw mut BUFFERED) }]));
189
    mock
190
      .expect_get_received_request_body()
191
      .times(1)
192
      .returning(|| Some(vec![unsafe { EnvoyMutBuffer::new(&raw mut RECEIVED) }]));
193

            
194
    assert_eq!(read_whole_request_body(&mut mock), b"hello world");
195
  }
196

            
197
  #[test]
198
  fn test_read_whole_request_body_empty_buffered() {
199
    // When buffered body is empty (None) and not the same, result equals the received body.
200
    static mut RECEIVED: [u8; 5] = *b"world";
201
    let mut mock = MockEnvoyHttpFilter::default();
202
    mock
203
      .expect_received_buffered_request_body()
204
      .times(1)
205
      .returning(|| false);
206
    mock
207
      .expect_get_buffered_request_body_size()
208
      .times(1)
209
      .returning(|| 0);
210
    mock
211
      .expect_get_received_request_body_size()
212
      .times(1)
213
      .returning(|| 5);
214
    mock
215
      .expect_get_buffered_request_body()
216
      .times(1)
217
      .returning(|| None);
218
    mock
219
      .expect_get_received_request_body()
220
      .times(1)
221
      .returning(|| Some(vec![unsafe { EnvoyMutBuffer::new(&raw mut RECEIVED) }]));
222

            
223
    assert_eq!(read_whole_request_body(&mut mock), b"world");
224
  }
225

            
226
  #[test]
227
  fn test_read_whole_response_body_received_is_buffered() {
228
    // When received_buffered_response_body() returns true, only the buffered body should be read.
229
    static mut BUFFER: [u8; 11] = *b"hello world";
230
    let mut mock = MockEnvoyHttpFilter::default();
231
    mock
232
      .expect_received_buffered_response_body()
233
      .times(1)
234
      .returning(|| true);
235
    mock
236
      .expect_get_buffered_response_body_size()
237
      .times(1)
238
      .returning(|| 11);
239
    mock
240
      .expect_get_buffered_response_body()
241
      .times(1)
242
      .returning(|| Some(vec![unsafe { EnvoyMutBuffer::new(&raw mut BUFFER) }]));
243
    // get_received_response_body_size and get_received_response_body should NOT be called.
244

            
245
    assert_eq!(read_whole_response_body(&mut mock), b"hello world");
246
  }
247

            
248
  #[test]
249
  fn test_read_whole_response_body_different_chunks() {
250
    // When received_buffered_response_body() returns false, both buffered and received are
251
    // combined.
252
    static mut BUFFERED: [u8; 6] = *b"hello ";
253
    static mut RECEIVED: [u8; 5] = *b"world";
254
    let mut mock = MockEnvoyHttpFilter::default();
255
    mock
256
      .expect_received_buffered_response_body()
257
      .times(1)
258
      .returning(|| false);
259
    mock
260
      .expect_get_buffered_response_body_size()
261
      .times(1)
262
      .returning(|| 6);
263
    mock
264
      .expect_get_received_response_body_size()
265
      .times(1)
266
      .returning(|| 5);
267
    mock
268
      .expect_get_buffered_response_body()
269
      .times(1)
270
      .returning(|| Some(vec![unsafe { EnvoyMutBuffer::new(&raw mut BUFFERED) }]));
271
    mock
272
      .expect_get_received_response_body()
273
      .times(1)
274
      .returning(|| Some(vec![unsafe { EnvoyMutBuffer::new(&raw mut RECEIVED) }]));
275

            
276
    assert_eq!(read_whole_response_body(&mut mock), b"hello world");
277
  }
278

            
279
  #[test]
280
  fn test_read_whole_response_body_empty_buffered() {
281
    // When buffered body is empty (None) and not the same, result equals the received body.
282
    static mut RECEIVED: [u8; 5] = *b"world";
283
    let mut mock = MockEnvoyHttpFilter::default();
284
    mock
285
      .expect_received_buffered_response_body()
286
      .times(1)
287
      .returning(|| false);
288
    mock
289
      .expect_get_buffered_response_body_size()
290
      .times(1)
291
      .returning(|| 0);
292
    mock
293
      .expect_get_received_response_body_size()
294
      .times(1)
295
      .returning(|| 5);
296
    mock
297
      .expect_get_buffered_response_body()
298
      .times(1)
299
      .returning(|| None);
300
    mock
301
      .expect_get_received_response_body()
302
      .times(1)
303
      .returning(|| Some(vec![unsafe { EnvoyMutBuffer::new(&raw mut RECEIVED) }]));
304

            
305
    assert_eq!(read_whole_response_body(&mut mock), b"world");
306
  }
307
}