<% use IPC::Open3 ();; use Symbol (); use IO::Select (); my $service = param('service') || ''; my $user = param('user'); my $project = param('project'); my $git = app->git; # Smart HTTP if ($service eq 'git-upload-pack' || $service eq 'git-receive-pack') { my $service_cmd = $service; substr($service_cmd, 0, 4, ''); my $rep = $git->rep($user, $project); my @cmd = $git->cmd($user, $project, $service_cmd, '--stateless-rpc', '--advertise-refs', $rep); my ($cout, $cerr) = (Symbol::gensym, Symbol::gensym); my $pid = IPC::Open3::open3(my $cin, $cout, $cerr, @cmd ); close $cin; my ( $refs, $err, $buf ) = ( '', '', '' ); my $s = IO::Select->new($cout, $cerr); my $buffer_size = $ENV{GITPREP_SMART_HTTP_BUFFER_SIZE}; while (my @ready = $s->can_read) { for my $handle (@ready) { while (sysread($handle, $buf, $buffer_size)) { if ($handle == $cerr) { $err .= $buf; } else { $refs .= $buf; } } $s->remove($handle) if eof($handle); } } close $cout; close $cerr; waitpid($pid, 0); if ($err) { app->log->error($err); $self->reply->exception($err); return; } $self->res->headers->content_type("application/x-$service-advertisement"); # Data start my $message = "# service=$service\n"; my $data = sprintf( '%04x', length($message) + 4 ) . $message . '0000' . $refs; $self->render(data => $data); return; } # Dumb HTTP else { # Update server info my @cmd = $git->cmd($user, $project, 'update-server-info'); open my $fh, '-|', @cmd or die "Can't open pipe for @cmd:$!"; close $fh or die "Can't close pipe for @cmd:$!"; my $content_type = 'text/plain; charset=UTF-8'; my $rep_home = app->git->rep_home; my $file = "$rep_home/$user/$project.git/info/refs"; if (-f $file) { my $asset = Mojo::Asset::File->new(path => $file); my $content = $asset->slurp; $content = '' unless defined $content; $self->res->headers->content_type($content_type); $self->res->headers->content_length(length $content); $self->res->body($content); $self->res->code(200); $self->rendered; return; } else { $self->res->code(404); $self->rendered; return; } } %>