PageRenderTime 47ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/DDG/Rewrite.pm

https://github.com/a-West/duckduckgo
Perl | 153 lines | 116 code | 29 blank | 8 comment | 21 complexity | e84dae01fa9ceee41414e2d5406445e2 MD5 | raw file
  1. package DDG::Rewrite;
  2. # ABSTRACT: A (mostly spice related) Rewrite definition in our system
  3. use Moo;
  4. use Carp qw( croak );
  5. use URI;
  6. sub BUILD {
  7. my ( $self ) = @_;
  8. my $to = $self->to;
  9. my $callback = $self->has_callback ? $self->callback : "";
  10. croak "Missing callback attribute for {{callback}} in to" if ($to =~ s/{{callback}}/$callback/g && !$self->has_callback);
  11. # Make sure we replace "{{dollar}}"" with "{dollar}".
  12. $to =~ s/{{dollar}}/\$\{dollar\}/g;
  13. my @missing_envs;
  14. for ($to =~ m/{{ENV{(\w+)}}}/g) {
  15. if (defined $ENV{$_}) {
  16. my $val = $ENV{$_};
  17. $to =~ s/{{ENV{$_}}}/$val/g;
  18. } else {
  19. push @missing_envs, $_;
  20. $to =~ s/{{ENV{$_}}}//g;
  21. }
  22. }
  23. $self->_missing_envs(\@missing_envs) if @missing_envs;
  24. $self->_parsed_to($to);
  25. }
  26. =head1 SYNOPSIS
  27. my $rewrite = DDG::Rewrite->new(
  28. path => '/js/test/',
  29. to => 'http://some.api/$1',
  30. );
  31. print $rewrite->nginx_conf;
  32. # location ^~ /js/test/ {
  33. # rewrite ^/js/test/(.*) /$1 break;
  34. # proxy_pass http://some.api:80/;
  35. # }
  36. my $missing_rewrite = DDG::Rewrite->new(
  37. path => '/js/test/',
  38. to => 'http://some.api/$1/?key={{ENV{DDGTEST_DDG_REWRITE_TEST_API_KEY}}}',
  39. );
  40. if ($missing_rewrite->missing_envs) { ... }
  41. # is false if $ENV{DDGTEST_DDG_REWRITE_TEST_API_KEY} is not set
  42. =head1 DESCRIPTION
  43. This class is used to contain a definition for a rewrite in our system. So far its specific
  44. designed for the problems we face towards spice redirects, but the definition is used in
  45. the L<App::DuckPAN> test server. In the production system we use those definitions to
  46. generate an L<nginx|http://duckduckgo.com/?q=nginx> config.
  47. =cut
  48. has path => (
  49. is => 'ro',
  50. required => 1,
  51. );
  52. has to => (
  53. is => 'ro',
  54. required => 1,
  55. );
  56. has from => (
  57. is => 'ro',
  58. predicate => 'has_from',
  59. );
  60. has callback => (
  61. is => 'ro',
  62. predicate => 'has_callback',
  63. );
  64. has wrap_jsonp_callback => (
  65. is => 'ro',
  66. default => sub { 0 },
  67. );
  68. has wrap_string_callback => (
  69. is => 'ro',
  70. default => sub { 0 },
  71. );
  72. has accept_header => (
  73. is => 'ro',
  74. default => sub { 0 },
  75. );
  76. has proxy_cache_valid => (
  77. is => 'ro',
  78. predicate => 'has_proxy_cache_valid',
  79. );
  80. has proxy_ssl_session_reuse => (
  81. is => 'ro',
  82. predicate => 'has_proxy_ssl_session_reuse',
  83. );
  84. has nginx_conf => (
  85. is => 'ro',
  86. lazy => 1,
  87. builder => '_build_nginx_conf',
  88. );
  89. sub _build_nginx_conf {
  90. my ( $self ) = @_;
  91. my $uri = URI->new($self->parsed_to);
  92. my $host = $uri->host;
  93. my $port = $uri->port;
  94. my $scheme = $uri->scheme;
  95. my $uri_path = $self->parsed_to;
  96. $uri_path =~ s!$scheme://$host:$port!!;
  97. $uri_path =~ s!$scheme://$host!!;
  98. # wrap various other things into jsonp
  99. croak "Cannot use wrap_jsonp_callback and wrap_string callback at the same time!" if $self->wrap_jsonp_callback && $self->wrap_string_callback;
  100. my $wrap_jsonp_callback = $self->has_callback && $self->wrap_jsonp_callback;
  101. my $wrap_string_callback = $self->has_callback && $self->wrap_string_callback;
  102. my $cfg = "location ^~ ".$self->path." {\n";
  103. $cfg .= "\tproxy_set_header Accept '".$self->accept_header."';\n" if $self->accept_header;
  104. $cfg .= "\techo_before_body '".$self->callback."(';\n" if $wrap_jsonp_callback;
  105. $cfg .= "\techo_before_body '".$self->callback.qq|("';\n| if $wrap_string_callback;
  106. $cfg .= "\trewrite ^".$self->path.($self->has_from ? $self->from : "(.*)")." ".$uri_path." break;\n";
  107. $cfg .= "\tproxy_pass ".$scheme."://".$host.":".$port."/;\n";
  108. $cfg .= "\tproxy_cache_valid ".$self->proxy_cache_valid.";\n" if $self->has_proxy_cache_valid;
  109. $cfg .= "\tproxy_ssl_session_reuse ".$self->proxy_ssl_session_reuse.";\n" if $self->has_proxy_ssl_session_reuse;
  110. $cfg .= "\techo_after_body ');';\n" if $wrap_jsonp_callback;
  111. $cfg .= "\techo_after_body '\");';\n" if $wrap_string_callback;
  112. $cfg .= "}\n";
  113. return $cfg;
  114. }
  115. has _missing_envs => (
  116. is => 'rw',
  117. predicate => 'has_missing_envs',
  118. );
  119. sub missing_envs { shift->_missing_envs }
  120. has _parsed_to => (
  121. is => 'rw',
  122. );
  123. sub parsed_to { shift->_parsed_to }
  124. 1;