Add http_fetch

This commit is contained in:
kpcyrd
2019-08-07 10:45:00 +02:00
parent 341674d7ac
commit b421e96ebb
7 changed files with 96 additions and 25 deletions

View File

@@ -154,6 +154,7 @@ For everything else please have a look at the [detailed list][1].
- [http_mksession](https://sn0int.readthedocs.io/en/latest/reference.html#http-mksession)
- [http_request](https://sn0int.readthedocs.io/en/latest/reference.html#http-request)
- [http_send](https://sn0int.readthedocs.io/en/latest/reference.html#http-send)
- [http_fetch](https://sn0int.readthedocs.io/en/latest/reference.html#http-fetch)
- [http_fetch_json](https://sn0int.readthedocs.io/en/latest/reference.html#http-fetch-json)
- [img_load](https://sn0int.readthedocs.io/en/latest/reference.html#img-load)
- [img_exif](https://sn0int.readthedocs.io/en/latest/reference.html#img-exif)

View File

@@ -405,11 +405,31 @@ the following keys:
if last_err() then return end
if resp['status'] ~= 200 then return 'http status error: ' .. resp['status'] end
http_fetch
----------
This does an http_send_ and also automatically validate the status code.
.. note::
You almost always want this when setting the ``into_blob`` option since this
function validates the status code *before* inserting the response body into
blob storage.
.. code-block:: lua
-- short form
data = http_fetch(req)
if last_err() then return end
-- long form
resp = http_send(req)
if last_err() then return end
if resp['status'] ~= 200 then return 'http status error: ' .. resp['status'] end
http_fetch_json
---------------
This is a shorthand for http_send_, validating the status code and parsing the
response body as json.
Identical to http_fetch_ but also automatically parses the response body as json.
.. code-block:: lua

View File

@@ -8,11 +8,8 @@ function run()
req = http_request(session, 'GET', 'https://www.kernel.org/theme/images/logos/tux.png', {
into_blob=true,
})
r = http_send(req)
r = http_fetch(req)
if last_err() then return end
if r['status'] ~= 200 then
return 'http error: ' .. r['status']
end
debug(r)
db_add('image', {

View File

@@ -389,6 +389,7 @@ fn ctx<'a>(env: Environment, logger: Arc<Mutex<Box<Reporter>>>) -> (hlua::Lua<'a
runtime::http_mksession(&mut lua, state.clone());
runtime::http_request(&mut lua, state.clone());
runtime::http_send(&mut lua, state.clone());
runtime::http_fetch(&mut lua, state.clone());
runtime::http_fetch_json(&mut lua, state.clone());
runtime::img_exif(&mut lua, state.clone());
runtime::img_load(&mut lua, state.clone());

View File

@@ -95,9 +95,8 @@ mod tests {
req = http_request(session, 'GET', 'https://www.kernel.org/theme/images/logos/tux.png', {
into_blob=true,
})
r = http_send(req)
r = http_fetch(req)
if last_err() then return end
if r['status'] ~= 200 then return 'http error: ' .. r['status'] end
img = img_load(r['blob'])
@@ -125,9 +124,8 @@ mod tests {
req = http_request(session, 'GET', 'https://www.kernel.org/theme/images/logos/tux.png', {
into_blob=true,
})
r = http_send(req)
r = http_fetch(req)
if last_err() then return end
if r['status'] ~= 200 then return 'http error: ' .. r['status'] end
nudity = img_nudity(r['blob'])
@@ -155,10 +153,9 @@ mod tests {
req = http_request(session, 'GET', url, {
into_blob=true,
})
r = http_send(req)
r = http_fetch(req)
if last_err() then return end
print(r)
if r['status'] ~= 200 then return 'wrong status code' end
location = img_exif(r['blob'])
print(location)

View File

@@ -31,7 +31,29 @@ pub fn http_send(lua: &mut hlua::Lua, state: Arc<State>) {
.context("invalid http request object")
.map_err(|err| state.set_error(err.into()))?;
req.send_lua(state.as_ref())
let resp = req.send(state.as_ref())
.map_err(|err| state.set_error(err))?;
req.response_to_lua(state.as_ref(), resp)
.map_err(|err| state.set_error(err))
.map(|resp| resp.into())
}))
}
pub fn http_fetch(lua: &mut hlua::Lua, state: Arc<State>) {
lua.set("http_fetch", hlua::function1(move |request: AnyLuaValue| -> Result<AnyLuaValue> {
let req = HttpRequest::try_from(request)
.context("invalid http request object")
.map_err(|err| state.set_error(err.into()))?;
let resp = req.send(state.as_ref())
.map_err(|err| state.set_error(err))?;
if resp.status < 200 || resp.status > 299 {
return Err(state.set_error(format_err!("http status error: {}", resp.status)));
}
req.response_to_lua(state.as_ref(), resp)
.map_err(|err| state.set_error(err))
.map(|resp| resp.into())
}))
@@ -167,6 +189,27 @@ mod tests {
#[test]
#[ignore]
fn verify_fetch_ok() {
let script = Script::load_unchecked(r#"
function run()
session = http_mksession()
req = http_request(session, "GET", "https://httpbin.org/anything", {})
x = http_fetch(req)
if last_err() then return end
o = json_decode(x['text'])
if last_err() then return end
if o['method'] ~= 'GET' then
return 'unexpected response'
end
end
"#).expect("failed to load script");
script.test().expect("Script failed");
}
#[test]
#[ignore]
fn verify_fetch_json_ok() {
let script = Script::load_unchecked(r#"
function run()
session = http_mksession()
@@ -185,6 +228,19 @@ mod tests {
#[test]
#[ignore]
fn verify_fetch_404() {
let script = Script::load_unchecked(r#"
function run()
session = http_mksession()
req = http_request(session, "GET", "https://httpbin.org/status/404", {})
x = http_fetch(req)
end
"#).expect("failed to load script");
script.test().err().expect("Script should have failed");
}
#[test]
#[ignore]
fn verify_fetch_json_404() {
let script = Script::load_unchecked(r#"
function run()
session = http_mksession()
@@ -197,7 +253,7 @@ mod tests {
#[test]
#[ignore]
fn verify_fetch_invalid_json() {
fn verify_fetch_json_invalid() {
let script = Script::load_unchecked(r#"
function run()
session = http_mksession()

View File

@@ -215,27 +215,24 @@ impl HttpRequest {
.with_timeout(self.timeout)
.wait_for_response()?;
Ok(res)
}
pub fn send_lua(&self, state: &State) -> Result<LuaMap> {
let res = self.send(state)?;
// map result to LuaMap
let mut resp = LuaMap::new();
resp.insert_num("status", f64::from(res.status));
for cookie in &res.cookies {
HttpRequest::register_cookies_on_state(&self.session, state, cookie);
}
Ok(res)
}
pub fn response_to_lua(&self, state: &State, res: Response) -> Result<LuaMap> {
// map result to LuaMap
let mut resp = LuaMap::new();
resp.insert_num("status", f64::from(res.status));
let mut headers = LuaMap::new();
for (key, value) in res.headers {
headers.insert_str(key.to_lowercase(), value);
}
resp.insert("headers", headers);
if self.into_blob {
let blob = Blob::create(res.body);
let id = state.register_blob(blob);
@@ -286,6 +283,7 @@ impl Into<AnyLuaValue> for HttpRequest {
pub struct CookieJar(HashMap<String, String>);
impl CookieJar {
#[inline(always)]
pub fn register_in_jar(&mut self, key: String, value: String) {
self.0.insert(key, value);
}
@@ -294,6 +292,7 @@ impl CookieJar {
impl Deref for CookieJar {
type Target = HashMap<String, String>;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.0
}