1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
use rand::{distributions::Alphanumeric, Rng};

#[derive(Debug)]
pub struct Form {
    boundary: [u8; 15],
    buffer: Vec<u8>,
}

impl Form {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn build(mut self) -> Vec<u8> {
        self.buffer.extend(b"\r\n");
        self.boundary();
        self.buffer.extend(b"--");

        self.buffer
    }

    pub fn content_type(&self) -> Vec<u8> {
        const NAME: &str = "multipart/form-data; boundary=";

        let mut content_type = Vec::with_capacity(NAME.len() + 15);
        content_type.extend(NAME.as_bytes());
        content_type.extend(&self.boundary);

        content_type
    }

    pub fn file(&mut self, name: &[u8], filename: &[u8], data: &[u8]) -> &mut Self {
        self.start();
        self.name(name);
        self.filename(filename);
        self.data(data);

        self
    }

    pub fn part(&mut self, name: &[u8], data: &[u8]) -> &mut Self {
        self.start();
        self.name(name);
        self.data(data);

        self
    }

    pub fn payload_json(&mut self, json: &[u8]) -> &mut Self {
        self.start();
        self.name(b"payload_json");
        self.buffer.extend(b"\r\nContent-Type: application/json");
        self.data(json);

        self
    }

    fn start(&mut self) {
        self.buffer.extend(b"\r\n");
        self.boundary();
        self.buffer.extend(b"\r\nContent-Disposition: form-data");
    }

    fn boundary(&mut self) {
        self.buffer.extend(b"--");
        self.buffer.extend(&self.boundary);
    }

    fn filename(&mut self, filename: &[u8]) {
        self.buffer.extend(br#"; filename=""#);
        self.buffer.extend(filename);
        self.buffer.push(b'"');
    }

    fn name(&mut self, name: &[u8]) {
        self.buffer.extend(br#"; name=""#);
        self.buffer.extend(name);
        self.buffer.push(b'"');
    }

    fn data(&mut self, data: &[u8]) {
        self.buffer.extend(b"\r\n\r\n");
        self.buffer.extend(data);
    }
}

impl Default for Form {
    fn default() -> Self {
        let mut boundary = [0; 15];
        let mut rng = rand::thread_rng();

        for value in &mut boundary {
            *value = rng.sample(Alphanumeric);
        }

        Self {
            boundary,
            buffer: Vec::new(),
        }
    }
}