[READ-ONLY] Mirror of https://github.com/FoxxMD/docker-proxy-filter. Filter the contents of Docker API responses
docker docker-socket-proxy filter
0

Configure Feed

Select the types of activity you want to include in your feed.

remove formatting changes by Github Codespace

Andreas Brett (Apr 4, 2026, 9:49 PM UTC) 1a5ab3c8 d51533cd

+37 -63
+37 -63
src/proxy.rs
··· 1 - use ::http::StatusCode; 1 + use tracing::*; 2 + use std::sync::{Arc, Mutex}; 3 + use std::collections::HashMap; 4 + use ntex::{http::{self, HttpMessage}, web::{self}}; 2 5 use futures_util::TryStreamExt; 3 - use ntex::{ 4 - http::{self, HttpMessage}, 5 - web::{self}, 6 - }; 7 - use std::collections::HashMap; 8 - use std::sync::{Arc, Mutex}; 9 - use tracing::*; 6 + use ::http::StatusCode; 10 7 11 - use crate::config::AppConfig; 8 + use crate::config::{AppConfig}; 12 9 use crate::docker::{self, types::*}; 13 10 use crate::utils; 14 11 ··· 29 26 client: web::types::State<http::Client>, 30 27 forward_url: web::types::State<url::Url>, 31 28 app_config: web::types::State<AppConfig>, 32 - data: web::types::State<AppStateWithContainerMap>, 29 + data: web::types::State<AppStateWithContainerMap> 33 30 ) -> Result<web::HttpResponse, web::Error> { 34 31 let mut new_url = forward_url.get_ref().clone(); 35 32 new_url.set_path(req.uri().path()); ··· 53 50 client_resp.content_type(res.content_type()); 54 51 55 52 if res.status() == 200 { 53 + 56 54 // if route is to list containers we want to return a filtered list 57 55 if new_url.path().contains("containers/json") { 58 56 let _list_span = span!(Level::DEBUG, "Container List").entered(); 59 57 60 - let container_res = &res 61 - .json::<Vec<ContainerSummary>>() 62 - // 2mb in bytes 63 - .limit(2097152) 64 - .await; 58 + let container_res = &res.json::<Vec<ContainerSummary>>() 59 + // 2mb in bytes 60 + .limit(2097152).await; 65 61 66 62 let containers = match container_res { 67 - Ok(list_res) => list_res, 63 + Ok(list_res) => { 64 + list_res 65 + } 68 66 Err(e) => { 69 67 panic!("{e}"); 70 68 } 71 69 }; 72 - 70 + 73 71 // filter all containers to only those that have values from CONTAINER_NAMES includes in their names 74 - let filtered_containers = containers 75 - .into_iter() 76 - .filter(|&con| { 77 - let _list_span = span!( 78 - Level::DEBUG, 79 - "Container", 80 - id = utils::short_id(con.id.as_ref().unwrap()) 81 - ) 82 - .entered(); 83 - docker::container_summary_match( 84 - con, 85 - &app_config.get_ref().container_names, 86 - &app_config.get_ref().container_labels, 87 - ) 72 + let filtered_containers = containers.into_iter() 73 + .filter(|&con| { 74 + let _list_span = span!(Level::DEBUG, "Container", id = utils::short_id(con.id.as_ref().unwrap())).entered(); 75 + docker::container_summary_match(con, &app_config.get_ref().container_names, &app_config.get_ref().container_labels) 88 76 }) 89 77 .collect::<Vec<&ContainerSummary>>(); 90 78 91 79 let fresp = web::HttpResponse::build(res.status()).json(&filtered_containers); 92 - debug!( 93 - "{} of {} containers valid", 94 - filtered_containers.len(), 95 - containers.len() 96 - ); 80 + debug!("{} of {} containers valid", filtered_containers.len(), containers.len()); 97 81 Ok(fresp) 98 82 } else { 83 + 99 84 // only deal with routes that are for containers like /containers/1234/{some_resource} 100 85 match docker::match_container_get(new_url.path()) { 101 86 // the regex pulls the container id from the route with a named capture group, avaiable as m.id 102 - Some(m) => { 87 + 88 + Some (m) => { 103 89 let short_cid = utils::short_id(&m.id); //format!("{start}...{end}", start = &m.id[..6], end = &m.id[&m.id.len() - 6..]); 104 90 let _con_span = span!(Level::DEBUG, "Container", id = short_cid).entered(); 105 91 debug!("Matched container route with Id {}", &m.id); ··· 111 97 // or if we encountered an error last time then try again 112 98 if !cm.contains_key(&m.id) || cm.get(&m.id).unwrap().is_none() { 113 99 debug!("Requested Id not in map, trying to inspect..."); 114 - let info_res = 115 - docker::get_container_info(&client, &forward_url, &m.id).await; 100 + let info_res = docker::get_container_info(&client, &forward_url, &m.id).await; 116 101 match info_res { 117 102 Ok((name, labels)) => { 118 - let is_container_match = docker::match_labels_or_names( 119 - &app_config.get_ref().container_names, 120 - &app_config.get_ref().container_labels, 121 - &Vec::from([name.clone()]), 122 - &labels, 123 - ); 124 - debug!( 125 - "Recording container '{}' {} valid", 126 - name, 127 - is!(is_container_match; "as";"as not") 128 - ); 103 + let is_container_match = docker::match_labels_or_names(&app_config.get_ref().container_names, &app_config.get_ref().container_labels, &Vec::from([name.clone()]), &labels); 104 + debug!("Recording container '{}' {} valid", name, is!(is_container_match; "as";"as not")); 129 105 cm.insert(m.id.clone(), Some(is_container_match)); 130 106 } 131 107 Err(e) => { ··· 142 118 143 119 // then we try to get the name from the stateful hashmap 144 120 let allowed = cm.get(&m.id).unwrap(); 145 - 121 + 146 122 match allowed { 147 123 Some(n) => { 148 124 // only return if a response if requested container has a name that includes values from CONTAINER_NAMES ··· 151 127 // if the route resource is specifically the Container Inspect API 152 128 // then we may need to scrub Envs if SCRUB_ENVS=true 153 129 if m.resource == "json" { 130 + 154 131 client_resp.content_type("application/json"); 155 132 156 133 if app_config.get_ref().scrub_envs { 157 - let mut container = 158 - res.json::<ContainerInspect>().await.unwrap(); 134 + let mut container = res.json::<ContainerInspect>().await.unwrap(); 159 135 container.config.as_mut().unwrap().env = Some(Vec::new()); 160 136 Ok(client_resp.json(&container)) 161 137 } else { 162 138 Ok(client_resp.streaming(res.into_stream())) 163 139 } 140 + 164 141 } else { 165 142 client_resp.content_type(res.content_type()); 166 143 Ok(client_resp.streaming(res.into_stream())) ··· 168 145 } else { 169 146 debug!("Does not match container filters, 404ing..."); 170 147 client_resp.status(StatusCode::NOT_FOUND); 171 - Ok(client_resp.json(&DockerErrorMessage { 172 - message: format!("No such container: {}", &m.id), 173 - })) 148 + Ok(client_resp.json(&DockerErrorMessage { message: format!("No such container: {}", &m.id)})) 174 149 } 175 150 } 176 151 None => { 177 - debug!( 178 - "Does not exist or Docker API previously returned an error, 404ing..." 179 - ); 152 + debug!("Does not exist or Docker API previously returned an error, 404ing..."); 180 153 client_resp.status(StatusCode::NOT_FOUND); 181 - Ok(client_resp.json(&DockerErrorMessage { 182 - message: format!("No such container: {}", &m.id), 183 - })) 154 + Ok(client_resp.json(&DockerErrorMessage { message: format!("No such container: {}", &m.id)})) 184 155 } 185 156 } 186 157 } ··· 191 162 } 192 163 } 193 164 } 165 + 194 166 } else { 195 167 let stream = res.into_stream(); 196 168 Ok(client_resp.streaming(stream)) 197 169 } 198 - } 170 + 171 + 172 + }