GET for /snapshot.tar.bz2 now redirects to the latest snapshot
This commit is contained in:
		| @@ -10,7 +10,11 @@ use jsonrpc_http_server::{ | |||||||
|     RequestMiddlewareAction, ServerBuilder, |     RequestMiddlewareAction, ServerBuilder, | ||||||
| }; | }; | ||||||
| use regex::Regex; | use regex::Regex; | ||||||
| use solana_ledger::{bank_forks::BankForks, blockstore::Blockstore}; | use solana_ledger::{ | ||||||
|  |     bank_forks::{BankForks, SnapshotConfig}, | ||||||
|  |     blockstore::Blockstore, | ||||||
|  |     snapshot_utils, | ||||||
|  | }; | ||||||
| use solana_sdk::hash::Hash; | use solana_sdk::hash::Hash; | ||||||
| use std::{ | use std::{ | ||||||
|     net::SocketAddr, |     net::SocketAddr, | ||||||
| @@ -32,16 +36,27 @@ pub struct JsonRpcService { | |||||||
| struct RpcRequestMiddleware { | struct RpcRequestMiddleware { | ||||||
|     ledger_path: PathBuf, |     ledger_path: PathBuf, | ||||||
|     snapshot_archive_path_regex: Regex, |     snapshot_archive_path_regex: Regex, | ||||||
|  |     snapshot_config: Option<SnapshotConfig>, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl RpcRequestMiddleware { | impl RpcRequestMiddleware { | ||||||
|     pub fn new(ledger_path: PathBuf) -> Self { |     pub fn new(ledger_path: PathBuf, snapshot_config: Option<SnapshotConfig>) -> Self { | ||||||
|         Self { |         Self { | ||||||
|             ledger_path, |             ledger_path, | ||||||
|             snapshot_archive_path_regex: Regex::new(r"/snapshot-\d+-[[:alnum:]]+\.tar\.bz2$") |             snapshot_archive_path_regex: Regex::new(r"/snapshot-\d+-[[:alnum:]]+\.tar\.bz2$") | ||||||
|                 .unwrap(), |                 .unwrap(), | ||||||
|  |             snapshot_config, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     fn redirect(location: &str) -> hyper::Response<hyper::Body> { | ||||||
|  |         hyper::Response::builder() | ||||||
|  |             .status(hyper::StatusCode::SEE_OTHER) | ||||||
|  |             .header(hyper::header::LOCATION, location) | ||||||
|  |             .body(hyper::Body::from(String::from(location))) | ||||||
|  |             .unwrap() | ||||||
|  |     } | ||||||
|  |  | ||||||
|     fn not_found() -> hyper::Response<hyper::Body> { |     fn not_found() -> hyper::Response<hyper::Body> { | ||||||
|         hyper::Response::builder() |         hyper::Response::builder() | ||||||
|             .status(hyper::StatusCode::NOT_FOUND) |             .status(hyper::StatusCode::NOT_FOUND) | ||||||
| @@ -59,7 +74,13 @@ impl RpcRequestMiddleware { | |||||||
|     fn is_get_path(&self, path: &str) -> bool { |     fn is_get_path(&self, path: &str) -> bool { | ||||||
|         match path { |         match path { | ||||||
|             "/genesis.tar.bz2" => true, |             "/genesis.tar.bz2" => true, | ||||||
|             _ => self.snapshot_archive_path_regex.is_match(path), |             _ => { | ||||||
|  |                 if self.snapshot_config.is_some() { | ||||||
|  |                     self.snapshot_archive_path_regex.is_match(path) | ||||||
|  |                 } else { | ||||||
|  |                     false | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -89,6 +110,32 @@ impl RequestMiddleware for RpcRequestMiddleware { | |||||||
|     fn on_request(&self, request: hyper::Request<hyper::Body>) -> RequestMiddlewareAction { |     fn on_request(&self, request: hyper::Request<hyper::Body>) -> RequestMiddlewareAction { | ||||||
|         trace!("request uri: {}", request.uri()); |         trace!("request uri: {}", request.uri()); | ||||||
|  |  | ||||||
|  |         if let Some(ref snapshot_config) = self.snapshot_config { | ||||||
|  |             if request.uri().path() == "/snapshot.tar.bz2" { | ||||||
|  |                 // Convenience redirect to the latest snapshot | ||||||
|  |                 return RequestMiddlewareAction::Respond { | ||||||
|  |                     should_validate_hosts: true, | ||||||
|  |                     response: Box::new(jsonrpc_core::futures::future::ok( | ||||||
|  |                         if let Some((snapshot_archive, _)) = | ||||||
|  |                             snapshot_utils::get_highest_snapshot_archive_path( | ||||||
|  |                                 &snapshot_config.snapshot_package_output_path, | ||||||
|  |                             ) | ||||||
|  |                         { | ||||||
|  |                             RpcRequestMiddleware::redirect(&format!( | ||||||
|  |                                 "/{}", | ||||||
|  |                                 snapshot_archive | ||||||
|  |                                     .file_name() | ||||||
|  |                                     .unwrap_or_else(|| std::ffi::OsStr::new("")) | ||||||
|  |                                     .to_str() | ||||||
|  |                                     .unwrap_or(&"") | ||||||
|  |                             )) | ||||||
|  |                         } else { | ||||||
|  |                             RpcRequestMiddleware::not_found() | ||||||
|  |                         }, | ||||||
|  |                     )), | ||||||
|  |                 }; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|         if self.is_get_path(request.uri().path()) { |         if self.is_get_path(request.uri().path()) { | ||||||
|             self.get(request.uri().path()) |             self.get(request.uri().path()) | ||||||
|         } else { |         } else { | ||||||
| @@ -105,6 +152,7 @@ impl JsonRpcService { | |||||||
|     pub fn new( |     pub fn new( | ||||||
|         rpc_addr: SocketAddr, |         rpc_addr: SocketAddr, | ||||||
|         config: JsonRpcConfig, |         config: JsonRpcConfig, | ||||||
|  |         snapshot_config: Option<SnapshotConfig>, | ||||||
|         bank_forks: Arc<RwLock<BankForks>>, |         bank_forks: Arc<RwLock<BankForks>>, | ||||||
|         block_commitment_cache: Arc<RwLock<BlockCommitmentCache>>, |         block_commitment_cache: Arc<RwLock<BlockCommitmentCache>>, | ||||||
|         blockstore: Arc<Blockstore>, |         blockstore: Arc<Blockstore>, | ||||||
| @@ -148,7 +196,7 @@ impl JsonRpcService { | |||||||
|                             AccessControlAllowOrigin::Any, |                             AccessControlAllowOrigin::Any, | ||||||
|                         ])) |                         ])) | ||||||
|                         .cors_max_age(86400) |                         .cors_max_age(86400) | ||||||
|                         .request_middleware(RpcRequestMiddleware::new(ledger_path)) |                         .request_middleware(RpcRequestMiddleware::new(ledger_path, snapshot_config)) | ||||||
|                         .start_http(&rpc_addr); |                         .start_http(&rpc_addr); | ||||||
|                 if let Err(e) = server { |                 if let Err(e) = server { | ||||||
|                     warn!("JSON RPC service unavailable error: {:?}. \nAlso, check that port {} is not already in use by another application", e, rpc_addr.port()); |                     warn!("JSON RPC service unavailable error: {:?}. \nAlso, check that port {} is not already in use by another application", e, rpc_addr.port()); | ||||||
| @@ -225,6 +273,7 @@ mod tests { | |||||||
|         let mut rpc_service = JsonRpcService::new( |         let mut rpc_service = JsonRpcService::new( | ||||||
|             rpc_addr, |             rpc_addr, | ||||||
|             JsonRpcConfig::default(), |             JsonRpcConfig::default(), | ||||||
|  |             None, | ||||||
|             bank_forks, |             bank_forks, | ||||||
|             block_commitment_cache, |             block_commitment_cache, | ||||||
|             Arc::new(blockstore), |             Arc::new(blockstore), | ||||||
| @@ -253,16 +302,27 @@ mod tests { | |||||||
|  |  | ||||||
|     #[test] |     #[test] | ||||||
|     fn test_is_get_path() { |     fn test_is_get_path() { | ||||||
|         let rrm = RpcRequestMiddleware::new(PathBuf::from("/")); |         let rrm = RpcRequestMiddleware::new(PathBuf::from("/"), None); | ||||||
|  |         let rrm_with_snapshot_config = RpcRequestMiddleware::new( | ||||||
|  |             PathBuf::from("/"), | ||||||
|  |             Some(SnapshotConfig { | ||||||
|  |                 snapshot_interval_slots: 0, | ||||||
|  |                 snapshot_package_output_path: PathBuf::from("/"), | ||||||
|  |                 snapshot_path: PathBuf::from("/"), | ||||||
|  |             }), | ||||||
|  |         ); | ||||||
|  |  | ||||||
|         assert!(rrm.is_get_path("/genesis.tar.bz2")); |         assert!(rrm.is_get_path("/genesis.tar.bz2")); | ||||||
|         assert!(!rrm.is_get_path("genesis.tar.bz2")); |         assert!(!rrm.is_get_path("genesis.tar.bz2")); | ||||||
|  |  | ||||||
|         assert!(!rrm.is_get_path("/snapshot.tar.bz2")); |         assert!(!rrm.is_get_path("/snapshot.tar.bz2")); // This is a redirect | ||||||
|  |  | ||||||
|         assert!( |         assert!( | ||||||
|             rrm.is_get_path("/snapshot-100-AvFf9oS8A8U78HdjT9YG2sTTThLHJZmhaMn2g8vkWYnr.tar.bz2") |             !rrm.is_get_path("/snapshot-100-AvFf9oS8A8U78HdjT9YG2sTTThLHJZmhaMn2g8vkWYnr.tar.bz2") | ||||||
|         ); |         ); | ||||||
|  |         assert!(rrm_with_snapshot_config | ||||||
|  |             .is_get_path("/snapshot-100-AvFf9oS8A8U78HdjT9YG2sTTThLHJZmhaMn2g8vkWYnr.tar.bz2")); | ||||||
|  |  | ||||||
|         assert!(!rrm.is_get_path( |         assert!(!rrm.is_get_path( | ||||||
|             "/snapshot-notaslotnumber-AvFf9oS8A8U78HdjT9YG2sTTThLHJZmhaMn2g8vkWYnr.tar.bz2" |             "/snapshot-notaslotnumber-AvFf9oS8A8U78HdjT9YG2sTTThLHJZmhaMn2g8vkWYnr.tar.bz2" | ||||||
|         )); |         )); | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ use bzip2::bufread::BzDecoder; | |||||||
| use clap::{ | use clap::{ | ||||||
|     crate_description, crate_name, value_t, value_t_or_exit, values_t_or_exit, App, Arg, ArgMatches, |     crate_description, crate_name, value_t, value_t_or_exit, values_t_or_exit, App, Arg, ArgMatches, | ||||||
| }; | }; | ||||||
| use console::{style, Emoji}; | use console::Emoji; | ||||||
| use indicatif::{ProgressBar, ProgressStyle}; | use indicatif::{ProgressBar, ProgressStyle}; | ||||||
| use log::*; | use log::*; | ||||||
| use rand::{thread_rng, Rng}; | use rand::{thread_rng, Rng}; | ||||||
| @@ -953,12 +953,6 @@ pub fn main() { | |||||||
|         warn!("--vote-signer-address ignored"); |         warn!("--vote-signer-address ignored"); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     println!( |  | ||||||
|         "{} {}", |  | ||||||
|         style(crate_name!()).bold(), |  | ||||||
|         solana_clap_utils::version!() |  | ||||||
|     ); |  | ||||||
|  |  | ||||||
|     let _log_redirect = { |     let _log_redirect = { | ||||||
|         #[cfg(unix)] |         #[cfg(unix)] | ||||||
|         { |         { | ||||||
| @@ -996,6 +990,7 @@ pub fn main() { | |||||||
|         .join(","), |         .join(","), | ||||||
|     ); |     ); | ||||||
|  |  | ||||||
|  |     info!("{} {}", crate_name!(), solana_clap_utils::version!()); | ||||||
|     info!("Starting validator with: {:#?}", std::env::args_os()); |     info!("Starting validator with: {:#?}", std::env::args_os()); | ||||||
|  |  | ||||||
|     let vote_account = pubkey_of(&matches, "vote_account").unwrap_or_else(|| { |     let vote_account = pubkey_of(&matches, "vote_account").unwrap_or_else(|| { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user