Skip to content

Commit d1635ee

Browse files
authored
Merge pull request #78 from mkantor/request-headers
Handle request headers, including them in render data.
2 parents 38bdef7 + a6ff4bb commit d1635ee

File tree

13 files changed

+393
-49
lines changed

13 files changed

+393
-49
lines changed
Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
1-
{{error-code}} {{request.route}}{{#each request.query-parameters}}
2-
{{@key}}: {{this}}{{/each}}
1+
{{error-code}} {{request.route}}
2+
query parameters:{{#each request.query-parameters}}
3+
{{@key}}: {{this}}{{/each}}
4+
{{!-- don't emit headers in snapshot tests (for parity with get command) --}}
5+
request headers:{{~#unless request.request-headers.is-operator-snapshot-test}}{{#each request.request-headers}}
6+
{{@key}}: {{this}}{{/each}}{{/unless~}}
Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
#!/bin/sh
22

3-
# Ensure that we get the same output whether served over HTTP or not.
4-
echo "$OPERATOR_RENDER_DATA" \
5-
| sed -E 's/"socket-address":"[^"]*"/"socket-address":null/' \
6-
| sed -E 's/"socket-address":null/"socket-address":"$SOCKET_ADDRESS"/'
3+
render_data_without_socket_address=$(
4+
echo "$OPERATOR_RENDER_DATA" \
5+
| sed -E 's/"socket-address":"[^"]*"/"socket-address":null/' \
6+
| sed -E 's/"socket-address":null/"socket-address":"$SOCKET_ADDRESS"/'
7+
)
8+
9+
# Ensure that snapshot tests produce the same output for HTTP and get command.
10+
if [ "${render_data_without_socket_address#*'"is-operator-snapshot-test":"true"'}" != "$render_data_without_socket_address" ]
11+
then
12+
echo "$render_data_without_socket_address" \
13+
| sed -E 's/"request-headers":\{[^}]*\}/"request-headers":\{\}/'
14+
else
15+
echo "$render_data_without_socket_address"
16+
fi

src/cli.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::http::QueryString;
33
use crate::*;
44
use futures::executor;
55
use futures::stream::TryStreamExt;
6+
use std::collections::HashMap;
67
use std::io;
78
use std::net::ToSocketAddrs;
89
use thiserror::Error;
@@ -128,7 +129,11 @@ pub fn eval<I: io::Read, O: io::Write>(
128129

129130
let query_parameters = query_string.unwrap_or_default();
130131

131-
let render_context = content_engine.render_context(None, query_parameters.into());
132+
// Request headers cannot be specified on the CLI (yet).
133+
let request_headers = HashMap::new();
134+
135+
let render_context =
136+
content_engine.render_context(None, query_parameters.into(), request_headers);
132137
let media = content_item.render(render_context, &[mime::STAR_STAR])?;
133138

134139
executor::block_on(media.content.try_for_each(|bytes| {
@@ -166,8 +171,14 @@ pub fn get<O: io::Write>(
166171

167172
let query_parameters = query_string.unwrap_or_default();
168173

169-
let render_context =
170-
content_engine.render_context(Some(route.clone()), query_parameters.into());
174+
// Request headers cannot be specified on the CLI (yet).
175+
let request_headers = HashMap::new();
176+
177+
let render_context = content_engine.render_context(
178+
Some(route.clone()),
179+
query_parameters.into(),
180+
request_headers,
181+
);
171182
let media = content_item.render(render_context, &[accept.unwrap_or(mime::STAR_STAR)])?;
172183

173184
executor::block_on(media.content.try_for_each(|bytes| {

src/content/content_engine.rs

Lines changed: 64 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ where
5858
&self,
5959
request_route: Option<Route>,
6060
query_parameters: HashMap<String, String>,
61+
request_headers: HashMap<String, String>,
6162
) -> RenderContext<ServerInfo, Self>;
6263

6364
fn new_template(
@@ -378,6 +379,7 @@ where
378379
&self,
379380
route: Option<Route>,
380381
query_parameters: HashMap<String, String>,
382+
request_headers: HashMap<String, String>,
381383
) -> RenderContext<ServerInfo, Self> {
382384
RenderContext {
383385
content_engine: self,
@@ -389,6 +391,7 @@ where
389391
request: RequestData {
390392
route,
391393
query_parameters,
394+
request_headers,
392395
},
393396
},
394397
}
@@ -472,7 +475,7 @@ mod tests {
472475
.expect("Template could not be parsed");
473476
let rendered = renderable
474477
.render(
475-
content_engine.render_context(None, HashMap::new()),
478+
content_engine.render_context(None, HashMap::new(), HashMap::new()),
476479
&[mime::TEXT_HTML],
477480
)
478481
.expect(&format!("Template rendering failed for `{}`", template));
@@ -531,7 +534,7 @@ mod tests {
531534
.expect("Template could not be parsed");
532535
let rendered = renderable
533536
.render(
534-
content_engine.render_context(None, HashMap::new()),
537+
content_engine.render_context(None, HashMap::new(), HashMap::new()),
535538
&[mime::TEXT_HTML],
536539
)
537540
.expect(&format!("Template rendering failed for `{}`", template));
@@ -562,7 +565,7 @@ mod tests {
562565
.expect("Content could not be found");
563566
let rendered = content
564567
.render(
565-
content_engine.render_context(None, HashMap::new()),
568+
content_engine.render_context(None, HashMap::new(), HashMap::new()),
566569
&[mime::TEXT_HTML],
567570
)
568571
.expect(&format!(
@@ -630,7 +633,7 @@ mod tests {
630633
.expect("Template could not be parsed");
631634
let rendered = renderable
632635
.render(
633-
content_engine.render_context(None, HashMap::new()),
636+
content_engine.render_context(None, HashMap::new(), HashMap::new()),
634637
&[mime::TEXT_HTML],
635638
)
636639
.expect(&format!("Template rendering failed for `{}`", template));
@@ -669,7 +672,7 @@ mod tests {
669672
)
670673
.expect("Template could not be parsed");
671674
let result = renderable.render(
672-
content_engine.render_context(None, HashMap::new()),
675+
content_engine.render_context(None, HashMap::new(), HashMap::new()),
673676
&[mime::TEXT_HTML],
674677
);
675678
assert!(
@@ -698,7 +701,7 @@ mod tests {
698701
None => panic!("No content was found at '{}'", route),
699702
Some(renderable) => {
700703
let result = renderable.render(
701-
content_engine.render_context(None, HashMap::new()),
704+
content_engine.render_context(None, HashMap::new(), HashMap::new()),
702705
&[mime::TEXT_HTML],
703706
);
704707
assert!(
@@ -728,7 +731,7 @@ mod tests {
728731
)
729732
.expect("Template could not be created");
730733
let result = template.render(
731-
content_engine.render_context(None, HashMap::new()),
734+
content_engine.render_context(None, HashMap::new(), HashMap::new()),
732735
&[mime::TEXT_PLAIN],
733736
);
734737

@@ -756,7 +759,7 @@ mod tests {
756759
None => panic!("No content was found at '{}'", route),
757760
Some(renderable) => {
758761
let result = renderable.render(
759-
content_engine.render_context(None, HashMap::new()),
762+
content_engine.render_context(None, HashMap::new(), HashMap::new()),
760763
&[target_media_type],
761764
);
762765
assert!(
@@ -789,7 +792,7 @@ mod tests {
789792
)
790793
.expect("Test template was invalid")
791794
.render(
792-
content_engine.render_context(None, HashMap::new()),
795+
content_engine.render_context(None, HashMap::new(), HashMap::new()),
793796
&[mime::TEXT_PLAIN],
794797
)
795798
.expect("Failed to render unregistered template"),
@@ -802,7 +805,7 @@ mod tests {
802805
.get(&route("/echo-target-media-type"))
803806
.expect("Test template does not exist")
804807
.render(
805-
content_engine.render_context(None, HashMap::new()),
808+
content_engine.render_context(None, HashMap::new(), HashMap::new()),
806809
&[mime::TEXT_HTML],
807810
)
808811
.expect("Failed to render registered template"),
@@ -835,7 +838,7 @@ mod tests {
835838
.expect("Content could not be found");
836839
let rendered = content
837840
.render(
838-
content_engine.render_context(None, HashMap::new()),
841+
content_engine.render_context(None, HashMap::new(), HashMap::new()),
839842
&[mime::TEXT_PLAIN],
840843
)
841844
.expect(&format!("Rendering failed for content at '{}'", route));
@@ -866,7 +869,7 @@ mod tests {
866869
.expect("Content could not be found");
867870
let rendered = content
868871
.render(
869-
content_engine.render_context(None, HashMap::new()),
872+
content_engine.render_context(None, HashMap::new(), HashMap::new()),
870873
&[mime::TEXT_PLAIN],
871874
)
872875
.expect(&format!("Rendering failed for content at '{}'", route1));
@@ -889,7 +892,7 @@ mod tests {
889892
.expect("Content could not be found");
890893
let rendered = content
891894
.render(
892-
content_engine.render_context(None, HashMap::new()),
895+
content_engine.render_context(None, HashMap::new(), HashMap::new()),
893896
&[mime::TEXT_PLAIN],
894897
)
895898
.expect(&format!("Rendering failed for content at '{}'", route2));
@@ -918,7 +921,7 @@ mod tests {
918921
.expect("Content could not be found");
919922

920923
let result1 = content.render(
921-
content_engine.render_context(None, HashMap::new()),
924+
content_engine.render_context(None, HashMap::new(), HashMap::new()),
922925
&[mime::TEXT_PLAIN], // Not text/html!
923926
);
924927
assert!(
@@ -928,7 +931,7 @@ mod tests {
928931
);
929932

930933
let result2 = content.render(
931-
content_engine.render_context(None, HashMap::new()),
934+
content_engine.render_context(None, HashMap::new(), HashMap::new()),
932935
&[mime::TEXT_HTML],
933936
);
934937
assert!(
@@ -952,7 +955,7 @@ mod tests {
952955

953956
let media = content
954957
.render(
955-
content_engine.render_context(None, HashMap::new()),
958+
content_engine.render_context(None, HashMap::new(), HashMap::new()),
956959
&[mime::APPLICATION_OCTET_STREAM],
957960
)
958961
.expect(&format!(
@@ -985,7 +988,7 @@ mod tests {
985988
.expect("Content could not be found");
986989
let rendered = content
987990
.render(
988-
content_engine.render_context(None, HashMap::new()),
991+
content_engine.render_context(None, HashMap::new(), HashMap::new()),
989992
&[mime::TEXT_PLAIN],
990993
)
991994
.expect(&format!("Rendering failed for content at '{}'", route));
@@ -1060,7 +1063,50 @@ mod tests {
10601063
.expect("Template could not be parsed");
10611064
let rendered = renderable
10621065
.render(
1063-
content_engine.render_context(None, query_parameters),
1066+
content_engine.render_context(None, query_parameters, HashMap::new()),
1067+
&[mime::TEXT_PLAIN],
1068+
)
1069+
.expect(&format!("Template rendering failed for `{}`", template));
1070+
let actual_output = media_to_string(rendered);
1071+
1072+
assert!(
1073+
expected_outputs.contains(&actual_output),
1074+
"Template rendering for `{}` did not produce expected output (any of {:?}), got \"{}\"",
1075+
template,
1076+
expected_outputs,
1077+
actual_output,
1078+
);
1079+
}
1080+
1081+
#[test]
1082+
fn templates_receive_request_headers() {
1083+
let shared_content_engine = TestContentEngine::from_content_directory(
1084+
arbitrary_content_directory_with_valid_content(),
1085+
(),
1086+
)
1087+
.expect("Content engine could not be created");
1088+
let content_engine = shared_content_engine.read().unwrap();
1089+
1090+
let template = "{{#each request.request-headers}}{{@key}}: {{this}}\n{{/each}}";
1091+
1092+
let request_headers = hashmap![
1093+
String::from("hello") => String::from("world"),
1094+
String::from("goodbye") => String::from("moon"),
1095+
];
1096+
let expected_outputs = [
1097+
String::from("hello: world\ngoodbye: moon\n"),
1098+
String::from("goodbye: moon\nhello: world\n"),
1099+
];
1100+
1101+
let renderable = content_engine
1102+
.new_template(
1103+
template,
1104+
MediaType::from_media_range(mime::TEXT_PLAIN).unwrap(),
1105+
)
1106+
.expect("Template could not be parsed");
1107+
let rendered = renderable
1108+
.render(
1109+
content_engine.render_context(None, HashMap::new(), request_headers),
10641110
&[mime::TEXT_PLAIN],
10651111
)
10661112
.expect(&format!("Template rendering failed for `{}`", template));

src/content/content_item.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ mod tests {
263263
request: RequestData {
264264
route: None,
265265
query_parameters: HashMap::new(),
266+
request_headers: HashMap::new(),
266267
},
267268
}
268269
}
@@ -315,7 +316,9 @@ mod tests {
315316
.expect("Test template was invalid");
316317
let rendered = template.render_to_native_media_type(
317318
content_engine.handlebars_registry(),
318-
content_engine.render_context(None, HashMap::new()).data,
319+
content_engine
320+
.render_context(None, HashMap::new(), HashMap::new())
321+
.data,
319322
);
320323

321324
let template_output = media_to_string(rendered.expect("Rendering failed"));
@@ -336,7 +339,7 @@ mod tests {
336339
let rendered = template.render_to_native_media_type(
337340
content_engine.handlebars_registry(),
338341
content_engine
339-
.render_context(Some(route("/test")), HashMap::new())
342+
.render_context(Some(route("/test")), HashMap::new(), HashMap::new())
340343
.data,
341344
);
342345

0 commit comments

Comments
 (0)