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, | ||||
| }; | ||||
| 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 std::{ | ||||
|     net::SocketAddr, | ||||
| @@ -32,16 +36,27 @@ pub struct JsonRpcService { | ||||
| struct RpcRequestMiddleware { | ||||
|     ledger_path: PathBuf, | ||||
|     snapshot_archive_path_regex: Regex, | ||||
|     snapshot_config: Option<SnapshotConfig>, | ||||
| } | ||||
|  | ||||
| impl RpcRequestMiddleware { | ||||
|     pub fn new(ledger_path: PathBuf) -> Self { | ||||
|     pub fn new(ledger_path: PathBuf, snapshot_config: Option<SnapshotConfig>) -> Self { | ||||
|         Self { | ||||
|             ledger_path, | ||||
|             snapshot_archive_path_regex: Regex::new(r"/snapshot-\d+-[[:alnum:]]+\.tar\.bz2$") | ||||
|                 .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> { | ||||
|         hyper::Response::builder() | ||||
|             .status(hyper::StatusCode::NOT_FOUND) | ||||
| @@ -59,7 +74,13 @@ impl RpcRequestMiddleware { | ||||
|     fn is_get_path(&self, path: &str) -> bool { | ||||
|         match path { | ||||
|             "/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 { | ||||
|         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()) { | ||||
|             self.get(request.uri().path()) | ||||
|         } else { | ||||
| @@ -105,6 +152,7 @@ impl JsonRpcService { | ||||
|     pub fn new( | ||||
|         rpc_addr: SocketAddr, | ||||
|         config: JsonRpcConfig, | ||||
|         snapshot_config: Option<SnapshotConfig>, | ||||
|         bank_forks: Arc<RwLock<BankForks>>, | ||||
|         block_commitment_cache: Arc<RwLock<BlockCommitmentCache>>, | ||||
|         blockstore: Arc<Blockstore>, | ||||
| @@ -148,7 +196,7 @@ impl JsonRpcService { | ||||
|                             AccessControlAllowOrigin::Any, | ||||
|                         ])) | ||||
|                         .cors_max_age(86400) | ||||
|                         .request_middleware(RpcRequestMiddleware::new(ledger_path)) | ||||
|                         .request_middleware(RpcRequestMiddleware::new(ledger_path, snapshot_config)) | ||||
|                         .start_http(&rpc_addr); | ||||
|                 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()); | ||||
| @@ -225,6 +273,7 @@ mod tests { | ||||
|         let mut rpc_service = JsonRpcService::new( | ||||
|             rpc_addr, | ||||
|             JsonRpcConfig::default(), | ||||
|             None, | ||||
|             bank_forks, | ||||
|             block_commitment_cache, | ||||
|             Arc::new(blockstore), | ||||
| @@ -253,16 +302,27 @@ mod tests { | ||||
|  | ||||
|     #[test] | ||||
|     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("/snapshot.tar.bz2")); | ||||
|         assert!(!rrm.is_get_path("/snapshot.tar.bz2")); // This is a redirect | ||||
|  | ||||
|         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( | ||||
|             "/snapshot-notaslotnumber-AvFf9oS8A8U78HdjT9YG2sTTThLHJZmhaMn2g8vkWYnr.tar.bz2" | ||||
|         )); | ||||
|   | ||||
| @@ -2,7 +2,7 @@ use bzip2::bufread::BzDecoder; | ||||
| use clap::{ | ||||
|     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 log::*; | ||||
| use rand::{thread_rng, Rng}; | ||||
| @@ -953,12 +953,6 @@ pub fn main() { | ||||
|         warn!("--vote-signer-address ignored"); | ||||
|     } | ||||
|  | ||||
|     println!( | ||||
|         "{} {}", | ||||
|         style(crate_name!()).bold(), | ||||
|         solana_clap_utils::version!() | ||||
|     ); | ||||
|  | ||||
|     let _log_redirect = { | ||||
|         #[cfg(unix)] | ||||
|         { | ||||
| @@ -996,6 +990,7 @@ pub fn main() { | ||||
|         .join(","), | ||||
|     ); | ||||
|  | ||||
|     info!("{} {}", crate_name!(), solana_clap_utils::version!()); | ||||
|     info!("Starting validator with: {:#?}", std::env::args_os()); | ||||
|  | ||||
|     let vote_account = pubkey_of(&matches, "vote_account").unwrap_or_else(|| { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user