mirror of
https://github.com/Orange-OpenSource/hurl.git
synced 2024-11-26 11:43:08 +03:00
Add extension function on Easy for getting certinfo.
This commit is contained in:
parent
4acb12d2bd
commit
9fb1cb7801
@ -29,7 +29,7 @@ use super::request::*;
|
|||||||
use super::request_spec::*;
|
use super::request_spec::*;
|
||||||
use super::response::*;
|
use super::response::*;
|
||||||
use super::{Header, HttpError, Verbosity};
|
use super::{Header, HttpError, Verbosity};
|
||||||
use crate::http::ContextDir;
|
use crate::http::{easy_ext, ContextDir};
|
||||||
use crate::util::logger::Logger;
|
use crate::util::logger::Logger;
|
||||||
use base64::engine::general_purpose;
|
use base64::engine::general_purpose;
|
||||||
use base64::Engine;
|
use base64::Engine;
|
||||||
@ -123,6 +123,9 @@ impl Client {
|
|||||||
// way to get access to the outgoing headers.
|
// way to get access to the outgoing headers.
|
||||||
self.handle.verbose(true).unwrap();
|
self.handle.verbose(true).unwrap();
|
||||||
|
|
||||||
|
// Activates the access of certificates info chain after a transfer has been executed.
|
||||||
|
self.handle.certinfo(true).unwrap();
|
||||||
|
|
||||||
if !options.connects_to.is_empty() {
|
if !options.connects_to.is_empty() {
|
||||||
let connects = to_list(&options.connects_to);
|
let connects = to_list(&options.connects_to);
|
||||||
self.handle.connect_to(connects).unwrap();
|
self.handle.connect_to(connects).unwrap();
|
||||||
@ -312,6 +315,7 @@ impl Client {
|
|||||||
let duration = start.elapsed();
|
let duration = start.elapsed();
|
||||||
let length = response_body.len();
|
let length = response_body.len();
|
||||||
let certificate = None;
|
let certificate = None;
|
||||||
|
let _certinfo = easy_ext::get_certinfo(&self.handle)?;
|
||||||
self.handle.reset();
|
self.handle.reset();
|
||||||
|
|
||||||
let request = Request {
|
let request = Request {
|
||||||
|
151
packages/hurl/src/http/easy_ext.rs
Normal file
151
packages/hurl/src/http/easy_ext.rs
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
* Hurl (https://hurl.dev)
|
||||||
|
* Copyright (C) 2023 Orange
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
use curl::easy::Easy;
|
||||||
|
use curl::Error;
|
||||||
|
use curl_sys::{curl_certinfo, curl_slist};
|
||||||
|
use std::ffi::CStr;
|
||||||
|
use std::ptr;
|
||||||
|
|
||||||
|
/// Represents certificate information.
|
||||||
|
/// `data` has format "name:content";
|
||||||
|
pub struct CertInfo {
|
||||||
|
pub data: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the information of the first certificate in the certificates chain.
|
||||||
|
pub fn get_certinfo(easy: &Easy) -> Result<Option<CertInfo>, Error> {
|
||||||
|
unsafe {
|
||||||
|
let mut certinfo = ptr::null_mut::<curl_certinfo>();
|
||||||
|
let rc =
|
||||||
|
curl_sys::curl_easy_getinfo(easy.raw(), curl_sys::CURLINFO_CERTINFO, &mut certinfo);
|
||||||
|
if rc != curl_sys::CURLE_OK {
|
||||||
|
return Err(Error::new(rc));
|
||||||
|
}
|
||||||
|
if certinfo.is_null() {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
let count = (*certinfo).num_of_certs;
|
||||||
|
if count <= 0 {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
let slist = *((*certinfo).certinfo.offset(0));
|
||||||
|
let data = to_list(slist);
|
||||||
|
Ok(Some(CertInfo { data }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts an instance of libcurl linked list [`curl_slist`] to a vec of [`String`].
|
||||||
|
fn to_list(slist: *mut curl_slist) -> Vec<String> {
|
||||||
|
let mut data = vec![];
|
||||||
|
let mut cur = slist;
|
||||||
|
loop {
|
||||||
|
if cur.is_null() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
let ret = CStr::from_ptr((*cur).data).to_bytes();
|
||||||
|
let value = String::from_utf8_lossy(ret);
|
||||||
|
data.push(value.to_string());
|
||||||
|
cur = (*cur).next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data
|
||||||
|
}
|
||||||
|
|
||||||
|
// // Iterator based implementation more similar to curl crates List implementation.
|
||||||
|
// // See <https://github.com/alexcrichton/curl-rust/blob/main/src/easy/list.rs>
|
||||||
|
// pub struct CertInfo2 {
|
||||||
|
// raw: *mut curl_certinfo,
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // An iterator over CertInfo2
|
||||||
|
// pub struct Iter<'a> {
|
||||||
|
// me: &'a CertInfo2,
|
||||||
|
// cur: u32,
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// pub unsafe fn from_raw(raw: *mut curl_certinfo) -> CertInfo2 {
|
||||||
|
// CertInfo2 { raw }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// impl CertInfo2 {
|
||||||
|
// pub fn new() -> CertInfo2 {
|
||||||
|
// CertInfo2 {
|
||||||
|
// raw: ptr::null_mut(),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// pub fn iter(&self) -> Iter {
|
||||||
|
// Iter {
|
||||||
|
// me: self,
|
||||||
|
// cur: 0,
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// impl<'a> IntoIterator for &'a CertInfo2 {
|
||||||
|
// type Item = *mut curl_slist;
|
||||||
|
// type IntoIter = Iter<'a>;
|
||||||
|
//
|
||||||
|
// fn into_iter(self) -> Iter<'a> {
|
||||||
|
// self.iter()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// impl<'a> Iterator for Iter<'a> {
|
||||||
|
// type Item = *mut curl_slist;
|
||||||
|
//
|
||||||
|
// fn next(&mut self) -> Option<*mut curl_slist> {
|
||||||
|
// unsafe {
|
||||||
|
// if self.cur >= (*self.me.raw).num_of_certs as u32 {
|
||||||
|
// return None
|
||||||
|
// }
|
||||||
|
// let slist = *((*self.me.raw).certinfo.offset(self.cur as isize));
|
||||||
|
// self.cur += 1;
|
||||||
|
// Some(slist)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::to_list;
|
||||||
|
use std::ffi::CString;
|
||||||
|
use std::ptr;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn convert_curl_slist_to_vec() {
|
||||||
|
let mut slist = ptr::null_mut();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
for value in ["foo", "bar", "baz"] {
|
||||||
|
let str = CString::new(value).unwrap();
|
||||||
|
slist = curl_sys::curl_slist_append(slist, str.as_ptr());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
to_list(slist),
|
||||||
|
vec!["foo".to_string(), "bar".to_string(), "baz".to_string()]
|
||||||
|
);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
curl_sys::curl_slist_free_all(slist);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -42,3 +42,16 @@ pub enum HttpError {
|
|||||||
},
|
},
|
||||||
InvalidUrl(String),
|
InvalidUrl(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<curl::Error> for HttpError {
|
||||||
|
fn from(err: curl::Error) -> Self {
|
||||||
|
let code = err.code() as i32;
|
||||||
|
let description = err.description().to_string();
|
||||||
|
let url = "".to_string();
|
||||||
|
HttpError::Libcurl {
|
||||||
|
code,
|
||||||
|
description,
|
||||||
|
url,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -38,6 +38,7 @@ mod context_dir;
|
|||||||
mod cookie;
|
mod cookie;
|
||||||
mod core;
|
mod core;
|
||||||
mod debug;
|
mod debug;
|
||||||
|
mod easy_ext;
|
||||||
mod error;
|
mod error;
|
||||||
mod header;
|
mod header;
|
||||||
mod mimetype;
|
mod mimetype;
|
||||||
|
Loading…
Reference in New Issue
Block a user