RequestBodyBuffer

Struct RequestBodyBuffer 

Source
pub struct RequestBodyBuffer { /* private fields */ }
Expand description

An opaque object that represents the underlying Envoy Http request body buffer. This is used to interact with it from the module code. The buffer consists of multiple slices. Each slice is a contiguous memory region.

This corresponds to either a frame of the request body or the whole body.

This is a shallow wrapper around the raw pointer to the Envoy request body buffer.

TODO: implement the std::io::Read trait for this object.

Implementations§

Source§

impl RequestBodyBuffer

Source

pub fn length(&self) -> usize

Returns the number of bytes in the buffer.

Source

pub fn slices_count(&self) -> usize

Returns the number of slices in the buffer.

Source

pub fn slices(&self) -> Vec<&mut [u8]>

Returns the slices of the buffer. The slices are the contiguous memory regions that represent the buffer.

Examples found in repository?
example/example.rs (line 393)
354    fn request_body(
355        &mut self,
356        request_body_frame: &RequestBodyBuffer,
357        end_of_stream: bool,
358    ) -> RequestBodyStatus {
359        println!(
360            "new request body frame: {}",
361            String::from_utf8(request_body_frame.copy()).unwrap()
362        );
363        if !end_of_stream {
364            // Wait for the end of the stream to see the full body.
365            return RequestBodyStatus::StopIterationAndBuffer;
366        }
367
368        // Get the entire request body reference - this does not copy the body.
369        let entire_body = self.envoy_filter_instance.get_request_body_buffer();
370        println!(
371            "entire request body: {}",
372            String::from_utf8(entire_body.copy()).unwrap()
373        );
374
375        // This demonstrates how to use the reader to read the body.
376        let mut reader = entire_body.reader();
377        let mut buf = vec![0; 2];
378        let mut offset = 0;
379        loop {
380            let n = reader.read(&mut buf).unwrap();
381            if n == 0 {
382                break;
383            }
384            println!(
385                "request body read 2 bytes offset at {}: \"{}\"",
386                offset,
387                std::str::from_utf8(&buf[..n]).unwrap()
388            );
389            offset += 2;
390        }
391
392        // Replace the entire body with 'Y' without copying.
393        for i in entire_body.slices() {
394            for j in i {
395                *j = b'X';
396            }
397        }
398        RequestBodyStatus::Continue
399    }
Source

pub fn copy(&self) -> Vec<u8>

Copies the entire buffer into a single contiguous Vec managed in Rust.

Examples found in repository?
example/example.rs (line 361)
354    fn request_body(
355        &mut self,
356        request_body_frame: &RequestBodyBuffer,
357        end_of_stream: bool,
358    ) -> RequestBodyStatus {
359        println!(
360            "new request body frame: {}",
361            String::from_utf8(request_body_frame.copy()).unwrap()
362        );
363        if !end_of_stream {
364            // Wait for the end of the stream to see the full body.
365            return RequestBodyStatus::StopIterationAndBuffer;
366        }
367
368        // Get the entire request body reference - this does not copy the body.
369        let entire_body = self.envoy_filter_instance.get_request_body_buffer();
370        println!(
371            "entire request body: {}",
372            String::from_utf8(entire_body.copy()).unwrap()
373        );
374
375        // This demonstrates how to use the reader to read the body.
376        let mut reader = entire_body.reader();
377        let mut buf = vec![0; 2];
378        let mut offset = 0;
379        loop {
380            let n = reader.read(&mut buf).unwrap();
381            if n == 0 {
382                break;
383            }
384            println!(
385                "request body read 2 bytes offset at {}: \"{}\"",
386                offset,
387                std::str::from_utf8(&buf[..n]).unwrap()
388            );
389            offset += 2;
390        }
391
392        // Replace the entire body with 'Y' without copying.
393        for i in entire_body.slices() {
394            for j in i {
395                *j = b'X';
396            }
397        }
398        RequestBodyStatus::Continue
399    }
Source

pub fn reader(&self) -> RequestBodyBufferReader

Returns a reader that implements the std::io::Read trait.

Examples found in repository?
example/example.rs (line 376)
354    fn request_body(
355        &mut self,
356        request_body_frame: &RequestBodyBuffer,
357        end_of_stream: bool,
358    ) -> RequestBodyStatus {
359        println!(
360            "new request body frame: {}",
361            String::from_utf8(request_body_frame.copy()).unwrap()
362        );
363        if !end_of_stream {
364            // Wait for the end of the stream to see the full body.
365            return RequestBodyStatus::StopIterationAndBuffer;
366        }
367
368        // Get the entire request body reference - this does not copy the body.
369        let entire_body = self.envoy_filter_instance.get_request_body_buffer();
370        println!(
371            "entire request body: {}",
372            String::from_utf8(entire_body.copy()).unwrap()
373        );
374
375        // This demonstrates how to use the reader to read the body.
376        let mut reader = entire_body.reader();
377        let mut buf = vec![0; 2];
378        let mut offset = 0;
379        loop {
380            let n = reader.read(&mut buf).unwrap();
381            if n == 0 {
382                break;
383            }
384            println!(
385                "request body read 2 bytes offset at {}: \"{}\"",
386                offset,
387                std::str::from_utf8(&buf[..n]).unwrap()
388            );
389            offset += 2;
390        }
391
392        // Replace the entire body with 'Y' without copying.
393        for i in entire_body.slices() {
394            for j in i {
395                *j = b'X';
396            }
397        }
398        RequestBodyStatus::Continue
399    }
400
401    fn response_body(
402        &mut self,
403        response_body_frame: &ResponseBodyBuffer,
404        end_of_stream: bool,
405    ) -> ResponseBodyStatus {
406        println!(
407            "new response body frame: {}",
408            String::from_utf8(response_body_frame.copy()).unwrap()
409        );
410        if !end_of_stream {
411            // Wait for the end of the stream to see the full body.
412            return ResponseBodyStatus::StopIterationAndBuffer;
413        }
414
415        // Get the entire response body reference - this does not copy the body.
416        let entire_body = self.envoy_filter_instance.get_response_body_buffer();
417        println!(
418            "entire response body: {}",
419            String::from_utf8(entire_body.copy()).unwrap()
420        );
421
422        // This demonstrates how to use the reader to read the body.
423        let mut reader = entire_body.reader();
424        let mut buf = vec![0; 2];
425        let mut offset = 0;
426        loop {
427            let n = reader.read(&mut buf).unwrap();
428            if n == 0 {
429                break;
430            }
431            println!(
432                "response body read 2 bytes offset at {}: \"{}\"",
433                offset,
434                std::str::from_utf8(&buf[..n]).unwrap()
435            );
436            offset += 2;
437        }
438
439        // Replace the entire body with 'Y' without copying.
440        for i in entire_body.slices() {
441            for j in i {
442                *j = b'Y';
443            }
444        }
445
446        ResponseBodyStatus::Continue
447    }
448}
449
450/// BodiesReplaceFilter is a filter that replaces request/response bodies.
451///
452/// This implements the [`HttpFilter`] trait, and will be created per each filter chain.
453struct BodiesReplace {}
454
455impl HttpFilter for BodiesReplace {
456    fn new_instance(
457        &mut self,
458        envoy_filter_instance: EnvoyFilterInstance,
459    ) -> Box<dyn HttpFilterInstance> {
460        Box::new(BodiesReplaceInstance {
461            envoy_filter_instance,
462            request_append: String::new(),
463            request_prepend: String::new(),
464            request_replace: String::new(),
465            response_append: String::new(),
466            response_prepend: String::new(),
467            response_replace: String::new(),
468        })
469    }
470}
471
472/// BodiesReplaceInstance is a filter instance that replaces request/response bodies.
473///
474/// This implements the [`HttpFilterInstance`] trait, and will be created per each request.
475struct BodiesReplaceInstance {
476    envoy_filter_instance: EnvoyFilterInstance,
477    request_append: String,
478    request_prepend: String,
479    request_replace: String,
480    response_append: String,
481    response_prepend: String,
482    response_replace: String,
483}
484
485impl HttpFilterInstance for BodiesReplaceInstance {
486    fn request_headers(
487        &mut self,
488        request_headers: &RequestHeaders,
489        _end_of_stream: bool,
490    ) -> RequestHeadersStatus {
491        if let Some(value) = request_headers.get(b"append") {
492            self.request_append = std::str::from_utf8(value).unwrap().to_string();
493        }
494        if let Some(value) = request_headers.get(b"prepend") {
495            self.request_prepend = std::str::from_utf8(value).unwrap().to_string();
496        }
497        if let Some(value) = request_headers.get(b"replace") {
498            self.request_replace = std::str::from_utf8(value).unwrap().to_string();
499        }
500        request_headers.remove(b"content-length"); // Remove content-length header to avoid mismatch.
501        RequestHeadersStatus::Continue
502    }
503
504    fn request_body(
505        &mut self,
506        _request_body_frame: &RequestBodyBuffer,
507        end_of_stream: bool,
508    ) -> RequestBodyStatus {
509        if !end_of_stream {
510            // Wait for the end of the stream to see the full body.
511            return RequestBodyStatus::StopIterationAndBuffer;
512        }
513
514        let entire_body = self.envoy_filter_instance.get_request_body_buffer();
515        if !self.request_append.is_empty() {
516            entire_body.append(self.request_append.as_bytes());
517        }
518        if !self.request_prepend.is_empty() {
519            entire_body.prepend(self.request_prepend.as_bytes());
520        }
521        if !self.request_replace.is_empty() {
522            entire_body.replace(self.request_replace.as_bytes());
523        }
524        RequestBodyStatus::Continue
525    }
526
527    fn response_headers(
528        &mut self,
529        response_headers: &ResponseHeaders,
530        _end_of_stream: bool,
531    ) -> ResponseHeadersStatus {
532        if let Some(value) = response_headers.get(b"append") {
533            self.response_append = std::str::from_utf8(value).unwrap().to_string();
534        }
535        if let Some(value) = response_headers.get(b"prepend") {
536            self.response_prepend = std::str::from_utf8(value).unwrap().to_string();
537        }
538        if let Some(value) = response_headers.get(b"replace") {
539            self.response_replace = std::str::from_utf8(value).unwrap().to_string();
540        }
541        response_headers.remove(b"content-length"); // Remove content-length header to avoid mismatch.
542        ResponseHeadersStatus::Continue
543    }
544
545    fn response_body(
546        &mut self,
547        _response_body_frame: &ResponseBodyBuffer,
548        end_of_stream: bool,
549    ) -> ResponseBodyStatus {
550        if !end_of_stream {
551            // Wait for the end of the stream to see the full body.
552            return ResponseBodyStatus::StopIterationAndBuffer;
553        }
554
555        let entire_body = self.envoy_filter_instance.get_response_body_buffer();
556        if !self.response_append.is_empty() {
557            entire_body.append(self.response_append.as_bytes());
558        }
559        if !self.response_prepend.is_empty() {
560            entire_body.prepend(self.response_prepend.as_bytes());
561        }
562        if !self.response_replace.is_empty() {
563            entire_body.replace(self.response_replace.as_bytes());
564        }
565        ResponseBodyStatus::Continue
566    }
567}
568
569/// SendResponseFilter is a filter that sends a response.
570///
571/// This implements the [`HttpFilter`] trait, and will be created per each filter chain.
572struct SendResponseFilter {}
573
574impl HttpFilter for SendResponseFilter {
575    fn new_instance(
576        &mut self,
577        envoy_filter_instance: EnvoyFilterInstance,
578    ) -> Box<dyn HttpFilterInstance> {
579        Box::new(SendResponseFilterInstance {
580            envoy_filter_instance,
581            on_response_headers: false,
582        })
583    }
584}
585
586/// SendResponseFilterInstance is a filter instance that sends a response.
587///
588/// This implements the [`HttpFilterInstance`] trait, and will be created per each request.
589struct SendResponseFilterInstance {
590    envoy_filter_instance: EnvoyFilterInstance,
591    on_response_headers: bool,
592}
593
594impl HttpFilterInstance for SendResponseFilterInstance {
595    fn request_headers(
596        &mut self,
597        request_headers: &RequestHeaders,
598        _end_of_stream: bool,
599    ) -> RequestHeadersStatus {
600        if let Some(value) = request_headers.get(b":path") {
601            if value == "/on_request".as_bytes() {
602                let headers: Vec<(&[u8], &[u8])> = vec![
603                    ("foo".as_bytes(), "bar".as_bytes()),
604                    ("bar".as_bytes(), "baz".as_bytes()),
605                ];
606                self.envoy_filter_instance.send_response(
607                    401,
608                    headers.as_slice(),
609                    "local response at request headers".as_bytes(),
610                );
611            }
612            if value == b"/on_response" {
613                self.on_response_headers = true;
614            }
615        }
616        RequestHeadersStatus::Continue
617    }
618
619    fn response_headers(
620        &mut self,
621        _response_headers: &ResponseHeaders,
622        _end_of_stream: bool,
623    ) -> ResponseHeadersStatus {
624        if self.on_response_headers {
625            let headers: Vec<(&[u8], &[u8])> = vec![("dog".as_bytes(), "cat".as_bytes())];
626            self.envoy_filter_instance.send_response(
627                500,
628                headers.as_slice(),
629                "local response at response headers".as_bytes(),
630            );
631        }
632        ResponseHeadersStatus::Continue
633    }
634}
635
636/// ValidateJsonFilter is a filter that validates JSON.
637///
638/// This implements the [`HttpFilter`] trait, and will be created per each filter chain.
639struct ValidateJsonFilter {}
640
641impl HttpFilter for ValidateJsonFilter {
642    fn new_instance(
643        &mut self,
644        envoy_filter_instance: EnvoyFilterInstance,
645    ) -> Box<dyn HttpFilterInstance> {
646        Box::new(ValidateJsonFilterInstance {
647            envoy_filter_instance,
648        })
649    }
650}
651
652/// ValidateJsonFilterInstance is a filter instance that validates JSON.
653///
654/// This implements the [`HttpFilterInstance`] trait, and will be created per each request.
655struct ValidateJsonFilterInstance {
656    envoy_filter_instance: EnvoyFilterInstance,
657}
658
659#[derive(Serialize, Deserialize)]
660struct ValidateJsonFilterBody {
661    foo: String,
662}
663
664impl HttpFilterInstance for ValidateJsonFilterInstance {
665    fn request_body(
666        &mut self,
667        _request_body_frame: &RequestBodyBuffer,
668        end_of_stream: bool,
669    ) -> RequestBodyStatus {
670        if !end_of_stream {
671            // Wait for the end of the stream to see the full body.
672            return RequestBodyStatus::StopIterationAndBuffer;
673        }
674
675        let reader = self
676            .envoy_filter_instance
677            .get_request_body_buffer()
678            .reader();
679
680        match serde_json::from_reader(reader) {
681            Ok(body) => {
682                let _body: ValidateJsonFilterBody = body;
683            }
684            Err(_e) => {
685                self.envoy_filter_instance.send_response(400, &[], &[]);
686            }
687        }
688        RequestBodyStatus::Continue
689    }
Source

pub fn append(&self, data: &[u8])

Appends the given data to the buffer.

After this operation, previous slices might be invalidated.

Examples found in repository?
example/example.rs (line 516)
504    fn request_body(
505        &mut self,
506        _request_body_frame: &RequestBodyBuffer,
507        end_of_stream: bool,
508    ) -> RequestBodyStatus {
509        if !end_of_stream {
510            // Wait for the end of the stream to see the full body.
511            return RequestBodyStatus::StopIterationAndBuffer;
512        }
513
514        let entire_body = self.envoy_filter_instance.get_request_body_buffer();
515        if !self.request_append.is_empty() {
516            entire_body.append(self.request_append.as_bytes());
517        }
518        if !self.request_prepend.is_empty() {
519            entire_body.prepend(self.request_prepend.as_bytes());
520        }
521        if !self.request_replace.is_empty() {
522            entire_body.replace(self.request_replace.as_bytes());
523        }
524        RequestBodyStatus::Continue
525    }
Source

pub fn prepend(&self, data: &[u8])

Prepends the given data to the buffer.

After this operation, previous slices might be invalidated.

Examples found in repository?
example/example.rs (line 519)
504    fn request_body(
505        &mut self,
506        _request_body_frame: &RequestBodyBuffer,
507        end_of_stream: bool,
508    ) -> RequestBodyStatus {
509        if !end_of_stream {
510            // Wait for the end of the stream to see the full body.
511            return RequestBodyStatus::StopIterationAndBuffer;
512        }
513
514        let entire_body = self.envoy_filter_instance.get_request_body_buffer();
515        if !self.request_append.is_empty() {
516            entire_body.append(self.request_append.as_bytes());
517        }
518        if !self.request_prepend.is_empty() {
519            entire_body.prepend(self.request_prepend.as_bytes());
520        }
521        if !self.request_replace.is_empty() {
522            entire_body.replace(self.request_replace.as_bytes());
523        }
524        RequestBodyStatus::Continue
525    }
Source

pub fn drain(&self, size: usize)

Drains the buffer by the given size.

After this operation, previous slices might be invalidated.

Source

pub fn replace(&self, data: &[u8])

Replaces the entire buffer with the given data.

After this operation, previous slices might be invalidated.

Examples found in repository?
example/example.rs (line 522)
504    fn request_body(
505        &mut self,
506        _request_body_frame: &RequestBodyBuffer,
507        end_of_stream: bool,
508    ) -> RequestBodyStatus {
509        if !end_of_stream {
510            // Wait for the end of the stream to see the full body.
511            return RequestBodyStatus::StopIterationAndBuffer;
512        }
513
514        let entire_body = self.envoy_filter_instance.get_request_body_buffer();
515        if !self.request_append.is_empty() {
516            entire_body.append(self.request_append.as_bytes());
517        }
518        if !self.request_prepend.is_empty() {
519            entire_body.prepend(self.request_prepend.as_bytes());
520        }
521        if !self.request_replace.is_empty() {
522            entire_body.replace(self.request_replace.as_bytes());
523        }
524        RequestBodyStatus::Continue
525    }

Trait Implementations§

Source§

impl Clone for RequestBodyBuffer

Source§

fn clone(&self) -> RequestBodyBuffer

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for RequestBodyBuffer

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl From<RequestBodyBuffer> for RequestBodyBufferReader

Source§

fn from(buffer: RequestBodyBuffer) -> Self

Converts to this type from the input type.
Source§

impl Copy for RequestBodyBuffer

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.