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
//! HTTP transaction parsing.
//!
//! ## Remarks
//! Retina currently only parses HTTP 1.x request and response headers, and does not attempt to
//! parse or defragment HTTP bodies that may span multiple packets. This is enough for basic HTTP
//! header analysis, but not for deep inspection of message body contents. Support for
//! request/response continuations, chunked transfer encoding, and body content retrieval, are in
//! progress.
//!
//! This module does support parsing pipelined requests and maintains state for linking requests and
//! responses.
//!
/*
TODO: support request/response continuations (body that spans multiple packets)
TODO: support chunked transfer encoding
TODO: provide request/response body
TODO: HTTP/2 support
*/
pub mod parser;
mod transaction;
pub use self::transaction::{HttpRequest, HttpResponse};
use serde::Serialize;
/// Parsed HTTP transaction contents.
#[derive(Debug, Serialize, Clone)]
pub struct Http {
/// HTTP Request.
pub request: HttpRequest,
/// HTTP Response.
pub response: HttpResponse,
/// The pipelined depth into the connection of this transaction.
pub trans_depth: usize,
}
impl Http {
/// Returns the request URI, or `""` if it does not exist.
pub fn uri(&self) -> &str {
self.request.uri.as_deref().unwrap_or("")
}
/// Returns the HTTP method, or `""` if it does not exist.
pub fn method(&self) -> &str {
self.request.method.as_deref().unwrap_or("")
}
/// Returns the HTTP request version, or `""` if it does not exist.
pub fn request_version(&self) -> &str {
self.request.version.as_deref().unwrap_or("")
}
/// Returns the user agent string of the user agent, or `""` if it does not exist.
pub fn user_agent(&self) -> &str {
self.request.user_agent.as_deref().unwrap_or("")
}
/// Returns HTTP cookies sent by the client, or `""` if it does not exist.
pub fn cookie(&self) -> &str {
self.request.cookie.as_deref().unwrap_or("")
}
/// Returns the domain name of the server specified by the client, or `""` if it does not exist.
pub fn host(&self) -> &str {
self.request.host.as_deref().unwrap_or("")
}
/// Returns the size of the request body in bytes, or `0` if it does not exist.
pub fn request_content_length(&self) -> usize {
self.request.content_length.unwrap_or(0)
}
/// Returns the media type of the request resource, or `""` if it does not exist.
pub fn request_content_type(&self) -> &str {
self.request.content_type.as_deref().unwrap_or("")
}
/// Returns the form of encoding used to transfer the request body, or `""` if it does not
/// exist.
pub fn request_transfer_encoding(&self) -> &str {
self.request.transfer_encoding.as_deref().unwrap_or("")
}
/// Returns the HTTP response version, or `""` if it does not exist.
pub fn response_version(&self) -> &str {
self.response.version.as_deref().unwrap_or("")
}
/// Returns the HTTP status code, or `0` if it does not exist.
pub fn status_code(&self) -> u16 {
self.response.status_code.unwrap_or(0)
}
/// Returns the HTTP status tet, or `0` if it does not exist.
pub fn status_msg(&self) -> &str {
self.response.status_msg.as_deref().unwrap_or("")
}
/// Returns the size of the request body in bytes, or `0` if it does not exist.
pub fn response_content_length(&self) -> usize {
self.response.content_length.unwrap_or(0)
}
/// Returns the media type of the response resource, or `""` if it does not exist.
pub fn response_content_type(&self) -> &str {
self.response.content_type.as_deref().unwrap_or("")
}
/// Returns the form of encoding used to transfer the response body, or `""` if it does not
/// exist.
pub fn response_transfer_encoding(&self) -> &str {
self.response.transfer_encoding.as_deref().unwrap_or("")
}
// TODO: more methods...
}