Skip to content

Commit bc319dc

Browse files
fix(core): preserve allowedHeaders and fix hyphenated header names (#3383)
1 parent 61622db commit bc319dc

File tree

6 files changed

+114
-8
lines changed

6 files changed

+114
-8
lines changed

src/core/config/config_module/merge.rs

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ impl Invariant for Cache {
289289
.trace(&trace_name)
290290
}))
291291
.fuse(self.config.schema.unify(other.config.schema))
292-
.map( |(merged_types, merged_enums, schema)| {
292+
.map(|(merged_types, merged_enums, schema)| {
293293
types.extend(merged_types);
294294
enums.extend(merged_enums);
295295

@@ -298,6 +298,7 @@ impl Invariant for Cache {
298298
enums,
299299
unions: self.config.unions.merge_right(other.config.unions),
300300
schema,
301+
upstream: self.config.upstream.merge_right(other.config.upstream),
301302
..self.config
302303
};
303304

@@ -505,6 +506,91 @@ mod tests {
505506
Ok(())
506507
}
507508

509+
#[test]
510+
fn test_upstream_allowed_headers_propagation() -> Result<()> {
511+
use std::collections::BTreeSet;
512+
513+
use crate::core::config::Config;
514+
515+
// Create a Config with no allowed_headers
516+
let config1 = Config::default();
517+
518+
// Create a Config with allowed_headers
519+
let mut config2 = Config::default();
520+
let mut headers = BTreeSet::new();
521+
headers.insert("x-user-id".to_string());
522+
headers.insert("authorization".to_string());
523+
config2.upstream.allowed_headers = Some(headers.clone());
524+
525+
// Create Cache instances
526+
let cache1 = Cache::from(config1.clone());
527+
let cache2 = Cache::from(config2.clone());
528+
529+
// Verify initial state
530+
assert_eq!(cache1.config.upstream.allowed_headers, None);
531+
assert_eq!(
532+
cache2.config.upstream.allowed_headers,
533+
Some(headers.clone())
534+
);
535+
536+
// Test merging cache1 and cache2
537+
let merged = cache1.clone().unify(cache2.clone()).to_result()?;
538+
539+
// Verify that allowed_headers from cache2 are preserved in the merged cache
540+
assert_eq!(
541+
merged.config.upstream.allowed_headers,
542+
Some(headers.clone())
543+
);
544+
545+
// Test the reverse order (cache2 and cache1)
546+
let merged_reverse = cache2.unify(cache1).to_result()?;
547+
548+
// Verify that allowed_headers from cache2 are still preserved
549+
assert_eq!(
550+
merged_reverse.config.upstream.allowed_headers,
551+
Some(headers)
552+
);
553+
554+
Ok(())
555+
}
556+
557+
#[test]
558+
fn test_upstream_merge_right_order() -> Result<()> {
559+
use crate::core::config::Config;
560+
561+
// Create a Config with specific upstream settings
562+
let mut config1 = Config::default();
563+
config1.upstream.connect_timeout = Some(30);
564+
config1.upstream.timeout = Some(60);
565+
566+
// Create another Config with different upstream settings
567+
let mut config2 = Config::default();
568+
config2.upstream.timeout = Some(120); // This should override config1's timeout
569+
config2.upstream.http_cache = Some(1000); // This should be added to the merged config
570+
571+
// Create Cache instances
572+
let cache1 = Cache::from(config1.clone());
573+
let cache2 = Cache::from(config2.clone());
574+
575+
// Test merging cache1 and cache2
576+
let merged = cache1.clone().unify(cache2.clone()).to_result()?;
577+
578+
// Verify that values from cache2 override those from cache1
579+
assert_eq!(merged.config.upstream.connect_timeout, Some(30));
580+
assert_eq!(merged.config.upstream.timeout, Some(120)); // Should be from config2
581+
assert_eq!(merged.config.upstream.http_cache, Some(1000)); // Should be from config2
582+
583+
// Test the reverse order (cache2 and cache1)
584+
let merged_reverse = cache2.unify(cache1).to_result()?;
585+
586+
// Verify that values from cache1 override those from cache2
587+
assert_eq!(merged_reverse.config.upstream.connect_timeout, Some(30)); // Should be from config1
588+
assert_eq!(merged_reverse.config.upstream.timeout, Some(60)); // Should be from config1
589+
assert_eq!(merged_reverse.config.upstream.http_cache, Some(1000)); // Should be from config2
590+
591+
Ok(())
592+
}
593+
508594
mod core_type {
509595
use super::*;
510596
use crate::core::Type;

src/core/mustache/parse.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,14 @@ impl Mustache {
2121
fn parse_name(input: &str) -> IResult<&str, String> {
2222
let spaces = nom::character::complete::multispace0;
2323
let alpha = nom::character::complete::alpha1;
24-
let alphanumeric_or_underscore = nom::multi::many0(nom::branch::alt((
24+
let alphanumeric_or_underscore_or_hyphen = nom::multi::many0(nom::branch::alt((
2525
nom::character::complete::alphanumeric1,
2626
nom::bytes::complete::tag("_"),
27+
nom::bytes::complete::tag("-"),
2728
)));
2829

29-
let parser = nom::sequence::tuple((spaces, alpha, alphanumeric_or_underscore, spaces));
30+
let parser =
31+
nom::sequence::tuple((spaces, alpha, alphanumeric_or_underscore_or_hyphen, spaces));
3032

3133
nom::combinator::map(parser, |(_, a, b, _)| {
3234
let b: String = b.into_iter().collect();
@@ -269,4 +271,17 @@ mod tests {
269271
])])
270272
);
271273
}
274+
275+
#[test]
276+
fn test_hyphenated_variable_names() {
277+
let s = r"{{headers.user-id}}";
278+
let mustache: Mustache = Mustache::parse(s);
279+
assert_eq!(
280+
mustache,
281+
Mustache::from(vec![Segment::Expression(vec![
282+
"headers".to_string(),
283+
"user-id".to_string(),
284+
])])
285+
);
286+
}
272287
}

tests/core/snapshots/test-upstream-headers.md_0.snap

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
---
22
source: tests/core/spec.rs
33
expression: response
4-
snapshot_kind: text
54
---
65
{
76
"status": 200,
@@ -17,7 +16,9 @@ snapshot_kind: text
1716
{
1817
"id": 3
1918
}
20-
]
19+
],
20+
"fooField": "bar",
21+
"barField": "baz"
2122
}
2223
}
2324
}

tests/core/snapshots/test-upstream-headers.md_client.snap

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
---
22
source: tests/core/spec.rs
33
expression: formatted
4-
snapshot_kind: text
54
---
65
type Post {
76
id: Int
87
}
98

109
type Query {
10+
barField: String
11+
fooField: String
1112
posts: [Post]
1213
}
1314

tests/core/snapshots/test-upstream-headers.md_merged.snap

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
---
22
source: tests/core/spec.rs
33
expression: formatter
4-
snapshot_kind: text
54
---
65
schema @server @upstream(allowedHeaders: ["X-bar", "x-foo"]) @link(src: "schema_0.graphql", type: Config) {
76
query: Query
@@ -12,5 +11,7 @@ type Post {
1211
}
1312

1413
type Query {
14+
barField: String @expr(body: "{{.headers.x-bar}}")
15+
fooField: String @expr(body: "{{.headers.x-foo}}")
1516
posts: [Post] @http(url: "http://jsonplaceholder.typicode.com/posts")
1617
}

tests/execution/test-upstream-headers.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ schema {
1111
}
1212
type Query {
1313
posts: [Post] @http(url: "http://jsonplaceholder.typicode.com/posts")
14+
fooField: String @expr(body: "{{.headers.x-foo}}")
15+
barField: String @expr(body: "{{.headers.x-bar}}")
1416
}
1517
type Post {
1618
id: Int
@@ -44,5 +46,5 @@ type Post {
4446
X-foo: bar
4547
X-bar: baz
4648
body:
47-
query: query { posts { id } }
49+
query: query { posts { id } fooField barField }
4850
```

0 commit comments

Comments
 (0)