summaryrefslogtreecommitdiff
path: root/cli/ops/fetch.rs
blob: 25cf998120e8287accfa35f10bde055b7fc04bfa (plain)
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
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
use super::dispatch_json::{Deserialize, JsonOp, Value};
use super::io::StreamResource;
use crate::http_body::HttpBody;
use crate::http_util::get_client;
use crate::ops::json_op;
use crate::state::ThreadSafeState;
use deno::*;
use futures::future::FutureExt;
use futures::future::TryFutureExt;
use http::header::HeaderName;
use http::header::HeaderValue;
use http::Method;
use std;
use std::convert::From;

pub fn init(i: &mut Isolate, s: &ThreadSafeState) {
  i.register_op("fetch", s.core_op(json_op(s.stateful_op(op_fetch))));
}

#[derive(Deserialize)]
struct FetchArgs {
  method: Option<String>,
  url: String,
  headers: Vec<(String, String)>,
}

pub fn op_fetch(
  state: &ThreadSafeState,
  args: Value,
  data: Option<PinnedBuf>,
) -> Result<JsonOp, ErrBox> {
  let args: FetchArgs = serde_json::from_value(args)?;
  let url = args.url;

  let client = get_client();

  let method = match args.method {
    Some(method_str) => Method::from_bytes(method_str.as_bytes())?,
    None => Method::GET,
  };

  let url_ = url::Url::parse(&url).map_err(ErrBox::from)?;
  state.check_net_url(&url_)?;

  let mut request = client.request(method, url_);

  if let Some(buf) = data {
    request = request.body(Vec::from(&*buf));
  }

  for (key, value) in args.headers {
    let name = HeaderName::from_bytes(key.as_bytes()).unwrap();
    let v = HeaderValue::from_str(&value).unwrap();
    request = request.header(name, v);
  }
  debug!("Before fetch {}", url);
  let state_ = state.clone();
  let future = futures::compat::Compat01As03::new(request.send())
    .map_err(ErrBox::from)
    .and_then(move |res| {
      debug!("Fetch response {}", url);
      let status = res.status();
      let mut res_headers = Vec::new();
      for (key, val) in res.headers().iter() {
        res_headers.push((key.to_string(), val.to_str().unwrap().to_owned()));
      }

      let body = HttpBody::from(res.into_body());
      let mut table = state_.lock_resource_table();
      let rid = table.add(
        "httpBody",
        Box::new(StreamResource::HttpBody(Box::new(body))),
      );

      let json_res = json!({
        "bodyRid": rid,
        "status": status.as_u16(),
        "statusText": status.canonical_reason().unwrap_or(""),
        "headers": res_headers
      });

      futures::future::ok(json_res)
    });

  Ok(JsonOp::Async(future.boxed()))
}