1use ast;
2use std::fmt;
3use format::{Displayable, Formatter, Style};
4
5use value;
6
7impl Displayable for ast::Main {
8 fn display(&self, f: &mut Formatter) {
9 for item in &self.directives {
10 item.display(f);
11 }
12 }
13}
14
15impl Displayable for ast::Directive {
16 fn display(&self, f: &mut Formatter) {
17 self.item.display(f)
18 }
19}
20
21fn simple_block<D: fmt::Display>(f: &mut Formatter, name: D,
22 directives: &[ast::Directive])
23{
24 f.margin();
25 f.indent();
26 f.fmt(&format_args!("{} ", name));
27 f.start_block();
28 for dir in directives {
29 dir.display(f);
30 }
31 f.end_block();
32}
33
34fn one_arg_dir(name: &str, val: &value::Value, f: &mut Formatter) {
35 f.indent();
36 f.write(name);
37 f.write(" ");
38 val.display(f);
39 f.end();
40}
41
42impl Displayable for ast::Item {
43 fn display(&self, f: &mut Formatter) {
44 use ast::Item::*;
45 match *self {
46 | Daemon(opt)
47 | MasterProcess(opt)
48 | ProxyPassRequestHeaders(opt)
49 | ProxyPassRequestBody(opt)
50 | ProxyInterceptErrors(opt)
51 | ProxyBuffering(opt)
52 | Gzip(opt)
53 | Etag(opt)
54 | RecursiveErrorPages(opt)
55 | ChunkedTransferEncoding(opt)
56 | RealIpRecursive(opt)
57 => {
58 f.indent();
59 f.write(self.directive_name());
60 f.write(" ");
61 f.write(if opt { "on" } else { "off" });
62 f.end();
63 }
64 WorkerProcesses(ast::WorkerProcesses::Auto) => {
65 f.indent();
66 f.write("worker_processes auto");
67 f.end();
68 }
69 WorkerProcesses(ast::WorkerProcesses::Exact(n)) => {
70 f.indent();
71 f.write("worker_processes ");
72 f.fmt(&n);
73 f.end();
74 }
75 Http(ref h) => {
76 simple_block(f, "http", &h.directives);
77 }
78 Server(ref s) => {
79 simple_block(f, "server", &s.directives);
80 }
81 Location(ast::Location { ref pattern, ref directives, .. }) => {
82 simple_block(f,
83 format_args!("location {}", pattern),
84 &directives);
85 }
86 LimitExcept(ast::LimitExcept { ref methods, ref directives, .. })
87 => {
88 simple_block(f,
89 format_args!("limit_except {}", methods.join(" ")),
90 &directives);
91 }
92 Listen(ref lst) => {
93 f.indent();
94 lst.display(f);
95 }
96 ProxySetHeader { ref field, ref value } => {
97 f.indent();
98 f.write("proxy_set_header ");
99 field.display(f);
100 f.write(" ");
101 value.display(f);
102 f.end();
103 }
104 GzipStatic(opt) => {
105 f.indent();
106 f.write("gzip_static ");
107 f.write(opt.as_str());
108 f.end();
109 }
110 GzipProxied(ref opt) => {
111 f.indent();
112 f.write("gzip_proxied");
113 for item in opt {
114 f.write(" ");
115 f.write(item.as_str());
116 }
117 f.end();
118 }
119 AddHeader(ref h) => {
120 f.indent();
121 f.write("add_header ");
122 h.field.display(f);
123 f.write(" ");
124 h.value.display(f);
125 if h.always {
126 f.write(" always");
127 }
128 f.end();
129 }
130 ServerName(ref items) => {
131 use ast::ServerName::*;
132 f.indent();
133 f.write("server_name");
134 for item in items {
135 match *item {
136 Exact(ref v)
137 => f.fmt(&format_args!(" {}", escape(&v))),
138 Suffix(ref v)
139 => f.fmt(&format_args!(" .{}", escape(&v))),
140 StarSuffix(ref v)
141 => f.fmt(&format_args!(" *.{}", escape(&v))),
142 StarPrefix(ref v)
143 => f.fmt(&format_args!(" {}.*", escape(&v))),
144 Regex(ref v)
145 => f.fmt(&format_args!(" ~{}", escape(&v))),
146 }
147 }
148 f.end();
149 }
150 Set { ref variable, ref value } => {
151 f.indent();
152 f.write("set $");
153 f.write(variable); f.write(" ");
155 value.display(f);
156 f.end();
157 }
158 Map(ref m) => {
159 use ast::MapPattern::*;
160 f.margin();
161 f.indent();
162 f.write("map ");
163 m.expression.display(f);
164 f.write(" $");
165 f.write(&m.variable); f.write(" ");
167 f.start_block();
168 if m.volatile {
169 f.indent();
170 f.write("volatile");
171 f.end();
172 }
173 if m.hostnames {
174 f.indent();
175 f.write("hostnames");
176 f.end();
177 }
178 if let Some(ref def) = m.default {
179 f.indent();
180 f.write("default ");
181 def.display(f);
182 f.end();
183 }
184 for inc in &m.includes {
185 f.indent();
186 f.write("include ");
187 f.write(escape(inc));
188 f.end();
189 }
190 for &(ref pat, ref value) in &m.patterns {
191 f.indent();
192 match *pat {
193 Exact(ref v) if matches!(&v[..],
194 | "volatile"
195 | "hostnames"
196 | "default"
197 | "include"
198 ) => f.fmt(&format_args!("\\{}", escape(&v))),
199 Exact(ref v)
200 => f.fmt(&format_args!("{}", escape(&v))),
201 Suffix(ref v)
202 => f.fmt(&format_args!(".{}", escape(&v))),
203 StarSuffix(ref v)
204 => f.fmt(&format_args!("*.{}", escape(&v))),
205 StarPrefix(ref v)
206 => f.fmt(&format_args!("{}.*", escape(&v))),
207 Regex(ref v)
208 => f.fmt(&format_args!("~{}", escape(&v))),
209 }
210 f.write(" ");
211 value.display(f);
212 f.end();
213 }
214 f.end_block();
215 }
216 Rewrite(ref rw) => {
217 use ast::RewriteFlag::*;
218 f.indent();
219 f.write("rewrite ");
220 f.write(escape(&rw.regex));
221 f.write(" ");
222 rw.replacement.display(f);
223 f.write(match rw.flag {
224 Some(Last) => " last",
225 Some(Break) => " break",
226 Some(Redirect) => " redirect",
227 Some(Permanent) => " permanent",
228 None => "",
229 });
230 f.end();
231 }
232 | Root(ref val)
233 | Alias(ref val)
234 | DefaultType(ref val)
235 | ClientMaxBodySize(ref val)
236 | Include(ref val)
237 | RewriteByLuaFile(ref val)
238 | BalancerByLuaFile(ref val)
239 | AccessByLuaFile(ref val)
240 | HeaderFilterByLuaFile(ref val)
241 | ContentByLuaFile(ref val)
242 | BodyFilterByLuaFile(ref val)
243 | LogByLuaFile(ref val)
244 | LuaNeedRequestBody(ref val)
245 | SslCertificateByLuaFile(ref val)
246 | SslSessionFetchByLuaFile(ref val)
247 | SslSessionStoreByLuaFile(ref val)
248 | SslCertificate(ref val)
249 | SslCertificateKey(ref val)
250 | ProxyPass(ref val)
251 | ProxyCache(ref val)
252 | ProxyCacheKey(ref val)
253 | ProxyMethod(ref val)
254 | ProxyReadTimeout(ref val)
255 | ProxyConnectTimeout(ref val)
256 | ProxyHideHeader(ref val)
257 | ProxyPassHeader(ref val)
258 | ProxyNextUpstreamTries(ref val)
259 | ProxyNextUpstreamTimeout(ref val)
260 | ServerTokens(ref val)
261 | RealIpHeader(ref val)
262 => {
263 one_arg_dir(self.directive_name(), val, f);
264 }
265 | EmptyGif
266 | Internal
267 => {
268 f.indent();
269 f.write(self.directive_name());
270 f.end();
271 }
272 ErrorPage(ref ep) => {
273 use ast::ErrorPageResponse::*;
274 f.indent();
275 f.write("error_page");
276 for code in &ep.codes {
277 f.write(" ");
278 f.fmt(code);
279 }
280 match ep.response_code {
281 Target => {},
282 Replace(ref code) => { f.write(" ="); f.fmt(code); }
283 Redirect(ref code) => { f.write(" ="); f.fmt(code); }
284 Keep => { f.write(" ="); }
285 }
286 f.write(" ");
287 ep.uri.display(f);
288 f.end()
289 }
290 Return(ref ret) => {
291 use ast::Return::*;
292 f.indent();
293 f.write("return ");
294 match ret {
295 Redirect { code: None, url } => url.display(f),
296 Redirect { code: Some(code), url } => {
297 f.fmt(&code);
298 f.write(" ");
299 url.display(f);
300 }
301 Text { code, text } => {
302 f.fmt(&code);
303 match text {
304 Some(v) => {
305 f.write(" ");
306 v.display(f);
307 }
308 None => {}
309 }
310 }
311 }
312 f.end()
313 }
314 TryFiles(ref tf) => {
315 use ast::TryFilesLastOption::*;
316 f.indent();
317 f.write("try_files ");
318 for item in &tf.options {
319 item.display(f);
320 f.write(" ");
321 }
322 match tf.last_option {
323 Uri(ref v) => v.display(f),
324 NamedLocation(ref loc) => {
325 f.write("@");
326 f.write(&loc);
327 }
328 Code(code) => {
329 f.write("=");
330 f.fmt(&code);
331 }
332 }
333 f.end();
334 }
335 Expires(::ast::Expires { modified, ref value }) => {
336 f.indent();
337 f.write("expires ");
338 if modified {
339 f.write("modified ");
340 }
341 value.display(f);
342 f.end();
343 }
344 If(ast::If { ref condition, ref directives, position: _ }) => {
345 use ast::IfCondition::*;
346 f.indent();
347 f.write("if (");
348 match condition {
349 NonEmpty(ref v) => v.display(f),
350 Eq(ref v, ref s) => {
351 v.display(f);
352 f.write(" = ");
353 f.write(&escape(s));
354 }
355 Neq(ref v, ref s) => {
356 v.display(f);
357 f.write(" != ");
358 f.write(&escape(s));
359 }
360 RegEq(ref v, ref r, case) => {
361 v.display(f);
362 if *case {
363 f.write(" ~ ");
364 } else {
365 f.write(" ~* ");
366 }
367 f.write(&escape(r));
368 }
369 RegNeq(ref v, ref r, case) => {
370 v.display(f);
371 if *case {
372 f.write(" !~ ");
373 } else {
374 f.write(" !~* ");
375 }
376 f.write(&escape(r));
377 }
378 Exists(ref v) => {
379 f.write("-e ");
380 v.display(f);
381 }
382 NotExists(ref v) => {
383 f.write("!-e ");
384 v.display(f);
385 },
386 FileExists(ref v) => {
387 f.write("-f ");
388 v.display(f);
389 },
390 FileNotExists(ref v) => {
391 f.write("!-f ");
392 v.display(f);
393 },
394 DirExists(ref v) => {
395 f.write("-d ");
396 v.display(f);
397 },
398 DirNotExists(ref v) => {
399 f.write("!-d ");
400 v.display(f);
401 },
402 Executable(ref v) => {
403 f.write("-x ");
404 v.display(f);
405 },
406 NotExecutable(ref v) => {
407 f.write("!-x ");
408 v.display(f);
409 },
410 }
411 f.write(") ");
412 f.start_block();
413 for dir in directives {
414 dir.display(f);
415 }
416 f.end_block();
417 }
418 Allow(ref source) | Deny(ref source) => {
419 use ast::Source::*;
420 f.indent();
421 f.write(self.directive_name());
422 f.write(" ");
423 match source {
424 All => f.write("all"),
425 Unix => f.write("unix:"),
426 Ip(ip) => f.fmt(ip),
427 Network(ip, bits) => {
428 f.fmt(ip);
429 f.write("/");
430 f.fmt(bits);
431 }
432 }
433 f.end();
434 }
435 ProxyHttpVersion(ver) => {
436 use ast::ProxyHttpVersion::*;
437 f.indent();
438 match ver {
439 V1_0 => f.write("proxy_http_version 1.0"),
440 V1_1 => f.write("proxy_http_version 1.1"),
441 }
442 f.end();
443 }
444 ProxyIgnoreHeaders(ref headers) => {
445 f.indent();
446 f.write(self.directive_name());
447 for h in headers {
448 f.write(" ");
449 f.write(&escape(h));
450 }
451 f.end();
452 }
453 ProxyCacheValid(ref val) => {
454 use ast::ProxyCacheValid::*;
455 f.indent();
456 f.write(self.directive_name());
457 match val {
458 Normal(ref val) => {
459 f.write(" ");
460 val.display(f);
461 }
462 Specific(ref codes, ref val) => {
463 for code in codes {
464 f.write(" ");
465 f.fmt(&code);
466 }
467 f.write(" ");
468 val.display(f);
469 }
470 Any(ref val) => {
471 f.write(" any ");
472 val.display(f);
473 }
474 }
475 f.end();
476 }
477 KeepaliveTimeout(ref timeo, ref header_timeo) => {
478 f.indent();
479 f.write(self.directive_name());
480 f.write(" ");
481 timeo.display(f);
482 if let Some(header_timeo) = header_timeo {
483 f.write(" ");
484 header_timeo.display(f);
485 }
486 f.end();
487 }
488 ProxyNextUpstream(ref items) => {
489 use ast::ProxyNextUpstreamFlag::*;
490 f.indent();
491 f.write(self.directive_name());
492 for item in items {
493 f.write(" ");
494 f.write(match item {
495 Error => "error",
496 Timeout => "timeout",
497 InvalidHeader => "invalid_header",
498 Http500 => "http_500",
499 Http502 => "http_502",
500 Http503 => "http_503",
501 Http504 => "http_504",
502 Http403 => "http_403",
503 Http404 => "http_404",
504 Http429 => "http_429",
505 NonIdempotent => "non_idempotent",
506 Off => "off",
507 });
508 }
509 f.end();
510 }
511 AccessLog(ast::AccessLog::Off) => {
512 f.indent();
513 f.write("access_log off");
514 f.end();
515 }
516 AccessLog(ast::AccessLog::On(ref lg)) => {
517 f.indent();
518 f.write("access_log ");
519 lg.path.display(f);
520 if let Some(ref fmt) = lg.format {
521 f.write(" ");
522 f.fmt(&escape(fmt));
523 }
524 if let Some(ref buf) = lg.buffer {
525 f.write(" buffer=");
526 f.fmt(&escape(buf));
527 }
528 if let Some(ref gzip) = lg.gzip {
529 if let Some(level) = gzip {
530 f.write(" gzip=");
531 f.fmt(&level);
532 } else {
533 f.write(" gzip");
534 }
535 }
536 if let Some(ref flush) = lg.flush {
537 f.write(" flush=");
538 f.fmt(&escape(flush));
539 }
540 if let Some(ref condition) = lg.condition {
541 f.write(" if=");
542 condition.display(f);
543 }
544 f.end();
545 }
546 SetRealIpFrom(ref source) => {
547 use ast::RealIpFrom::*;
548 f.indent();
549 f.write(self.directive_name());
550 f.write(" ");
551 match source {
552 Unix => f.write("unix:"),
553 Ip(ip) => f.fmt(ip),
554 Network(ip, bits) => {
555 f.fmt(ip);
556 f.write("/");
557 f.fmt(bits);
558 }
559 }
560 f.end();
561 }
562 ErrorLog { ref file, level } => {
563 f.indent();
564 f.write(self.directive_name());
565 f.write(" ");
566 file.display(f);
567 if let Some(level) = level {
568 use ast::ErrorLevel::*;
569 f.write(" ");
570 f.write(match level {
571 Debug => "debug",
572 Info => "info",
573 Notice => "notice",
574 Warn => "warn",
575 Error => "error",
576 Crit => "crit",
577 Alert => "alert",
578 Emerg => "emerg",
579 });
580 }
581 f.end();
582 }
583 Index(ref items) => {
584 f.indent();
585 f.write("index");
586 for item in items {
587 f.write(" ");
588 item.display(f);
589 }
590 f.end();
591 }
592 }
593 }
594}
595
596impl Displayable for ast::Listen {
597 fn display(&self, f: &mut Formatter) {
598 f.write("listen ");
599 self.address.display(f);
600 if self.default_server { f.write(" default_server") }
601 if self.ssl { f.write(" ssl") }
602 match self.ext {
603 Some(ast::HttpExt::Http2) => f.write(" http2"),
604 Some(ast::HttpExt::Spdy) => f.write(" spdy"),
605 None => {}
606 }
607 if self.proxy_protocol { f.write(" proxy_protocol") }
608 if let Some(setfib) = self.setfib {
609 f.fmt(&format_args!(" setfib={}", setfib));
610 }
611 if let Some(fastopen) = self.fastopen {
612 f.fmt(&format_args!(" fastopen={}", fastopen));
613 }
614 if let Some(backlog) = self.backlog {
615 f.fmt(&format_args!(" backlog={}", backlog));
616 }
617 if let Some(rcvbuf) = self.rcvbuf {
618 f.fmt(&format_args!(" rcvbuf={}", rcvbuf));
619 }
620 if let Some(sndbuf) = self.sndbuf {
621 f.fmt(&format_args!(" sndbuf={}", sndbuf));
622 }
623 if self.deferred { f.write(" deferred") }
624 if self.bind { f.write(" bind") }
625 if let Some(ipv6only) = self.ipv6only {
626 f.fmt(&format_args!(" ipv6only={}",
627 if ipv6only { "on" } else { "off" }));
628 }
629 if self.reuseport { f.write(" reuseport") }
630 f.end();
631 }
632}
633
634impl Displayable for ast::Address {
635 fn display(&self, f: &mut Formatter) {
636 use ast::Address::*;
637 match *self {
638 Ip(sa) => f.fmt(&sa),
639 StarPort(p) => f.fmt(&format_args!("*:{}", p)),
640 Port(p) => f.fmt(&p),
641 Unix(ref path) => f.fmt(&format_args!("unix:{}", path.display())),
643 }
644 }
645}
646
647fn to_string<T: Displayable>(v: &T) -> String {
648 let style = Style::default();
649 let mut formatter = Formatter::new(&style);
650 v.display(&mut formatter);
651 formatter.into_string()
652}
653
654macro_rules! impl_display {
655 ($( $typ: ty, )+) => {
656 $(
657 impl fmt::Display for $typ {
658 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
659 f.write_str(&to_string(self))
660 }
661 }
662 )+
663 };
664}
665
666impl_display!(
667 ast::Main,
668 ast::Listen,
669 ast::Address,
670 ast::Directive,
671 ast::Item,
672 value::Value,
673);
674
675fn escape(s: &str) -> &str {
676 return s
678}
679
680impl fmt::Display for ast::LocationPattern {
681 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
682 use ast::LocationPattern::*;
683 match *self {
684 Prefix(ref p) => f.write_str(escape(p)),
685 Exact(ref p) => write!(f, "= {}", escape(p)),
686 FinalPrefix(ref p) => write!(f, "^~ {}", escape(p)),
687 Regex(ref p) => write!(f, "~ {}", escape(p)),
688 RegexInsensitive(ref p) => write!(f, "~* {}", escape(p)),
689 Named(ref name) => {
690 write!(f, "{}", escape(&(String::from("@") + name)))
691 }
692 }
693 }
694}
695
696impl ast::GzipStatic {
697 fn as_str(&self) -> &str {
698 use ast::GzipStatic::*;
699 match *self {
700 On => "on",
701 Off => "off",
702 Always => "always",
703 }
704 }
705}
706
707impl ast::GzipProxied {
708 fn as_str(&self) -> &str {
709 use ast::GzipProxied::*;
710 match *self {
711 Off => "off",
712 Expired => "expired",
713 NoCache => "no-cache",
714 NoStore => "no-store",
715 Private => "private",
716 NoLastModified => "no_last_modified",
717 NoEtag => "no_etag",
718 Auth => "auth",
719 Any => "any",
720 }
721 }
722}
723
724
725impl fmt::Display for ast::GzipStatic {
726 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
727 self.as_str().fmt(f)
728 }
729}
730
731impl fmt::Display for ast::GzipProxied {
732 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
733 self.as_str().fmt(f)
734 }
735}