diff --git a/Cargo.lock b/Cargo.lock index 6bc4f781134b8..ae79ed924e2a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -543,7 +543,7 @@ checksum = "4c3082de64b6d8e3956fa92e3009c27db209aa17388abf7a7d766adc6bb9b8ba" dependencies = [ "async-graphql", "futures-util", - "http 0.2.9", + "http 0.2.12", "serde_json", "warp", ] @@ -617,7 +617,7 @@ dependencies = [ "base64 0.21.7", "bytes 1.9.0", "futures 0.3.31", - "http 0.2.9", + "http 0.2.12", "memchr", "nkeys 0.3.2", "nuid", @@ -784,7 +784,7 @@ dependencies = [ "bytes 1.9.0", "fastrand 2.1.1", "hex", - "http 0.2.9", + "http 0.2.12", "hyper 0.14.28", "ring", "time", @@ -815,7 +815,7 @@ dependencies = [ "aws-smithy-types", "aws-types", "bytes 1.9.0", - "http 0.2.9", + "http 0.2.12", "http-body 0.4.5", "pin-project-lite", "tracing 0.1.41", @@ -837,7 +837,7 @@ dependencies = [ "aws-smithy-types", "aws-types", "fastrand 2.1.1", - "http 0.2.9", + "http 0.2.12", "percent-encoding", "tracing 0.1.41", "uuid", @@ -861,7 +861,7 @@ dependencies = [ "aws-smithy-types", "aws-smithy-xml", "aws-types", - "http 0.2.9", + "http 0.2.12", "regex", "tracing 0.1.41", ] @@ -884,7 +884,7 @@ dependencies = [ "aws-types", "bytes 1.9.0", "fastrand 2.1.1", - "http 0.2.9", + "http 0.2.12", "regex", "tracing 0.1.41", ] @@ -906,7 +906,7 @@ dependencies = [ "aws-smithy-types", "aws-types", "bytes 1.9.0", - "http 0.2.9", + "http 0.2.12", "regex", "tracing 0.1.41", ] @@ -928,7 +928,7 @@ dependencies = [ "aws-smithy-types", "aws-types", "bytes 1.9.0", - "http 0.2.9", + "http 0.2.12", "regex", "tracing 0.1.41", ] @@ -950,7 +950,7 @@ dependencies = [ "aws-smithy-types", "aws-types", "bytes 1.9.0", - "http 0.2.9", + "http 0.2.12", "regex", "tracing 0.1.41", ] @@ -976,7 +976,7 @@ dependencies = [ "aws-smithy-xml", "aws-types", "bytes 1.9.0", - "http 0.2.9", + "http 0.2.12", "http-body 0.4.5", "once_cell", "percent-encoding", @@ -1003,7 +1003,7 @@ dependencies = [ "aws-types", "bytes 1.9.0", "fastrand 2.1.1", - "http 0.2.9", + "http 0.2.12", "regex", "tracing 0.1.41", ] @@ -1026,7 +1026,7 @@ dependencies = [ "aws-smithy-types", "aws-smithy-xml", "aws-types", - "http 0.2.9", + "http 0.2.12", "regex", "tracing 0.1.41", ] @@ -1048,7 +1048,7 @@ dependencies = [ "aws-smithy-types", "aws-types", "bytes 1.9.0", - "http 0.2.9", + "http 0.2.12", "regex", "tracing 0.1.41", ] @@ -1070,7 +1070,7 @@ dependencies = [ "aws-smithy-types", "aws-types", "bytes 1.9.0", - "http 0.2.9", + "http 0.2.12", "regex", "tracing 0.1.41", ] @@ -1092,7 +1092,7 @@ dependencies = [ "aws-smithy-types", "aws-types", "bytes 1.9.0", - "http 0.2.9", + "http 0.2.12", "regex", "tracing 0.1.41", ] @@ -1115,7 +1115,7 @@ dependencies = [ "aws-smithy-types", "aws-smithy-xml", "aws-types", - "http 0.2.9", + "http 0.2.12", "regex", "tracing 0.1.41", ] @@ -1135,7 +1135,7 @@ dependencies = [ "form_urlencoded", "hex", "hmac", - "http 0.2.9", + "http 0.2.12", "http 1.1.0", "once_cell", "percent-encoding", @@ -1167,7 +1167,7 @@ dependencies = [ "crc32c", "crc32fast", "hex", - "http 0.2.9", + "http 0.2.12", "http-body 0.4.5", "md-5", "pin-project-lite", @@ -1199,7 +1199,7 @@ dependencies = [ "bytes 1.9.0", "bytes-utils", "futures-core", - "http 0.2.9", + "http 0.2.12", "http-body 0.4.5", "once_cell", "percent-encoding", @@ -1240,7 +1240,7 @@ dependencies = [ "bytes 1.9.0", "fastrand 2.1.1", "h2 0.3.26", - "http 0.2.9", + "http 0.2.12", "http-body 0.4.5", "http-body 1.0.0", "httparse", @@ -1263,7 +1263,7 @@ dependencies = [ "aws-smithy-async", "aws-smithy-types", "bytes 1.9.0", - "http 0.2.9", + "http 0.2.12", "http 1.1.0", "pin-project-lite", "tokio", @@ -1281,7 +1281,7 @@ dependencies = [ "bytes 1.9.0", "bytes-utils", "futures-core", - "http 0.2.9", + "http 0.2.12", "http 1.1.0", "http-body 0.4.5", "http-body 1.0.0", @@ -1331,7 +1331,7 @@ dependencies = [ "bitflags 1.3.2", "bytes 1.9.0", "futures-util", - "http 0.2.9", + "http 0.2.12", "http-body 0.4.5", "hyper 0.14.28", "itoa", @@ -1385,7 +1385,7 @@ dependencies = [ "async-trait", "bytes 1.9.0", "futures-util", - "http 0.2.9", + "http 0.2.12", "http-body 0.4.5", "mime", "rustversion", @@ -4017,7 +4017,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http 0.2.9", + "http 0.2.12", "indexmap 2.7.0", "slab", "tokio", @@ -4117,7 +4117,7 @@ dependencies = [ "base64 0.21.7", "bytes 1.9.0", "headers-core", - "http 0.2.9", + "http 0.2.12", "httpdate", "mime", "sha1", @@ -4129,7 +4129,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" dependencies = [ - "http 0.2.9", + "http 0.2.12", ] [[package]] @@ -4382,7 +4382,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes 1.9.0", - "http 0.2.9", + "http 0.2.12", "pin-project-lite", ] @@ -4421,7 +4421,7 @@ version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f560b665ad9f1572cfcaf034f7fb84338a7ce945216d64a90fd81f046a3caee" dependencies = [ - "http 0.2.9", + "http 0.2.12", "serde", ] @@ -4474,7 +4474,7 @@ dependencies = [ "futures-core", "futures-util", "h2 0.3.26", - "http 0.2.9", + "http 0.2.12", "http-body 0.4.5", "httparse", "httpdate", @@ -4529,7 +4529,7 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6ee5d7a8f718585d1c3c61dfde28ef5b0bb14734b4db13f5ada856cdc6c612b" dependencies = [ - "http 0.2.9", + "http 0.2.12", "hyper 0.14.28", "linked_hash_set", "once_cell", @@ -4550,7 +4550,7 @@ dependencies = [ "bytes 1.9.0", "futures 0.3.31", "headers", - "http 0.2.9", + "http 0.2.12", "hyper 0.14.28", "openssl", "tokio", @@ -4565,7 +4565,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", - "http 0.2.9", + "http 0.2.12", "hyper 0.14.28", "log", "rustls 0.21.11", @@ -5182,7 +5182,7 @@ dependencies = [ "base64 0.21.7", "bytes 1.9.0", "chrono", - "http 0.2.9", + "http 0.2.12", "percent-encoding", "serde", "serde-value", @@ -5263,7 +5263,7 @@ dependencies = [ "dirs-next", "either", "futures 0.3.31", - "http 0.2.9", + "http 0.2.12", "http-body 0.4.5", "hyper 0.14.28", "hyper-openssl", @@ -5294,7 +5294,7 @@ checksum = "25983d07f414dfffba08c5951fe110f649113416b1d8e22f7c89c750eb2555a7" dependencies = [ "chrono", "form_urlencoded", - "http 0.2.9", + "http 0.2.12", "json-patch", "k8s-openapi 0.18.0", "once_cell", @@ -6338,7 +6338,7 @@ dependencies = [ "base64 0.13.1", "chrono", "getrandom 0.2.15", - "http 0.2.9", + "http 0.2.12", "rand 0.8.5", "reqwest 0.11.26", "serde", @@ -6442,7 +6442,7 @@ dependencies = [ "flagset", "futures 0.3.31", "getrandom 0.2.15", - "http 0.2.9", + "http 0.2.12", "log", "md-5", "once_cell", @@ -6466,7 +6466,7 @@ dependencies = [ "dyn-clone", "ed25519-dalek", "hmac", - "http 0.2.9", + "http 0.2.12", "itertools 0.10.5", "log", "oauth2", @@ -7994,7 +7994,7 @@ dependencies = [ "futures-core", "futures-util", "h2 0.3.26", - "http 0.2.9", + "http 0.2.12", "http-body 0.4.5", "hyper 0.14.28", "hyper-rustls 0.24.2", @@ -9948,7 +9948,7 @@ dependencies = [ "bytes 1.9.0", "flate2", "h2 0.3.26", - "http 0.2.9", + "http 0.2.12", "http-body 0.4.5", "hyper 0.14.28", "hyper-timeout 0.4.1", @@ -10056,7 +10056,7 @@ dependencies = [ "bytes 1.9.0", "futures-core", "futures-util", - "http 0.2.9", + "http 0.2.12", "http-body 0.4.5", "http-range-header", "mime", @@ -10338,7 +10338,7 @@ dependencies = [ "byteorder", "bytes 1.9.0", "data-encoding", - "http 0.2.9", + "http 0.2.12", "httparse", "log", "rand 0.8.5", @@ -10759,7 +10759,7 @@ dependencies = [ "hex", "hickory-proto", "hostname 0.4.0", - "http 0.2.9", + "http 0.2.12", "http-body 0.4.5", "http-serde", "hyper 0.14.28", @@ -10968,7 +10968,7 @@ dependencies = [ "chrono", "chrono-tz", "encoding_rs", - "http 0.2.9", + "http 0.2.12", "indexmap 2.7.0", "inventory", "no-proxy", @@ -11034,7 +11034,7 @@ dependencies = [ "futures 0.3.31", "futures-util", "headers", - "http 0.2.9", + "http 0.2.12", "hyper-proxy", "indexmap 2.7.0", "ipnet", @@ -11395,7 +11395,7 @@ dependencies = [ "futures-channel", "futures-util", "headers", - "http 0.2.9", + "http 0.2.12", "hyper 0.14.28", "log", "mime", diff --git a/Cargo.toml b/Cargo.toml index 454f8d75c5510..a1c39a1d105cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -316,7 +316,7 @@ hash_hasher = { version = "2.0.0", default-features = false } hashbrown = { version = "0.14.5", default-features = false, optional = true, features = ["ahash"] } headers = { version = "0.3.9", default-features = false } hostname = { version = "0.4.0", default-features = false } -http = { version = "0.2.9", default-features = false } +http = { version = "0.2.12", default-features = false } http-serde = "1.1.3" http-body = { version = "0.4.5", default-features = false } hyper = { version = "0.14.28", default-features = false, features = ["client", "runtime", "http1", "http2", "server", "stream"] } diff --git a/changelog.d/20395_custom_response_headers_from_http_server.feature.md b/changelog.d/20395_custom_response_headers_from_http_server.feature.md new file mode 100644 index 0000000000000..46d0ccc47715c --- /dev/null +++ b/changelog.d/20395_custom_response_headers_from_http_server.feature.md @@ -0,0 +1,3 @@ +The `http_server` source now allows configuring custom headers to be added to responses via the `custom_response_headers` option. + +authors: chriscancompute diff --git a/src/sources/http_server.rs b/src/sources/http_server.rs index 83d8550efd45a..bb0fe801905da 100644 --- a/src/sources/http_server.rs +++ b/src/sources/http_server.rs @@ -6,7 +6,7 @@ use http::StatusCode; use http_serde; use tokio_util::codec::Decoder as _; use vrl::value::{kind::Collection, Kind}; -use warp::http::HeaderMap; +use warp::http::{HeaderMap, HeaderName, HeaderValue}; use vector_lib::codecs::{ decoding::{DeserializerConfig, FramingConfig}, @@ -99,6 +99,14 @@ pub struct SimpleHttpConfig { #[configurable(metadata(docs::examples = "*"))] headers: Vec, + /// Custom response headers to be added to the HTTP response + #[serde(default)] + #[configurable(metadata(docs::examples = "example_custom_response_headers()"))] + #[configurable(metadata( + docs::additional_props_description = "A custom response header key-values pair" + ))] + custom_response_headers: HashMap>, + /// A list of URL query parameters to include in the log event. /// /// Accepts the wildcard (`*`) character for query parameters matching a specified pattern. @@ -176,6 +184,13 @@ pub struct SimpleHttpConfig { keepalive: KeepaliveConfig, } +fn example_custom_response_headers() -> HashMap> { + HashMap::>::from_iter([( + "Access-Control-Allow-Origin".to_string(), + vec!["my-cool-server".to_string(), "my-other-server".to_string()], + )]) +} + impl SimpleHttpConfig { /// Builds the `schema::Definition` for this source using the provided `LogNamespace`. fn schema_definition(&self, log_namespace: LogNamespace) -> Definition { @@ -271,6 +286,7 @@ impl Default for SimpleHttpConfig { address: "0.0.0.0:8080".parse().unwrap(), encoding: None, headers: Vec::new(), + custom_response_headers: HashMap::new(), query_parameters: Vec::new(), tls: None, auth: None, @@ -362,8 +378,28 @@ impl SourceConfig for SimpleHttpConfig { .build()? .with_log_namespace(log_namespace); + let custom_response_headers = self + .custom_response_headers + .clone() + .into_iter() + .map(|(k, v)| { + let parsed_key = k + .parse::() + .map_err(|e| format!("Failed to parse header key {}: {}", k, e))?; + let parsed_values = v + .into_iter() + .map(|v| { + v.parse::() + .map_err(|e| format!("Failed to parse header value {}: {}", v, e)) + }) + .collect::>()?; + Ok::<(HeaderName, Vec), String>((parsed_key, parsed_values)) + }) + .collect::>()?; + let source = SimpleHttpSource { headers: build_param_matcher(&remove_duplicates(self.headers.clone(), "headers"))?, + custom_response_headers, query_parameters: build_param_matcher(&remove_duplicates( self.query_parameters.clone(), "query_parameters", @@ -415,6 +451,7 @@ impl SourceConfig for SimpleHttpConfig { #[derive(Clone)] struct SimpleHttpSource { headers: Vec, + custom_response_headers: HashMap>, query_parameters: Vec, path_key: OptionalValuePath, host_key: OptionalValuePath, @@ -520,10 +557,29 @@ impl HttpSource for SimpleHttpSource { fn enable_source_ip(&self) -> bool { self.host_key.path.is_some() } + + /// Enriches the warp::reply::Reply with custom headers + /// + /// This method adds the custom headers specified in the configuration + /// to the HTTP response. + fn enrich_reply(&self, reply: T) -> Box { + let mut response = reply.into_response(); + let header_map = response.headers_mut(); + + for (key, values) in &self.custom_response_headers { + for value in values { + header_map + .try_append(key.clone(), value.clone()) + .expect("Failed to append header. Too many custom http headers specified in custom_response_headers config."); + } + } + Box::new(response) + } } #[cfg(test)] mod tests { + use std::collections::HashMap; use std::str::FromStr; use std::{io::Write, net::SocketAddr}; @@ -567,6 +623,7 @@ mod tests { #[allow(clippy::too_many_arguments)] async fn source<'a>( headers: Vec, + custom_response_headers: HashMap>, query_parameters: Vec, path_key: &'a str, host_key: &'a str, @@ -595,6 +652,7 @@ mod tests { SimpleHttpConfig { address, headers, + custom_response_headers, encoding: None, query_parameters, response_code, @@ -705,6 +763,7 @@ mod tests { let (rx, addr) = source( vec![], + HashMap::new(), vec![], "http_path", "remote_ip", @@ -751,6 +810,7 @@ mod tests { let mut events = assert_source_compliance(&HTTP_PUSH_SOURCE_TAGS, async move { let (rx, addr) = source( vec![], + HashMap::new(), vec![], "http_path", "remote_ip", @@ -790,6 +850,7 @@ mod tests { let mut events = assert_source_compliance(&HTTP_PUSH_SOURCE_TAGS, async move { let (rx, addr) = source( vec![], + HashMap::new(), vec![], "http_path", "remote_ip", @@ -823,6 +884,7 @@ mod tests { let mut events = assert_source_compliance(&HTTP_PUSH_SOURCE_TAGS, async { let (rx, addr) = source( vec![], + HashMap::new(), vec![], "http_path", "remote_ip", @@ -861,6 +923,7 @@ mod tests { let mut events = assert_source_compliance(&HTTP_PUSH_SOURCE_TAGS, async { let (rx, addr) = source( vec![], + HashMap::new(), vec![], "http_path", "remote_ip", @@ -906,6 +969,7 @@ mod tests { let mut events = assert_source_compliance(&HTTP_PUSH_SOURCE_TAGS, async { let (rx, addr) = source( vec![], + HashMap::new(), vec![], "http_path", "remote_ip", @@ -957,6 +1021,7 @@ mod tests { let mut events = assert_source_compliance(&HTTP_PUSH_SOURCE_TAGS, async { let (rx, addr) = source( vec![], + HashMap::new(), vec![], "http_path", "remote_ip", @@ -1043,6 +1108,7 @@ mod tests { "X-*".to_string(), "AbsentHeader".to_string(), ], + HashMap::new(), vec![], "http_path", "remote_ip", @@ -1089,6 +1155,7 @@ mod tests { let (rx, addr) = source( vec!["*".to_string()], + HashMap::new(), vec![], "http_path", "remote_ip", @@ -1122,11 +1189,65 @@ mod tests { } } + #[tokio::test] + async fn http_custom_response_headers() { + async fn send(address: SocketAddr, body: &str) -> reqwest::Response { + reqwest::Client::new() + .post(&format!("http://{}/", address)) + .body(body.to_owned()) + .send() + .await + .unwrap() + } + + assert_source_compliance(&HTTP_PUSH_SOURCE_TAGS, async { + let mut custom_headers: HashMap> = HashMap::new(); + custom_headers.insert( + "Access-Control-Allow-Origin".to_string(), + vec!["example.com".to_string(), "example2.com".to_string()], + ); + + let (rx, addr) = source( + vec!["*".to_string()], + custom_headers, + vec![], + "http_path", + "remote_ip", + "/", + "POST", + StatusCode::OK, + true, + EventStatus::Delivered, + true, + None, + Some(JsonDeserializerConfig::default().into()), + ) + .await; + + spawn_collect_n( + async move { + let response = send(addr, "{\"key1\":\"value1\"}").await; + let response_headers = response.headers(); + let view = response_headers.get_all("Access-Control-Allow-Origin"); + let mut iter = view.iter(); + assert_eq!(&"example.com", iter.next().unwrap()); + assert_eq!(&"example2.com", iter.next().unwrap()); + assert!(iter.next().is_none()); + }, + rx, + 1, + ) + .await + }) + .await; + } + #[tokio::test] async fn http_query() { let mut events = assert_source_compliance(&HTTP_PUSH_SOURCE_TAGS, async { let (rx, addr) = source( vec![], + HashMap::new(), vec![ "source".to_string(), "region".to_string(), @@ -1226,6 +1347,7 @@ mod tests { let (rx, addr) = source( vec![], + HashMap::new(), vec![], "http_path", "remote_ip", @@ -1257,6 +1379,7 @@ mod tests { let mut events = assert_source_compliance(&HTTP_PUSH_SOURCE_TAGS, async { let (rx, addr) = source( vec![], + HashMap::new(), vec![], "vector_http_path", "vector_remote_ip", @@ -1298,6 +1421,7 @@ mod tests { let mut events = assert_source_compliance(&HTTP_PUSH_SOURCE_TAGS, async { let (rx, addr) = source( vec![], + HashMap::new(), vec![], "vector_http_path", "vector_remote_ip", @@ -1359,6 +1483,7 @@ mod tests { components::init_test(); let (_rx, addr) = source( vec![], + HashMap::new(), vec![], "vector_http_path", "vector_remote_ip", @@ -1384,6 +1509,7 @@ mod tests { assert_source_compliance(&HTTP_PUSH_SOURCE_TAGS, async move { let (rx, addr) = source( vec![], + HashMap::new(), vec![], "http_path", "remote_ip", @@ -1418,6 +1544,7 @@ mod tests { assert_source_compliance(&HTTP_PUSH_SOURCE_TAGS, async { let (rx, addr) = source( vec![], + HashMap::new(), vec![], "http_path", "remote_ip", @@ -1449,6 +1576,7 @@ mod tests { let events = assert_source_compliance(&HTTP_PUSH_SOURCE_TAGS, async { let (rx, addr) = source( vec![], + HashMap::new(), vec![], "http_path", "remote_ip", @@ -1482,6 +1610,7 @@ mod tests { components::init_test(); let (_rx, addr) = source( vec![], + HashMap::new(), vec![], "http_path", "remote_ip", diff --git a/src/sources/util/http/prelude.rs b/src/sources/util/http/prelude.rs index cb054937fdc9c..2c6e8569c71e9 100644 --- a/src/sources/util/http/prelude.rs +++ b/src/sources/util/http/prelude.rs @@ -70,6 +70,11 @@ pub trait HttpSource: Clone + Send + Sync + 'static { decode(encoding_header, body) } + // This function can be defined to enrich `warp::Reply`s. + fn enrich_reply(&self, reply: T) -> Box { + Box::new(reply) + } + #[allow(clippy::too_many_arguments)] fn run( self, @@ -90,6 +95,7 @@ pub trait HttpSource: Clone + Send + Sync + 'static { let path = path.to_owned(); let acknowledgements = cx.do_acknowledgements(acknowledgements); let enable_source_ip = self.enable_source_ip(); + let self_clone = self.clone(); Ok(Box::pin(async move { let mut filter: BoxedFilter<()> = match method { @@ -171,21 +177,32 @@ pub trait HttpSource: Clone + Send + Sync + 'static { events }); - handle_request(events, acknowledgements, response_code, cx.out.clone()) + handle_request(events, acknowledgements, response_code, cx.out.clone()).map( + { + let self_clone = self.clone(); + move |result| { + result.map(move |reply| self_clone.enrich_reply(reply)) + } + }, + ) }, ); let ping = warp::get().and(warp::path("ping")).map(|| "pong"); - let routes = svc.or(ping).recover(|r: Rejection| async move { - if let Some(e_msg) = r.find::() { - let json = warp::reply::json(e_msg); - Ok(warp::reply::with_status(json, e_msg.status_code())) - } else { - //other internal error - will return 500 internal server error - emit!(HttpInternalError { - message: &format!("Internal error: {:?}", r) - }); - Err(r) + let routes = svc.or(ping).recover(move |r: Rejection| { + let self_clone = self_clone.clone(); + async move { + if let Some(e_msg) = r.find::() { + let json = warp::reply::json(e_msg); + Ok(self_clone + .enrich_reply(warp::reply::with_status(json, e_msg.status_code()))) + } else { + //other internal error - will return 500 internal server error + emit!(HttpInternalError { + message: &format!("Internal error: {:?}", r) + }); + Err(r) + } } }); diff --git a/website/cue/reference/components/sources/base/http.cue b/website/cue/reference/components/sources/base/http.cue index d53ca9b9f93fd..2541e46796aba 100644 --- a/website/cue/reference/components/sources/base/http.cue +++ b/website/cue/reference/components/sources/base/http.cue @@ -47,6 +47,20 @@ base: components: sources: http: configuration: { } } } + custom_response_headers: { + description: "Custom response headers to be added to the HTTP response" + required: false + type: object: { + examples: [{ + "Access-Control-Allow-Origin": ["my-cool-server", "my-other-server"] + }] + options: "*": { + description: "A custom response header key-values pair" + required: true + type: array: items: type: string: {} + } + } + } decoding: { description: "Configures how events are decoded from raw bytes." required: false diff --git a/website/cue/reference/components/sources/base/http_server.cue b/website/cue/reference/components/sources/base/http_server.cue index 543a97a42c96c..d5173f4f17dc2 100644 --- a/website/cue/reference/components/sources/base/http_server.cue +++ b/website/cue/reference/components/sources/base/http_server.cue @@ -47,6 +47,20 @@ base: components: sources: http_server: configuration: { } } } + custom_response_headers: { + description: "Custom response headers to be added to the HTTP response" + required: false + type: object: { + examples: [{ + "Access-Control-Allow-Origin": ["my-cool-server", "my-other-server"] + }] + options: "*": { + description: "A custom response header key-values pair" + required: true + type: array: items: type: string: {} + } + } + } decoding: { description: "Configures how events are decoded from raw bytes." required: false