開発環境で静的HTMLファイルとCGIをサーブする方法

開発環境で静的HTMLファイルとCGIをサーブするために、Mojoliciousを使って簡単な実装を行いました。

本番の実行環境はApacheで、開発環境では、そうではないことは、普通にあります。

開発環境で静的なHTMLとCGIの試験が行える実装を書いてみました。

使い方

morbo serve_cgi.pl

ソースコード

# serve_cgi.pl
use Mojo::Message::Response;
use File::Temp 'tempfile';

use Mojolicious::Lite;

# render CGI
app->hook(before_dispatch => sub {
  my $c = shift;
  
  my $req = $c->req;
  
  my $path = $req->url->path;
  
  if ($path =~ /\.cgi$/) {
    my $method = $c->req->method;
    my $script_name = $c->app->home->rel_file("public/$path");
    
    # CGI Environment variable
    local $ENV{AUTH_TYPE} = '';
    local $ENV{CONTENT_LENGTH} = $req->headers->content_length;
    local $ENV{CONTENT_TYPE} = $req->headers->content_type;
    local $ENV{GATEWAY_INTERFACE} = 'CGI/1.1';
    local $ENV{PATH_INFO} = $req->url->path;
    local $ENV{PATH_TRANSLATED} = $req->url->path;
    local $ENV{QUERY_STRING} = $req->url->query->to_string;
    local $ENV{REMOTE_ADDR} = $c->tx->remote_address;
    local $ENV{REMOTE_HOST} = $c->tx->remote_address;
    local $ENV{REMOTE_IDENT} = '';
    local $ENV{REMOTE_USER} = '';
    local $ENV{REQUEST_METHOD} = $method;
    local $ENV{SCRIPT_NAME} = $script_name;
    local $ENV{SERVER_NAME} = 'localhost';
    local $ENV{SERVER_PORT} = $c->tx->remote_port;
    local $ENV{SERVER_SOFTWARE} = "Mojolicious (Perl)";
    local $ENV{SERVER_PROTOCOL} = 'HTTP/1.1';
    
    # Check script name
    unless ($script_name =~ /^[a-zA-Z_0-9\/\-\.]+$/) {
      die "Invalid script name";
    }
    
    # Run CGI script
    my $output;
    if ($method eq 'GET') {
      # GET requst
      $output = `$^X $script_name`;
      if ($?) {
        $c->res->code('505');
        $c->render(text => "Internal Server Error");
      }
    }
    elsif ($method eq 'POST') {
      # POST request
      my $body = $req->body;
      my ($in_fh, $in_file) = tempfile;
      print $in_fh $body;
      close $in_fh;
      $output = `$^X -pe "" $in_file | $^X $script_name`;
      if ($?) {
        $c->res->code('505');
        $c->render(text => "Internal Server Error");
      }
      unlink $in_file;
    }
    
    # Header part and body part
    my ($header_part, $body_part) = split("\n\n", $output, 2);
    
    # Response
    my $res = Mojo::Message::Response->new;
    while (!$res->is_finished) {
      $res->parse($header_part);
    }
    $c->res->code($res->code);
    $c->res->headers($res->headers);
    $c->render(data => $body_part);
  }
});

get '/' => sub {
  my $c = shift;
  
  $c->reply->static('index.html');
};

app->start;

もっといい方法あるよという方は、Twitterで、教えてください。

業務に役立つPerl

Perlテキスト処理のエッセンス

PerlでポータブルなLinuxファイル管理入門

ITエンジニアの求人情報など

 ITエンジニアの求人情報・Webサービス・ソフトウェア・スクールなどの情報。

システム開発のお問い合わせ