Skip to content

Commit

Permalink
Merge #66: add http header support
Browse files Browse the repository at this point in the history
73cc41c add http header support (John Cantrell)

Pull request description:

  Technically an end-user could do this themselves because the builders support passing in pre-built ureq/reqwest clients but this makes it a bit easier for them.

  <!-- This is an auto-generated comment: release notes by coderabbit.ai -->

  ## Summary by CodeRabbit

  - **New Features**
  - Introduced the ability to set custom HTTP headers for requests in both asynchronous and synchronous clients.
  - Added methods in the `Builder` struct for adding HTTP headers to requests.
  - **Improvements**
  - Enhanced error handling with new error variants for invalid HTTP header names and values.
  - **Tests**
  - Updated test setup to include custom HTTP headers.
  - Added a new test case for fetching transactions with specific HTTP headers.

  <!-- end of auto-generated comment: release notes by coderabbit.ai -->

Top commit has no ACKs.

Tree-SHA512: 8043b54b1cb1330492017674f3e028ad0bc80c08a722a2b413c4b39f8503e9228b9a008e379e610943ffdf1b50ad2cefedba55f716fe2e7fa69fc22fa0859146
  • Loading branch information
notmandatory committed Mar 21, 2024
2 parents 98edbc5 + 73cc41c commit bbeaab4
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 2 deletions.
14 changes: 13 additions & 1 deletion src/async.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use bitcoin::{
#[allow(unused_imports)]
use log::{debug, error, info, trace};

use reqwest::{Client, StatusCode};
use reqwest::{header, Client, StatusCode};

use crate::{BlockStatus, BlockSummary, Builder, Error, MerkleProof, OutputStatus, Tx, TxStatus};

Expand All @@ -49,6 +49,18 @@ impl AsyncClient {
client_builder = client_builder.timeout(core::time::Duration::from_secs(timeout));
}

if !builder.headers.is_empty() {
let mut headers = header::HeaderMap::new();
for (k, v) in builder.headers {
let header_name = header::HeaderName::from_lowercase(k.to_lowercase().as_bytes())
.map_err(|_| Error::InvalidHttpHeaderName(k))?;
let header_value = header::HeaderValue::from_str(&v)
.map_err(|_| Error::InvalidHttpHeaderValue(v))?;
headers.insert(header_name, header_value);
}
client_builder = client_builder.default_headers(headers);
}

Ok(Self::from_client(builder.base_url, client_builder.build()?))
}

Expand Down
9 changes: 9 additions & 0 deletions src/blocking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ pub struct BlockingClient {
pub proxy: Option<String>,
/// Socket timeout.
pub timeout: Option<u64>,
/// HTTP headers to set on every request made to Esplora server
pub headers: HashMap<String, String>,
}

impl BlockingClient {
Expand All @@ -45,6 +47,7 @@ impl BlockingClient {
url: builder.base_url,
proxy: builder.proxy,
timeout: builder.timeout,
headers: builder.headers,
}
}

Expand All @@ -60,6 +63,12 @@ impl BlockingClient {
request = request.with_timeout(*timeout);
}

if !self.headers.is_empty() {
for (key, value) in &self.headers {
request = request.with_header(key, value);
}
}

Ok(request)
}

Expand Down
62 changes: 61 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ pub struct Builder {
pub proxy: Option<String>,
/// Socket timeout.
pub timeout: Option<u64>,
/// HTTP headers to set on every request made to Esplora server
pub headers: HashMap<String, String>,
}

impl Builder {
Expand All @@ -126,6 +128,7 @@ impl Builder {
base_url: base_url.to_string(),
proxy: None,
timeout: None,
headers: HashMap::new(),
}
}

Expand All @@ -141,6 +144,12 @@ impl Builder {
self
}

/// Add a header to set on each request
pub fn header(mut self, key: &str, value: &str) -> Self {
self.headers.insert(key.to_string(), value.to_string());
self
}

/// build a blocking client from builder
#[cfg(feature = "blocking")]
pub fn build_blocking(self) -> BlockingClient {
Expand Down Expand Up @@ -181,6 +190,10 @@ pub enum Error {
HeaderHeightNotFound(u32),
/// Header hash not found
HeaderHashNotFound(BlockHash),
/// Invalid HTTP Header name specified
InvalidHttpHeaderName(String),
/// Invalid HTTP Header value specified
InvalidHttpHeaderValue(String),
}

impl fmt::Display for Error {
Expand Down Expand Up @@ -261,6 +274,13 @@ mod test {

#[cfg(all(feature = "blocking", feature = "async"))]
async fn setup_clients() -> (BlockingClient, AsyncClient) {
setup_clients_with_headers(HashMap::new()).await
}

#[cfg(all(feature = "blocking", feature = "async"))]
async fn setup_clients_with_headers(
headers: HashMap<String, String>,
) -> (BlockingClient, AsyncClient) {
PREMINE
.get_or_init(|| async {
let _miner = MINER.lock().await;
Expand All @@ -270,7 +290,11 @@ mod test {

let esplora_url = ELECTRSD.esplora_url.as_ref().unwrap();

let builder = Builder::new(&format!("http://{}", esplora_url));
let mut builder = Builder::new(&format!("http://{}", esplora_url));
if !headers.is_empty() {
builder.headers = headers;
}

let blocking_client = builder.build_blocking();

let builder_async = Builder::new(&format!("http://{}", esplora_url));
Expand Down Expand Up @@ -851,4 +875,40 @@ mod test {
let blocks_genesis_async = async_client.get_blocks(Some(0)).await.unwrap();
assert_eq!(blocks_genesis, blocks_genesis_async);
}

#[cfg(all(feature = "blocking", feature = "async"))]
#[tokio::test]
async fn test_get_tx_with_http_header() {
let headers = [(
"Authorization".to_string(),
"Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==".to_string(),
)]
.into();
let (blocking_client, async_client) = setup_clients_with_headers(headers).await;

let address = BITCOIND
.client
.get_new_address(Some("test"), Some(AddressType::Legacy))
.unwrap()
.assume_checked();
let txid = BITCOIND
.client
.send_to_address(
&address,
Amount::from_sat(1000),
None,
None,
None,
None,
None,
None,
)
.unwrap();
let _miner = MINER.lock().await;
generate_blocks_and_wait(1);

let tx = blocking_client.get_tx(&txid).unwrap();
let tx_async = async_client.get_tx(&txid).await.unwrap();
assert_eq!(tx, tx_async);
}
}

0 comments on commit bbeaab4

Please sign in to comment.