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
102
103
104
105
106
107
108
109
110
// Copyright 2020 Tetrate
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate std;

use std::fmt;
use std::prelude::v1::*;
use std::time::Duration;

use proxy_wasm::types::Bytes;

use crate::host;

/// Opaque identifier of an initiated HTTP request.
#[derive(Debug, PartialEq, Eq)]
pub struct RequestHandle(u32);

impl From<u32> for RequestHandle {
    fn from(token_id: u32) -> Self {
        RequestHandle(token_id)
    }
}

impl fmt::Display for RequestHandle {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

pub trait Client {
    fn send_request(
        &self,
        upstream: &str,
        headers: Vec<(&str, &str)>,
        body: Option<&[u8]>,
        trailers: Vec<(&str, &str)>,
        timeout: Duration,
    ) -> host::Result<RequestHandle>;
}

pub trait ResponseOps {
    fn get_http_call_response_headers(&self) -> host::Result<Vec<(String, String)>>;

    fn get_http_call_response_body(
        &self,
        start: usize,
        max_size: usize,
    ) -> host::Result<Option<Bytes>>;

    fn get_http_call_response_trailers(&self) -> host::Result<Vec<(String, String)>>;
}

pub mod ops {
    use std::time::Duration;

    use proxy_wasm::hostcalls;
    use proxy_wasm::types::{BufferType, Bytes, MapType};

    use super::{Client, RequestHandle, ResponseOps};
    use crate::host;

    pub struct Host;

    impl Client for Host {
        fn send_request(
            &self,
            upstream: &str,
            headers: Vec<(&str, &str)>,
            body: Option<&[u8]>,
            trailers: Vec<(&str, &str)>,
            timeout: Duration,
        ) -> host::Result<RequestHandle> {
            hostcalls::dispatch_http_call(upstream, headers, body, trailers, timeout)
                .map_err(|status| ("proxy_http_call", status))
                .map(RequestHandle::from)
        }
    }

    impl ResponseOps for Host {
        fn get_http_call_response_headers(&self) -> host::Result<Vec<(String, String)>> {
            hostcalls::get_map(MapType::HttpCallResponseHeaders)
                .map_err(|status| ("proxy_get_header_map_pairs", status))
        }

        fn get_http_call_response_body(
            &self,
            start: usize,
            max_size: usize,
        ) -> host::Result<Option<Bytes>> {
            hostcalls::get_buffer(BufferType::HttpCallResponseBody, start, max_size)
                .map_err(|status| ("proxy_get_buffer_bytes", status))
        }

        fn get_http_call_response_trailers(&self) -> host::Result<Vec<(String, String)>> {
            hostcalls::get_map(MapType::HttpCallResponseTrailers)
                .map_err(|status| ("proxy_get_header_map_pairs", status))
        }
    }
}