Skip to content

Commit 975df09

Browse files
committed
Added http from io-utils
1 parent 60a5cdc commit 975df09

File tree

3 files changed

+171
-2
lines changed

3 files changed

+171
-2
lines changed

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,5 @@ edition = "2021"
99
anyhow = "1"
1010
base64 = { version = "0.13.0", default-features = false }
1111
err-derive = "0.2"
12-
io-utils = { path = "../io-utils"}
1312
log = "0.4.13"
1413
uuid = { version = "1.1.2", features = ["serde"] }

src/http.rs

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
//! Common HTTP and proxy-attestation service-related functionality
2+
//!
3+
//! Provides material for posting buffers over HTTP, and for sending messages
4+
//! to the proxy attestation service over a HTTP interface.
5+
//!
6+
//! # Authors
7+
//!
8+
//! The Veracruz Development Team.
9+
//!
10+
//! # Copyright and licensing
11+
//!
12+
//! See the `LICENSE_MIT.markdown` file in the Veracruz root directory for copyright
13+
//! and licensing information.
14+
15+
use err_derive::Error;
16+
use log::{error, info};
17+
use reqwest::{blocking, Error as ReqwestError, header, StatusCode};
18+
use std::{collections::HashMap, string::String, vec::Vec};
19+
use transport_protocol::{
20+
ProxyAttestationServerResponse, TransportProtocolError,
21+
};
22+
23+
///////////////////////////////////////////////////////////////////////////////
24+
// Errors.
25+
///////////////////////////////////////////////////////////////////////////////
26+
27+
/// HTTP-related errors.
28+
#[derive(Debug, Error)]
29+
pub enum HttpError {
30+
/// Reqwest generated an error
31+
#[error(display = "Reqwest generated an error:{}", _0)]
32+
ReqwestError(ReqwestError),
33+
/// Invalid Header value
34+
#[error(display = "Invalid header value:{}", _0)]
35+
InvalidHeaderValue(header::InvalidHeaderValue),
36+
/// An unexpected HTTP status code was returned.
37+
#[error(display = "An unexpected HTTP return code was returned.")]
38+
UnexpectedHttpCode,
39+
/// Response did not contain a field that we expected
40+
#[error(display = "Response did not contain an expected field.")]
41+
PoorlyFormedResponse,
42+
#[error(
43+
display = "A transport protocol message could not be (de)serialized: {}.",
44+
_0
45+
)]
46+
SerializationError(TransportProtocolError),
47+
#[error(
48+
display = "A base64-encoded message could not be (de)serialized: {}.",
49+
_0
50+
)]
51+
Base64Error(base64::DecodeError),
52+
#[error(display = "A transport protocol error occurred: {}.", _0)]
53+
TransportProtocolError(TransportProtocolError),
54+
#[error(display = "An attestation-related error occurred: {}.", _0)]
55+
AttestationError(TransportProtocolError),
56+
#[error(display = "The proxy attestation service issued an unexpected reply.")]
57+
ProtocolError(ProxyAttestationServerResponse),
58+
#[error(display = "Unable to convert bytes to UTF8: {}.", _0)]
59+
Utf8Error(std::str::Utf8Error),
60+
}
61+
62+
///////////////////////////////////////////////////////////////////////////////
63+
// HTTP-related functionality.
64+
///////////////////////////////////////////////////////////////////////////////
65+
66+
#[derive(Debug)]
67+
pub enum HttpResponse {
68+
Ok(Vec<u8>), // 200: Body
69+
Created(String, Vec<u8>), //201: Location, Body
70+
Accepted(Vec<u8>), // 202: Body
71+
NonAuthoritativeInformation(Vec<u8>), // 203: Body
72+
NoContent, // 204
73+
ResetContent(Vec<u8>), // 205: Body
74+
PartialContent(Vec<u8>), // 206: Body
75+
}
76+
77+
fn convert_reqwest_response_to_http_response(res: blocking::Response) -> Result<HttpResponse, HttpError> {
78+
let response = match res.status() {
79+
StatusCode::OK => {
80+
let body = res.bytes().map_err(|_| HttpError::PoorlyFormedResponse)?;
81+
HttpResponse::Ok(body.to_vec())
82+
},
83+
StatusCode::CREATED => {
84+
let location = match res.headers().get(header::LOCATION) {
85+
None => return Err(HttpError::PoorlyFormedResponse),
86+
Some(loc) => loc.to_str().map_err(|_| HttpError::PoorlyFormedResponse)?.to_string(),
87+
};
88+
let body = res.bytes().map_err(|_| HttpError::PoorlyFormedResponse)?;
89+
90+
HttpResponse::Created(location, body.to_vec())
91+
}
92+
StatusCode::ACCEPTED => {
93+
let body = res.bytes().map_err(|_| HttpError::PoorlyFormedResponse)?;
94+
HttpResponse::Accepted(body.to_vec())
95+
}
96+
StatusCode::NON_AUTHORITATIVE_INFORMATION => {
97+
let body = res.bytes().map_err(|_| HttpError::PoorlyFormedResponse)?;
98+
HttpResponse::NonAuthoritativeInformation(body.to_vec())
99+
}
100+
StatusCode::NO_CONTENT => HttpResponse::NoContent,
101+
StatusCode::RESET_CONTENT => {
102+
let body = res.bytes().map_err(|_| HttpError::PoorlyFormedResponse)?;
103+
HttpResponse::ResetContent(body.to_vec())
104+
}
105+
StatusCode::PARTIAL_CONTENT => {
106+
let body = res.bytes().map_err(|_| HttpError::PoorlyFormedResponse)?;
107+
HttpResponse::PartialContent(body.to_vec())
108+
}
109+
_ => return Err(HttpError::UnexpectedHttpCode),
110+
};
111+
return Ok(response);
112+
}
113+
114+
/// Sends an encoded `buffer` via HTTP to a server at `url`. Fails if the
115+
/// Curl session fails for any reason, or if a non-success HTTP code is
116+
/// returned.
117+
pub fn post_buffer<U>(url: U, buffer: &String, content_type_option: Option<&str>) -> Result<HttpResponse, HttpError>
118+
where
119+
U: AsRef<str>,
120+
{
121+
let url = url.as_ref();
122+
let buffer: String = buffer.to_string();
123+
124+
info!(
125+
"Posting buffer {} ({} bytes) to {}.",
126+
buffer,
127+
buffer.len(),
128+
url
129+
);
130+
131+
let request_builder = blocking::Client::new()
132+
.post(url)
133+
.body(buffer);
134+
135+
let request_builder = match content_type_option {
136+
Some(content_type) => {
137+
request_builder.header(header::CONTENT_TYPE, header::HeaderValue::from_str(content_type).map_err(|err| HttpError::InvalidHeaderValue(err))?)
138+
}
139+
None => request_builder, // do nothing
140+
};
141+
let ret = request_builder.send()
142+
.map_err(|err| HttpError::ReqwestError(err))?;
143+
let response = convert_reqwest_response_to_http_response(ret)?;
144+
145+
return Ok(response);
146+
}
147+
148+
pub fn post_form<U: AsRef<str>>(url: U, form_data: &HashMap<String, String>) -> Result<HttpResponse, HttpError> {
149+
let url = url.as_ref();
150+
let client_builder = blocking::ClientBuilder::new();
151+
152+
let client = client_builder.build()
153+
.map_err(|err| {
154+
HttpError::ReqwestError(err)
155+
})?;
156+
let mut form = blocking::multipart::Form::new();
157+
for (key, value) in &*form_data {
158+
form = form.text(key.clone(), value.clone());
159+
}
160+
161+
let response = client.post(url)
162+
.multipart(form)
163+
.send()
164+
.map_err(|err| {
165+
HttpError::ReqwestError(err)
166+
})?;
167+
let response = convert_reqwest_response_to_http_response(response)?;
168+
return Ok(response);
169+
}

src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@
1212
use anyhow::{anyhow, Result as AnyhowResult};
1313
use base64;
1414
use err_derive::Error;
15-
use io_utils::http::{HttpResponse, post_form, post_buffer};
1615
use log::{error, info};
1716
use std::collections::HashMap;
1817
use uuid::Uuid;
1918

19+
mod http;
20+
2021
#[derive(Debug, Error)]
2122
pub enum ProxyAttestationClientError {
2223
#[error(display = "ProxyAttestationClient: HttpError: {:?}", _0)]

0 commit comments

Comments
 (0)