{"thread":{"id":"14791","subject":"[PATCH] gitweb: action in path with use_pathinfo","startedAt":"2008-08-01T12:23:45Z","lastAt":"2008-08-01T22:17:11Z","messageCount":4,"participants":["Giuseppe Bilotta"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"85896","messageId":"1217593425-28314-1-git-send-email-giuseppe.bilotta@gmail.com","threadId":"14791","inReplyTo":null,"subject":"[PATCH] gitweb: action in path with use_pathinfo","fromName":"Giuseppe Bilotta","fromEmail":"giuseppe.bilotta@gmail.com","sentAt":"2008-08-01T12:23:45Z","receivedAt":"2008-08-01T12:23:45Z","isPatch":true,"sender":{"key":"giuseppe.bilotta@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1464?v=4"},"body":"When using path info, reduce the number of CGI parameters by embedding\nthe action in the path. The typicial cgiweb path is thus\n$project/$action/$hash_base:$file_name or $project/$action/$hash\n\nThis is mostly backwards compatible with the old-style gitweb paths,\nexcept when $project/$branch was used to access a branch whose name\nmatches a gitweb action.\n\nSigned-off-by: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>\n---\n\nI've been thinking a long time about the best way to get rid of most\nCGI parameters when using path info, and I think that the attached\npatch solves the problem pretty well, since it makes most simple\n(one-paramater) actions accessible as plain paths.\n\nThe only weak point I see in my approach is with -replay=>1. Since in\nour case there are no CGI parameters to be replayed, I use the\ncorresponding variables. An alternative, safer method would probably\nbe to store the various request parameters in a separate hash,\nobtained by merging the CGI data with the one extracted from the\nrequest path. I didn't follow the latter route because the simpler\napproach implemented in this patch seems to work without problems.\n\n gitweb/gitweb.perl |  111 ++++++++++++++++++++++++++++++++++------------------\n 1 files changed, 73 insertions(+), 38 deletions(-)\n\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex aa8c27c..d4ed401 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -512,6 +512,37 @@ if (defined $searchtext) {\n \t$search_regexp = $search_use_regexp ? $searchtext : quotemeta $searchtext;\n }\n \n+# dispatch\n+my %actions = (\n+\t\"blame\" => \\&git_blame,\n+\t\"blobdiff\" => \\&git_blobdiff,\n+\t\"blobdiff_plain\" => \\&git_blobdiff_plain,\n+\t\"blob\" => \\&git_blob,\n+\t\"blob_plain\" => \\&git_blob_plain,\n+\t\"commitdiff\" => \\&git_commitdiff,\n+\t\"commitdiff_plain\" => \\&git_commitdiff_plain,\n+\t\"commit\" => \\&git_commit,\n+\t\"forks\" => \\&git_forks,\n+\t\"heads\" => \\&git_heads,\n+\t\"history\" => \\&git_history,\n+\t\"log\" => \\&git_log,\n+\t\"rss\" => \\&git_rss,\n+\t\"atom\" => \\&git_atom,\n+\t\"search\" => \\&git_search,\n+\t\"search_help\" => \\&git_search_help,\n+\t\"shortlog\" => \\&git_shortlog,\n+\t\"summary\" => \\&git_summary,\n+\t\"tag\" => \\&git_tag,\n+\t\"tags\" => \\&git_tags,\n+\t\"tree\" => \\&git_tree,\n+\t\"snapshot\" => \\&git_snapshot,\n+\t\"object\" => \\&git_object,\n+\t# those below don't need $project\n+\t\"opml\" => \\&git_opml,\n+\t\"project_list\" => \\&git_project_list,\n+\t\"project_index\" => \\&git_project_index,\n+);\n+\n # now read PATH_INFO and use it as alternative to parameters\n sub evaluate_path_info {\n \treturn if defined $project;\n@@ -536,6 +568,16 @@ sub evaluate_path_info {\n \t# do not change any parameters if an action is given using the query string\n \treturn if $action;\n \t$path_info =~ s,^\\Q$project\\E/*,,;\n+\n+\t# next comes the action\n+\t$action = $path_info;\n+\t$action =~ s,/.*$,,;\n+\tif (exists $actions{$action}) {\n+\t\t$path_info =~ s,^\\Q$action\\E/*,,;\n+\t} else {\n+\t\t$action  = undef;\n+\t}\n+\n \tmy ($refname, $pathname) = split(/:/, $path_info, 2);\n \tif (defined $pathname) {\n \t\t# we got \"project.git/branch:filename\" or \"project.git/branch:dir/\"\n@@ -549,10 +591,12 @@ sub evaluate_path_info {\n \t\t}\n \t\t$hash_base ||= validate_refname($refname);\n \t\t$file_name ||= validate_pathname($pathname);\n+\t\t$hash      ||= git_get_hash_by_path($hash_base, $file_name);\n \t} elsif (defined $refname) {\n \t\t# we got \"project.git/branch\"\n-\t\t$action ||= \"shortlog\";\n-\t\t$hash   ||= validate_refname($refname);\n+\t\t$action    ||= \"shortlog\";\n+\t\t$hash      ||= validate_refname($refname);\n+\t\t$hash_base ||= validate_refname($refname);\n \t}\n }\n evaluate_path_info();\n@@ -561,37 +605,6 @@ evaluate_path_info();\n our $git_dir;\n $git_dir = \"$projectroot/$project\" if $project;\n \n-# dispatch\n-my %actions = (\n-\t\"blame\" => \\&git_blame,\n-\t\"blobdiff\" => \\&git_blobdiff,\n-\t\"blobdiff_plain\" => \\&git_blobdiff_plain,\n-\t\"blob\" => \\&git_blob,\n-\t\"blob_plain\" => \\&git_blob_plain,\n-\t\"commitdiff\" => \\&git_commitdiff,\n-\t\"commitdiff_plain\" => \\&git_commitdiff_plain,\n-\t\"commit\" => \\&git_commit,\n-\t\"forks\" => \\&git_forks,\n-\t\"heads\" => \\&git_heads,\n-\t\"history\" => \\&git_history,\n-\t\"log\" => \\&git_log,\n-\t\"rss\" => \\&git_rss,\n-\t\"atom\" => \\&git_atom,\n-\t\"search\" => \\&git_search,\n-\t\"search_help\" => \\&git_search_help,\n-\t\"shortlog\" => \\&git_shortlog,\n-\t\"summary\" => \\&git_summary,\n-\t\"tag\" => \\&git_tag,\n-\t\"tags\" => \\&git_tags,\n-\t\"tree\" => \\&git_tree,\n-\t\"snapshot\" => \\&git_snapshot,\n-\t\"object\" => \\&git_object,\n-\t# those below don't need $project\n-\t\"opml\" => \\&git_opml,\n-\t\"project_list\" => \\&git_project_list,\n-\t\"project_index\" => \\&git_project_index,\n-);\n-\n if (!defined $action) {\n \tif (defined $hash) {\n \t\t$action = git_get_type($hash);\n@@ -649,8 +661,13 @@ sub href (%) {\n \tif ($params{-replay}) {\n \t\twhile (my ($name, $symbol) = each %mapping) {\n \t\t\tif (!exists $params{$name}) {\n-\t\t\t\t# to allow for multivalued params we use arrayref form\n-\t\t\t\t$params{$name} = [ $cgi->param($symbol) ];\n+\t\t\t\tif ($cgi->param($symbol)) {\n+\t\t\t\t\t# to allow for multivalued params we use arrayref form\n+\t\t\t\t\t$params{$name} = [ $cgi->param($symbol) ];\n+\t\t\t\t} else {\n+\t\t\t\t\tno strict 'refs';\n+\t\t\t\t\t$params{$name} = $$name if $$name;\n+\t\t\t\t}\n \t\t\t}\n \t\t}\n \t}\n@@ -661,10 +678,28 @@ sub href (%) {\n \t\t$href .= \"/\".esc_url($params{'project'}) if defined $params{'project'};\n \t\tdelete $params{'project'};\n \n-\t\t# Summary just uses the project path URL\n-\t\tif (defined $params{'action'} && $params{'action'} eq 'summary') {\n+\t\t# Summary just uses the project path URL, any other action come next\n+\t\t# in the URL\n+\t\tif (defined $params{'action'}) {\n+\t\t\t$href .= \"/\".esc_url($params{'action'}) unless $params{'action'} eq 'summary';\n \t\t\tdelete $params{'action'};\n \t\t}\n+\n+\t\t# next, we put either hash_base:file_name or hash\n+\t\tif (defined $params{'hash_base'}) {\n+\t\t\t$href .= \"/\".esc_url($params{'hash_base'});\n+\t\t\tif (defined $params{'file_name'}) {\n+\t\t\t\t$href .= \":\".esc_url($params{'file_name'});\n+\t\t\t\tdelete $params{'hash'} if $params{'hash'} eq git_get_hash_by_path($params{'hash_base'},$params{'file_name'});\n+\t\t\t\tdelete $params{'file_name'};\n+\t\t\t} else {\n+\t\t\t\tdelete $params{'hash'} if $params{'hash'} eq $params{'hash_base'};\n+\t\t\t}\n+\t\t\tdelete $params{'hash_base'};\n+\t\t} elsif (defined $params{'hash'}) {\n+\t\t\t$href .= \"/\".esc_url($params{'hash'});\n+\t\t\tdelete $params{'hash'};\n+\t\t}\n \t}\n \n \t# now encode the parameters explicitly\n-- \n1.5.6.3\n"},{"id":"85926","messageId":"1217622913-9747-1-git-send-email-giuseppe.bilotta@gmail.com","threadId":"14791","inReplyTo":"1217593425-28314-1-git-send-email-giuseppe.bilotta@gmail.com","subject":"[PATCH] gitweb: use_pathinfo filenames start with /","fromName":"Giuseppe Bilotta","fromEmail":"giuseppe.bilotta@gmail.com","sentAt":"2008-08-01T20:35:13Z","receivedAt":"2008-08-01T20:35:13Z","isPatch":true,"sender":{"key":"giuseppe.bilotta@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1464?v=4"},"body":"When using path info, make filenames start with a / (right after the :\nthat separates them from the hash base). This minimal change allows\nrelative navigation to work properly when viewing HTML files.\n---\n\nThis patch is based on top of my previous patch\n  gitweb: action in path with use_pathinfo\n(which I sent with the wrong CC: lines)\n\n gitweb/gitweb.perl |    2 +-\n 1 files changed, 1 insertions(+), 1 deletions(-)\n\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex 56fbdab..a8c0887 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -664,7 +664,7 @@ sub href (%) {\n \t\tif (defined $params{'hash_base'}) {\n \t\t\t$href .= \"/\".esc_url($params{'hash_base'});\n \t\t\tif (defined $params{'file_name'}) {\n-\t\t\t\t$href .= \":\".esc_url($params{'file_name'});\n+\t\t\t\t$href .= \":/\".esc_url($params{'file_name'});\n \t\t\t\tdelete $params{'hash'} if $params{'hash'} eq git_get_hash_by_path($params{'hash_base'},$params{'file_name'});\n \t\t\t\tdelete $params{'file_name'};\n \t\t\t} else {\n-- \n1.5.6.3\n"},{"id":"85942","messageId":"1217629031-14894-1-git-send-email-giuseppe.bilotta@gmail.com","threadId":"14791","inReplyTo":"1217622913-9747-1-git-send-email-giuseppe.bilotta@gmail.com","subject":"[PATCH 1/2] gitweb: parse parent..current syntax from pathinfo","fromName":"Giuseppe Bilotta","fromEmail":"giuseppe.bilotta@gmail.com","sentAt":"2008-08-01T22:17:10Z","receivedAt":"2008-08-01T22:17:10Z","isPatch":true,"sender":{"key":"giuseppe.bilotta@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1464?v=4"},"body":"This makes it possible to use an URL such as\n$project/somebranch..otherbranch:/filename to get a diff between\ndifferent version of a file. Paths like\n$project/$action/somebranch:/somefile..otherbranch:/otherfile are parsed\nas well.\n---\n\nThis patch and the next apply on top of my previous two\ngitweb pathinfo patches. \n\nI realize that these patches of mine coming through in burst\ncan get pretty annoying, but I honestly wasn't planning of\nmaking so many changes to the path info feature. So let me\nknow if it's better to resend the patches in a series.\n\nHopefully, with this patch and the next the series should be\ncomplete, as most commands will now be able to get all of\ntheir parameters from the path without using CGI parameters.\n\n gitweb/gitweb.perl |   22 ++++++++++++++++++++--\n 1 files changed, 20 insertions(+), 2 deletions(-)\n\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex 9e90017..8364b71 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -578,7 +578,9 @@ sub evaluate_path_info {\n \t\t$action  = undef;\n \t}\n \n-\tmy ($refname, $pathname) = split(/:/, $path_info, 2);\n+\t$path_info =~ /^((.+?)(:(.+))?\\.\\.)?(.+?)(:(.+))?$/;\n+\tmy ($parentrefname, $parentpathname, $refname, $pathname) = (\n+\t\t$2, $4, $5, $7);\n \tif (defined $pathname) {\n \t\t# we got \"project.git/branch:filename\" or \"project.git/branch:dir/\"\n \t\t# we could use git_get_type(branch:pathname), but it needs $git_dir\n@@ -587,11 +589,27 @@ sub evaluate_path_info {\n \t\t\t$action  ||= \"tree\";\n \t\t\t$pathname =~ s,/$,,;\n \t\t} else {\n-\t\t\t$action  ||= \"blob_plain\";\n+\t\t\tif ($parentrefname) {\n+\t\t\t\t$action ||= \"blobdiff_plain\";\n+\t\t\t} else {\n+\t\t\t\t$action  ||= \"blob_plain\";\n+\t\t\t}\n \t\t}\n \t\t$hash_base ||= validate_refname($refname);\n \t\t$file_name ||= validate_pathname($pathname);\n \t\t$hash      ||= git_get_hash_by_path($hash_base, $file_name);\n+\n+\t\tif ($parentrefname) {\n+\t\t\t$hash_parent_base ||= validate_refname($parentrefname);\n+\t\t\tif ($parentpathname) {\n+\t\t\t\t$parentpathname =~ s,^/+,,;\n+\t\t\t\t$parentpathname =~ s,/$,,;\n+\t\t\t\t$file_parent ||= validate_pathname($parentpathname);\n+\t\t\t} else {\n+\t\t\t\t$file_parent ||= $file_name\n+\t\t\t}\n+\t\t\t$hash_parent ||= git_get_hash_by_path($hash_parent_base, $file_parent);\n+\t\t}\n \t} elsif (defined $refname) {\n \t\t# we got \"project.git/branch\"\n \t\t$action    ||= \"shortlog\";\n-- \n1.5.6.3\n"},{"id":"85943","messageId":"1217629031-14894-2-git-send-email-giuseppe.bilotta@gmail.com","threadId":"14791","inReplyTo":"1217629031-14894-1-git-send-email-giuseppe.bilotta@gmail.com","subject":"[PATCH 2/2] gitweb: use_pathinfo creates parent..current paths","fromName":"Giuseppe Bilotta","fromEmail":"giuseppe.bilotta@gmail.com","sentAt":"2008-08-01T22:17:11Z","receivedAt":"2008-08-01T22:17:11Z","isPatch":true,"sender":{"key":"giuseppe.bilotta@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1464?v=4"},"body":"If use_pathinfo is enabled, href now creates links that contain paths in\nthe form $project/$action/oldhash:/oldname..newhash:/newname for actions\nthat use hash_parent etc.\n---\n gitweb/gitweb.perl |   26 +++++++++++++++++++++++---\n 1 files changed, 23 insertions(+), 3 deletions(-)\n\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex 8364b71..e89e1a1 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -703,9 +703,29 @@ sub href (%) {\n \t\t\tdelete $params{'action'};\n \t\t}\n \n-\t\t# next, we put either hash_base:file_name or hash\n+\t\t# next, we put hash_parent_base:/file_parent..hash_base:/file_name, stripping nonexistent or useless pieces\n+\t\t$href .= \"/\" if ($params{'hash_base'} || $params{'hash_parent_base'} || $params{'hash_parent'} || $params{'hash'});\n \t\tif (defined $params{'hash_base'}) {\n-\t\t\t$href .= \"/\".esc_url($params{'hash_base'});\n+\t\t\tif (defined $params{'hash_parent_base'}) {\n+\t\t\t\t$href .= esc_url($params{'hash_parent_base'});\n+\t\t\t\tif (defined $params{'file_parent'}) {\n+\t\t\t\t\t$href .= \":/\".esc_url($params{'file_parent'}) unless $params{'file_parent'} eq $params{'file_name'};\n+\t\t\t\t\tdelete $params{'hash_parent'} if $params{'hash_parent'} eq git_get_hash_by_path($params{'hash_parent_base'},$params{'file_parent'});\n+\t\t\t\t\tdelete $params{'file_parent'};\n+\t\t\t\t} else {\n+\t\t\t\t\tdelete $params{'hash_parent'} if $params{'hash_parent'} eq $params{'hash_parent_base'};\n+\t\t\t\t\tif ($params{'file_name'}) {\n+\t\t\t\t\t\tdelete $params{'hash_parent'} if $params{'hash_parent'} eq git_get_hash_by_path($params{'hash_parent_base'},$params{'file_name'});\n+\t\t\t\t\t}\n+\t\t\t\t}\n+\t\t\t\t$href .= \"..\";\n+\t\t\t\tdelete $params{'hash_parent_base'};\n+\t\t\t} elsif (defined $params{'hash_parent'}) {\n+\t\t\t\t$href .= esc_url($params{'hash_parent'}). \"..\";\n+\t\t\t\tdelete $params{'hash_parent'};\n+\t\t\t}\n+\n+\t\t\t$href .= esc_url($params{'hash_base'});\n \t\t\tif (defined $params{'file_name'}) {\n \t\t\t\t$href .= \":/\".esc_url($params{'file_name'});\n \t\t\t\tdelete $params{'hash'} if $params{'hash'} eq git_get_hash_by_path($params{'hash_base'},$params{'file_name'});\n@@ -715,7 +735,7 @@ sub href (%) {\n \t\t\t}\n \t\t\tdelete $params{'hash_base'};\n \t\t} elsif (defined $params{'hash'}) {\n-\t\t\t$href .= \"/\".esc_url($params{'hash'});\n+\t\t\t$href .= esc_url($params{'hash'});\n \t\t\tdelete $params{'hash'};\n \t\t}\n \t}\n-- \n1.5.6.3\n"}]}