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
111
112
113
114
115
116
117
118
119
// Copyright (c) 2019 Timo Savola.
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

//! Access a local HTTP server.

#[macro_use]
extern crate lazy_static;

use flatbuffers::{root, FlatBufferBuilder};
use gain::service::Service;

// The schema file can be found at https://gate.computer/localhost
#[allow(unused, unused_imports)]
#[path = "localhost_generated.rs"]
mod flat;

lazy_static! {
    static ref SERVICE: Service = Service::register("gate.computer/localhost");
}

/// Make a GET request.
pub async fn get(uri: &str) -> Response {
    request("GET", uri, None, &[]).await
}

/// Make a POST request.
pub async fn post(uri: &str, content_type: &str, body: &[u8]) -> Response {
    request("POST", uri, Some(content_type), body).await
}

/// Make a PUT request.
pub async fn put(uri: &str, content_type: &str, body: &[u8]) -> Response {
    request("PUT", uri, Some(content_type), body).await
}

/// Make an HTTP request.
pub async fn request(
    method: &str,
    uri: &str,
    content_type: Option<&str>,
    content: &[u8],
) -> Response {
    let mut b = FlatBufferBuilder::new();

    let content = if !content.is_empty() {
        Some(b.create_vector(content))
    } else {
        None
    };

    let content_type = match content_type {
        Some(s) => Some(b.create_string(s)),
        None => None,
    };

    let uri = b.create_string(uri);
    let method = b.create_string(method);

    let function = flat::Request::create(
        &mut b,
        &flat::RequestArgs {
            method: Some(method),
            uri: Some(uri),
            content_type: content_type,
            body: content,
        },
    );

    let call = flat::Call::create(
        &mut b,
        &flat::CallArgs {
            function_type: flat::Function::Request,
            function: Some(function.as_union_value()),
        },
    );

    b.finish_minimal(call);

    SERVICE
        .call(b.finished_data(), |reply: &[u8]| {
            if reply.is_empty() {
                return Response {
                    status_code: 0,
                    content_type: None,
                    content: Vec::new(),
                };
            }

            let r = root::<flat::Response>(reply).unwrap();

            Response {
                status_code: r.status_code(),
                content_type: match r.content_type() {
                    Some(s) => Some(s.to_owned()),
                    None => None,
                },
                content: {
                    let mut v = Vec::new();
                    if let Some(b) = r.body() {
                        v.reserve(b.len());
                        v.extend_from_slice(b);
                    }
                    v
                },
            }
        })
        .await
}

/// HTTP response.
pub struct Response {
    pub status_code: u16,
    pub content_type: Option<String>,
    pub content: Vec<u8>,
}

#[cfg(feature = "lep")]
pub mod lep;