{"thread":{"id":"15997","subject":"[PATCHv7 4/5] gitweb: parse parent..current syntax from PATH_INFO","startedAt":"2008-10-21T19:34:49Z","lastAt":"2008-10-21T19:34:54Z","messageCount":6,"participants":["Giuseppe Bilotta"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"93629","messageId":"1224617694-29277-1-git-send-email-giuseppe.bilotta@gmail.com","threadId":"15997","inReplyTo":null,"subject":"[PATCHv7 0/5] gitweb: PATH_INFO enhancement","fromName":"Giuseppe Bilotta","fromEmail":"giuseppe.bilotta@gmail.com","sentAt":"2008-10-21T19:34:49Z","receivedAt":"2008-10-21T19:34:49Z","isPatch":false,"sender":{"key":"giuseppe.bilotta@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1464?v=4"},"body":"Sevent attempt for my gitweb PATH_INFO patchset, whose purpose is to\nreduce the use of CGI parameters by embedding as many parameters as\npossible in the URL path itself, provided the pathinfo feature is\nenabled.\n\nThe new typical gitweb URL is therefore in the form\n\n$project/$action/$parent:$file..$hash:$file\n\n(with useless parts stripped). Backwards compatibility for old-style\n$project/$hash[:$file] URLs is kept, as long as $hash is not a refname\nwhose name happens to match a git action.\n\nThe main implementation is provided by paired patches (#1#2, #4#5)\nthat implement parsing and generation of the new style URLs.\n\nPatch #3 is a minor improvement to the URL syntax that allows web\nsites to be properly browsable in raw mode.\n\nThe patchset depends on my previous input parameter handling patch\ncurrently waiting in 'next'. This resend fixes some mainly aesthetical\nissues spotted by Jakub\n\nGiuseppe Bilotta (5):\n  gitweb: parse project/action/hash_base:filename PATH_INFO\n  gitweb: generate project/action/hash URLs\n  gitweb: use_pathinfo filenames start with /\n  gitweb: parse parent..current syntax from PATH_INFO\n  gitweb: generate parent..current URLs\n\n gitweb/gitweb.perl |  133 +++++++++++++++++++++++++++++++++++++++++++++++----\n 1 files changed, 122 insertions(+), 11 deletions(-)\n"},{"id":"93630","messageId":"1224617694-29277-2-git-send-email-giuseppe.bilotta@gmail.com","threadId":"15997","inReplyTo":"1224617694-29277-1-git-send-email-giuseppe.bilotta@gmail.com","subject":"[PATCHv7 1/5] gitweb: parse project/action/hash_base:filename PATH_INFO","fromName":"Giuseppe Bilotta","fromEmail":"giuseppe.bilotta@gmail.com","sentAt":"2008-10-21T19:34:50Z","receivedAt":"2008-10-21T19:34:50Z","isPatch":false,"sender":{"key":"giuseppe.bilotta@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1464?v=4"},"body":"This patch enables gitweb to parse URLs with more information embedded\nin PATH_INFO, reducing the need for CGI parameters. The typical gitweb\npath is now $project/$action/$hash_base:$file_name or\n$project/$action/$hash\n\nThis is mostly backwards compatible with the old-style gitweb paths,\n$project/$branch[:$filename], except when it was used to access a branch\nwhose name matches a gitweb action.\n\nSigned-off-by: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>\n---\n gitweb/gitweb.perl |   46 +++++++++++++++++++++++++++++++++++++++-------\n 1 files changed, 39 insertions(+), 7 deletions(-)\n\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex 98f1bfa..1f847bb 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -534,23 +534,55 @@ sub evaluate_path_info {\n \treturn if $input_params{'action'};\n \t$path_info =~ s,^\\Q$project\\E/*,,;\n \n+\t# next, check if we have an action\n+\tmy $action = $path_info;\n+\t$action =~ s,/.*$,,;\n+\tif (exists $actions{$action}) {\n+\t\t$path_info =~ s,^$action/*,,;\n+\t\t$input_params{'action'} = $action;\n+\t}\n+\n+\t# list of actions that want hash_base instead of hash, but can have no\n+\t# pathname (f) parameter\n+\tmy @wants_base = (\n+\t\t'tree',\n+\t\t'history',\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-\t\t# we could use git_get_type(branch:pathname), but it needs $git_dir\n+\t\t# we got \"branch:filename\" or \"branch:dir/\"\n+\t\t# we could use git_get_type(branch:pathname), but:\n+\t\t# - it needs $git_dir\n+\t\t# - it does a git() call\n+\t\t# - the convention of terminating directories with a slash\n+\t\t#   makes it superfluous\n+\t\t# - embedding the action in the PATH_INFO would make it even\n+\t\t#   more superfluous\n \t\t$pathname =~ s,^/+,,;\n \t\tif (!$pathname || substr($pathname, -1) eq \"/\") {\n-\t\t\t$input_params{'action'} = \"tree\";\n+\t\t\t$input_params{'action'} ||= \"tree\";\n \t\t\t$pathname =~ s,/$,,;\n \t\t} else {\n-\t\t\t$input_params{'action'} = \"blob_plain\";\n+\t\t\t$input_params{'action'} ||= \"blob_plain\";\n \t\t}\n \t\t$input_params{'hash_base'} ||= $refname;\n \t\t$input_params{'file_name'} ||= $pathname;\n \t} elsif (defined $refname) {\n-\t\t# we got \"project.git/branch\"\n-\t\t$input_params{'action'} = \"shortlog\";\n-\t\t$input_params{'hash'} ||= $refname;\n+\t\t# we got \"branch\". In this case we have to choose if we have to\n+\t\t# set hash or hash_base.\n+\t\t#\n+\t\t# Most of the actions without a pathname only want hash to be\n+\t\t# set, except for the ones specified in @wants_base that want\n+\t\t# hash_base instead. It should also be noted that hand-crafted\n+\t\t# links having 'history' as an action and no pathname or hash\n+\t\t# set will fail, but that happens regardless of PATH_INFO.\n+\t\t$input_params{'action'} ||= \"shortlog\";\n+\t\tif (grep { $_ eq $input_params{'action'} } @wants_base) {\n+\t\t\t$input_params{'hash_base'} ||= $refname;\n+\t\t} else {\n+\t\t\t$input_params{'hash'} ||= $refname;\n+\t\t}\n \t}\n }\n evaluate_path_info();\n-- \n1.5.6.5\n"},{"id":"93628","messageId":"1224617694-29277-3-git-send-email-giuseppe.bilotta@gmail.com","threadId":"15997","inReplyTo":"1224617694-29277-2-git-send-email-giuseppe.bilotta@gmail.com","subject":"[PATCHv7 2/5] gitweb: generate project/action/hash URLs","fromName":"Giuseppe Bilotta","fromEmail":"giuseppe.bilotta@gmail.com","sentAt":"2008-10-21T19:34:51Z","receivedAt":"2008-10-21T19:34:51Z","isPatch":false,"sender":{"key":"giuseppe.bilotta@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1464?v=4"},"body":"When generating path info URLs, reduce the number of CGI parameters by\nembedding action and hash_parent:filename or hash in the path.\n\nSigned-off-by: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>\n---\n gitweb/gitweb.perl |   33 ++++++++++++++++++++++++++++++---\n 1 files changed, 30 insertions(+), 3 deletions(-)\n\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex 1f847bb..27587aa 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -731,14 +731,41 @@ sub href (%) {\n \n \tmy ($use_pathinfo) = gitweb_check_feature('pathinfo');\n \tif ($use_pathinfo) {\n-\t\t# use PATH_INFO for project name\n+\t\t# try to put as many parameters as possible in PATH_INFO:\n+\t\t#   - project name\n+\t\t#   - action\n+\t\t#   - hash or hash_base:filename\n+\n+\t\t# When the script is the root DirectoryIndex for the domain,\n+\t\t# $href here would be something like http://gitweb.example.com/\n+\t\t# Thus, we strip any trailing / from $href, to spare us double\n+\t\t# slashes in the final URL\n+\t\t$href =~ s,/$,,;\n+\n+\t\t# Then add the project name, if present\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 is\n+\t\t# added to 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# Finally, 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{'file_name'};\n+\t\t\t}\n+\t\t\tdelete $params{'hash'};\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.5\n"},{"id":"93631","messageId":"1224617694-29277-4-git-send-email-giuseppe.bilotta@gmail.com","threadId":"15997","inReplyTo":"1224617694-29277-3-git-send-email-giuseppe.bilotta@gmail.com","subject":"[PATCHv7 3/5] gitweb: use_pathinfo filenames start with /","fromName":"Giuseppe Bilotta","fromEmail":"giuseppe.bilotta@gmail.com","sentAt":"2008-10-21T19:34:52Z","receivedAt":"2008-10-21T19:34:52Z","isPatch":false,"sender":{"key":"giuseppe.bilotta@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1464?v=4"},"body":"Generate PATH_INFO URLs in the form project/action/hash_base:/filename\nrather than project/action/hash_base:filename (the latter form is still\naccepted in input).\n\nThis minimal change allows relative navigation to work properly when\nviewing HTML files in raw ('blob_plain') mode.\n\nSigned-off-by: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>\n---\n gitweb/gitweb.perl |    6 +++---\n 1 files changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex 27587aa..9da547d 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -734,7 +734,7 @@ sub href (%) {\n \t\t# try to put as many parameters as possible in PATH_INFO:\n \t\t#   - project name\n \t\t#   - action\n-\t\t#   - hash or hash_base:filename\n+\t\t#   - hash or hash_base:/filename\n \n \t\t# When the script is the root DirectoryIndex for the domain,\n \t\t# $href here would be something like http://gitweb.example.com/\n@@ -753,11 +753,11 @@ sub href (%) {\n \t\t\tdelete $params{'action'};\n \t\t}\n \n-\t\t# Finally, we put either hash_base:file_name or hash\n+\t\t# Finally, 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\t$href .= \":/\".esc_url($params{'file_name'});\n \t\t\t\tdelete $params{'file_name'};\n \t\t\t}\n \t\t\tdelete $params{'hash'};\n-- \n1.5.6.5\n"},{"id":"93626","messageId":"1224617694-29277-5-git-send-email-giuseppe.bilotta@gmail.com","threadId":"15997","inReplyTo":"1224617694-29277-4-git-send-email-giuseppe.bilotta@gmail.com","subject":"[PATCHv7 4/5] gitweb: parse parent..current syntax from PATH_INFO","fromName":"Giuseppe Bilotta","fromEmail":"giuseppe.bilotta@gmail.com","sentAt":"2008-10-21T19:34:53Z","receivedAt":"2008-10-21T19:34:53Z","isPatch":false,"sender":{"key":"giuseppe.bilotta@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1464?v=4"},"body":"This patch makes it possible to use an URL such as\nproject/action/somebranch..otherbranch:/filename to get a diff between\ndifferent version of a file. Paths like\nproject/action/somebranch:/somefile..otherbranch:/otherfile are parsed\nas well.\n\nAll '*diff' actions and in general actions that use $hash_parent[_base]\nand $file_parent (e.g. 'shortlog') can now get all of their parameters\nfrom PATH_INFO\n\nSigned-off-by: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>\n---\n gitweb/gitweb.perl |   36 ++++++++++++++++++++++++++++++++++--\n 1 files changed, 34 insertions(+), 2 deletions(-)\n\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex 9da547d..59449de 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -549,7 +549,12 @@ sub evaluate_path_info {\n \t\t'history',\n \t);\n \n-\tmy ($refname, $pathname) = split(/:/, $path_info, 2);\n+\t# we want to catch\n+\t# [$hash_parent_base[:$file_parent]..]$hash_parent[:$file_name]\n+\tmy ($parentrefname, $parentpathname, $refname, $pathname) =\n+\t\t($path_info =~ /^(?:(.+?)(?::(.+))?\\.\\.)?(.+?)(?::(.+))?$/);\n+\n+\t# first, analyze the 'current' part\n \tif (defined $pathname) {\n \t\t# we got \"branch:filename\" or \"branch:dir/\"\n \t\t# we could use git_get_type(branch:pathname), but:\n@@ -564,7 +569,13 @@ sub evaluate_path_info {\n \t\t\t$input_params{'action'} ||= \"tree\";\n \t\t\t$pathname =~ s,/$,,;\n \t\t} else {\n-\t\t\t$input_params{'action'} ||= \"blob_plain\";\n+\t\t\t# the default action depends on whether we had parent info\n+\t\t\t# or not\n+\t\t\tif ($parentrefname) {\n+\t\t\t\t$input_params{'action'} ||= \"blobdiff_plain\";\n+\t\t\t} else {\n+\t\t\t\t$input_params{'action'} ||= \"blob_plain\";\n+\t\t\t}\n \t\t}\n \t\t$input_params{'hash_base'} ||= $refname;\n \t\t$input_params{'file_name'} ||= $pathname;\n@@ -584,6 +595,27 @@ sub evaluate_path_info {\n \t\t\t$input_params{'hash'} ||= $refname;\n \t\t}\n \t}\n+\n+\t# next, handle the 'parent' part, if present\n+\tif (defined $parentrefname) {\n+\t\t# a missing pathspec defaults to the 'current' filename, allowing e.g.\n+\t\t# someproject/blobdiff/oldrev..newrev:/filename\n+\t\tif ($parentpathname) {\n+\t\t\t$parentpathname =~ s,^/+,,;\n+\t\t\t$parentpathname =~ s,/$,,;\n+\t\t\t$input_params{'file_parent'} ||= $parentpathname;\n+\t\t} else {\n+\t\t\t$input_params{'file_parent'} ||= $input_params{'file_name'};\n+\t\t}\n+\t\t# we assume that hash_parent_base is wanted if a path was specified,\n+\t\t# or if the action wants hash_base instead of hash\n+\t\tif (defined $input_params{'file_parent'} ||\n+\t\t\tgrep { $_ eq $input_params{'action'} } @wants_base) {\n+\t\t\t$input_params{'hash_parent_base'} ||= $parentrefname;\n+\t\t} else {\n+\t\t\t$input_params{'hash_parent'} ||= $parentrefname;\n+\t\t}\n+\t}\n }\n evaluate_path_info();\n \n-- \n1.5.6.5\n"},{"id":"93627","messageId":"1224617694-29277-6-git-send-email-giuseppe.bilotta@gmail.com","threadId":"15997","inReplyTo":"1224617694-29277-5-git-send-email-giuseppe.bilotta@gmail.com","subject":"[PATCHv7 5/5] gitweb: generate parent..current URLs","fromName":"Giuseppe Bilotta","fromEmail":"giuseppe.bilotta@gmail.com","sentAt":"2008-10-21T19:34:54Z","receivedAt":"2008-10-21T19:34:54Z","isPatch":false,"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\nIf any of the filename contains two consecutive dots, it's kept as a CGI\nparameter since the resulting path would otherwise be ambiguous.\n\nSigned-off-by: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>\n---\n gitweb/gitweb.perl |   28 ++++++++++++++++++++++++----\n 1 files changed, 24 insertions(+), 4 deletions(-)\n\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex 59449de..9d1af7e 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -766,6 +766,7 @@ sub href (%) {\n \t\t# try to put as many parameters as possible in PATH_INFO:\n \t\t#   - project name\n \t\t#   - action\n+\t\t#   - hash_parent or hash_parent_base:/file_parent\n \t\t#   - hash or hash_base:/filename\n \n \t\t# When the script is the root DirectoryIndex for the domain,\n@@ -785,17 +786,36 @@ sub href (%) {\n \t\t\tdelete $params{'action'};\n \t\t}\n \n-\t\t# Finally, we put either hash_base:/file_name or hash\n+\t\t# Next, we put hash_parent_base:/file_parent..hash_base:/file_name,\n+\t\t# stripping nonexistent or useless pieces\n+\t\t$href .= \"/\" if ($params{'hash_base'} || $params{'hash_parent_base'}\n+\t\t\t|| $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{'file_name'}) {\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\t# skip the file_parent if it's the same as the file_name\n+\t\t\t\tdelete $params{'file_parent'} if $params{'file_parent'} eq $params{'file_name'};\n+\t\t\t\tif (defined $params{'file_parent'} && $params{'file_parent'} !~ /\\.\\./) {\n+\t\t\t\t\t$href .= \":/\".esc_url($params{'file_parent'});\n+\t\t\t\t\tdelete $params{'file_parent'};\n+\t\t\t\t}\n+\t\t\t\t$href .= \"..\";\n+\t\t\t\tdelete $params{'hash_parent'};\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'} && $params{'file_name'} !~ /\\.\\./) {\n \t\t\t\t$href .= \":/\".esc_url($params{'file_name'});\n \t\t\t\tdelete $params{'file_name'};\n \t\t\t}\n \t\t\tdelete $params{'hash'};\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.5\n"}]}