@matheusbsbs / matheus-bagliano / commits / 9872cd6f6c
Fork 0

gitweb: add patch view

The output of commitdiff_plain is not intended for git-am: * when given a range of commits, commitdiff_plain publishes a single patch with the message from the first commit, instead of a patchset * the hand-built email format replicates the commit summary both as email subject and as first line of the email itself, resulting in a duplication if the output is used with git-am. We thus create a new view that can be fed to git-am directly, allowing patch exchange via gitweb. The new view exposes the output of git format-patch directly, limiting it to a single patch in the case of a single commit. A configurable upper limit defaulting to 16 is imposed on the number of commits which will be included in a patchset, to prevent DoS attacks on the server. Setting the limit to 0 will disable the patch view, setting it to a negative number will remove the limit. Signed-off-by: Giuseppe Bilotta <giuseppe.bilotta@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Giuseppe Bilotta committed Dec 18, 2008 at 08:13 UTC 9872cd6f6c40803db9e784b6287db72e0cb6b5c3
1 file changed +68 -1
gitweb/gitweb.perl
+68 -1
@@ -329,6 +329,21 @@ our %feature = (
329 'ctags' => {
330 'override' => 0,
331 'default' => [0]},
332 +
333 + # The maximum number of patches in a patchset generated in patch
334 + # view. Set this to 0 or undef to disable patch view, or to a
335 + # negative number to remove any limit.
336 +
337 + # To disable system wide have in $GITWEB_CONFIG
338 + # $feature{'patches'}{'default'} = [0];
339 + # To have project specific config enable override in $GITWEB_CONFIG
340 + # $feature{'patches'}{'override'} = 1;
341 + # and in project config gitweb.patches = 0|n;
342 + # where n is the maximum number of patches allowed in a patchset.
343 + 'patches' => {
344 + 'sub' => \&feature_patches,
345 + 'override' => 0,
346 + 'default' => [16]},
347 );
348
349 sub gitweb_get_feature {
@@ -410,6 +425,16 @@ sub feature_pickaxe {
425 return ($_[0]);
426 }
427
428 +sub feature_patches {
429 + my @val = (git_get_project_config('patches', '--int'));
430 +
431 + if (@val) {
432 + return @val;
433 + }
434 +
435 + return ($_[0]);
436 +}
437 +
438 # checking HEAD file with -e is fragile if the repository was
439 # initialized long time ago (i.e. symlink HEAD) and was pack-ref'ed
440 # and then pruned.
@@ -503,6 +528,7 @@ our %actions = (
528 "heads" => \&git_heads,
529 "history" => \&git_history,
530 "log" => \&git_log,
531 + "patch" => \&git_patch,
532 "rss" => \&git_rss,
533 "atom" => \&git_atom,
534 "search" => \&git_search,
@@ -5386,6 +5412,13 @@ sub git_blobdiff_plain {
5412
5413 sub git_commitdiff {
5414 my $format = shift || 'html';
5415 +
5416 + my $patch_max;
5417 + if ($format eq 'patch') {
5418 + ($patch_max) = gitweb_get_feature('patches');
5419 + die_error(403, "Patch view not allowed") unless $patch_max;
5420 + }
5421 +
5422 $hash ||= $hash_base || "HEAD";
5423 my %co = parse_commit($hash)
5424 or die_error(404, "Unknown commit object");
@@ -5483,7 +5516,23 @@ sub git_commitdiff {
5516 open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts,
5517 '-p', $hash_parent_param, $hash, "--"
5518 or die_error(500, "Open git-diff-tree failed");
5486 -
5519 + } elsif ($format eq 'patch') {
5520 + # For commit ranges, we limit the output to the number of
5521 + # patches specified in the 'patches' feature.
5522 + # For single commits, we limit the output to a single patch,
5523 + # diverging from the git-format-patch default.
5524 + my @commit_spec = ();
5525 + if ($hash_parent) {
5526 + if ($patch_max > 0) {
5527 + push @commit_spec, "-$patch_max";
5528 + }
5529 + push @commit_spec, '-n', "$hash_parent..$hash";
5530 + } else {
5531 + push @commit_spec, '-1', '--root', $hash;
5532 + }
5533 + open $fd, "-|", git_cmd(), "format-patch", '--encoding=utf8',
5534 + '--stdout', @commit_spec
5535 + or die_error(500, "Open git-format-patch failed");
5536 } else {
5537 die_error(400, "Unknown commitdiff format");
5538 }
@@ -5532,6 +5581,14 @@ sub git_commitdiff {
5581 print to_utf8($line) . "\n";
5582 }
5583 print "---\n\n";
5584 + } elsif ($format eq 'patch') {
5585 + my $filename = basename($project) . "-$hash.patch";
5586 +
5587 + print $cgi->header(
5588 + -type => 'text/plain',
5589 + -charset => 'utf-8',
5590 + -expires => $expires,
5591 + -content_disposition => 'inline; filename="' . "$filename" . '"');
5592 }
5593
5594 # write patch
@@ -5553,6 +5610,11 @@ sub git_commitdiff {
5610 print <$fd>;
5611 close $fd
5612 or print "Reading git-diff-tree failed\n";
5613 + } elsif ($format eq 'patch') {
5614 + local $/ = undef;
5615 + print <$fd>;
5616 + close $fd
5617 + or print "Reading git-format-patch failed\n";
5618 }
5619 }
5620
@@ -5560,6 +5622,11 @@ sub git_commitdiff_plain {
5622 git_commitdiff('plain');
5623 }
5624
5625 +# format-patch-style patches
5626 +sub git_patch {
5627 + git_commitdiff('patch');
5628 +}
5629 +
5630 sub git_history {
5631 if (!defined $hash_base) {
5632 $hash_base = git_get_head_hash($project);