[PATCH 3 of 3 RFC] hgweb: handle obsolete changesets gracefully
Augie Fackler
raf at durin42.com
Fri Aug 9 15:12:34 UTC 2013
On Thu, Aug 08, 2013 at 09:48:46AM +0200, Dan Villiom Podlaski Christiansen wrote:
> # HG changeset patch
> # User Dan Villiom Podlaski Christiansen <danchr at gmail.com>
> # Date 1375624663 -7200
> # Sun Aug 04 15:57:43 2013 +0200
> # Node ID 5507e2af80f5e8026a054ce440c0c8958134eefe
> # Parent b1f7ae28c3e371a70ee363a4fbe5d50063a224fc
> hgweb: handle obsolete changesets gracefully
>
> If the changeset has any successors, issue a 403 Moved Permanently;
I think you mean 301?
> otherwise we issue a 410 Gone. Please note that this is slightly
> misleading for 'secret' changesets, as they may appear later on.
I think you should handle these separately if possible, since secret
changesets probably want to be 404. Also, you should verify that the
destination of the 301 isn't a 404 before redirecting there, because
that /would/ potentially leak some secret changeset hash IDs.
>
> diff --git a/mercurial/hgweb/common.py b/mercurial/hgweb/common.py
> --- a/mercurial/hgweb/common.py
> +++ b/mercurial/hgweb/common.py
> @@ -9,12 +9,14 @@
> import errno, mimetypes, os
>
> HTTP_OK = 200
> +HTTP_MOVED_PERMANENTLY = 301
> HTTP_NOT_MODIFIED = 304
> HTTP_BAD_REQUEST = 400
> HTTP_UNAUTHORIZED = 401
> HTTP_FORBIDDEN = 403
> HTTP_NOT_FOUND = 404
> HTTP_METHOD_NOT_ALLOWED = 405
> +HTTP_GONE = 410
> HTTP_SERVER_ERROR = 500
>
>
> diff --git a/mercurial/hgweb/hgweb_mod.py b/mercurial/hgweb/hgweb_mod.py
> --- a/mercurial/hgweb/hgweb_mod.py
> +++ b/mercurial/hgweb/hgweb_mod.py
> @@ -8,11 +8,13 @@
>
> import os
> from mercurial import ui, hg, hook, error, encoding, templater, util, repoview
> +from mercurial import obsolete
> +from mercurial.node import short
> from mercurial.templatefilters import websub
> from mercurial.i18n import _
> from common import get_stat, ErrorResponse, permhooks, caching
> -from common import HTTP_OK, HTTP_NOT_MODIFIED, HTTP_BAD_REQUEST
> -from common import HTTP_NOT_FOUND, HTTP_SERVER_ERROR
> +from common import HTTP_OK, HTTP_NOT_MODIFIED, HTTP_BAD_REQUEST, HTTP_GONE
> +from common import HTTP_NOT_FOUND, HTTP_SERVER_ERROR, HTTP_MOVED_PERMANENTLY
> from request import wsgirequest
> import webcommands, protocol, webutil, re
>
> @@ -249,6 +251,33 @@ class hgweb(object):
>
> return content
>
> + except error.FilteredLookupError, err:
> + succsets = obsolete.successorssets(self.repo, err.rev)
> +
> + if not succsets:
> + req.respond(HTTP_GONE, ctype)
> +
> + return tmpl('error', error=err.message)
> +
> + elif len(succsets) != 1:
> + # TODO: changeset has divergent successors
> + req.respond(HTTP_SERVER_ERROR, ctype)
> +
> + return tmpl('error', error=err.message)
> +
> + location = [req.url.rstrip('/')]
> + location += req.form['cmd']
> +
> + location.append(short(succsets[0][-1]))
> +
> + if 'file' in req.form:
> + location += req.form['file']
> +
> + req.headers.extend([('Location', '/'.join(location))])
> + req.respond(HTTP_MOVED_PERMANENTLY, ctype)
> +
> + return tmpl('error', error=err.message)
> +
> except (error.LookupError, error.RepoLookupError), err:
> req.respond(HTTP_NOT_FOUND, ctype)
> msg = str(err)
> diff --git a/mercurial/hgweb/webutil.py b/mercurial/hgweb/webutil.py
> --- a/mercurial/hgweb/webutil.py
> +++ b/mercurial/hgweb/webutil.py
> @@ -201,6 +201,9 @@ def cleanpath(repo, path):
> def changeidctx (repo, changeid):
> try:
> ctx = repo[changeid]
> + except error.FilteredLookupError:
> + raise
> +
> except error.RepoError:
> man = repo.manifest
> ctx = repo[man.linkrev(man.rev(man.lookup(changeid)))]
> diff --git a/tests/test-hgweb-commands.t b/tests/test-hgweb-commands.t
> --- a/tests/test-hgweb-commands.t
> +++ b/tests/test-hgweb-commands.t
> @@ -1385,7 +1385,7 @@ proper status for filtered revision
> $ PATH_INFO=/rev/5; export PATH_INFO
> $ QUERY_STRING='style=raw'
> $ python hgweb.cgi #> search
> - Status: 404 Not Found\r (esc)
> + Status: 410 Gone\r (esc)
> ETag: *\r (glob) (esc)
> Content-Type: text/plain; charset=ascii\r (esc)
> \r (esc)
> @@ -1399,7 +1399,7 @@ proper status for filtered revision
> $ PATH_INFO=/rev/4; export PATH_INFO
> $ QUERY_STRING='style=raw'
> $ python hgweb.cgi #> search
> - Status: 404 Not Found\r (esc)
> + Status: 410 Gone\r (esc)
> ETag: *\r (glob) (esc)
> Content-Type: text/plain; charset=ascii\r (esc)
> \r (esc)
> @@ -1498,6 +1498,47 @@ filtered '0' changeset
>
>
>
> +Test obsolete redirection
> +
> + $ cat > ../obs.py << EOF
> + > import mercurial.obsolete
> + > mercurial.obsolete._enabled = True
> + > EOF
> + $ echo '[extensions]' >> $HGRCPATH
> + $ echo "rebase=" >> $HGRCPATH
> + $ echo "obs=${TESTTMP}/obs.py" >> $HGRCPATH
> + $ hg up 12
> + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
> + $ echo B > b; hg add b
> + $ hg ci -m 6
> +
> +Use a rebase to obsolete r13, and test redirection
> +
> + $ hg rebase -r 13 -d 11
> + $ PATH_INFO=/rev/13; export PATH_INFO
> + $ QUERY_STRING='style=raw'
> + $ python hgweb.cgi #> search
> + Status: 301 Moved Permanently\r (esc)
> + ETag: *\r (glob) (esc)
> + Location: /test/rev/0d601cf5c587\r (esc)
> + Content-Type: text/plain; charset=ascii\r (esc)
> + \r (esc)
> +
> + error: revision 13 is hidden
> +
> +Rebase r13 once more, testing divergent changesets
> +
> + $ hg --hidden rebase -r 13 -d 9
> + $ PATH_INFO=/rev/13; export PATH_INFO
> + $ QUERY_STRING='style=raw'
> + $ python hgweb.cgi #> search
> + Status: 500 Internal Server Error\r (esc)
> + ETag: *\r (glob) (esc)
> + Content-Type: text/plain; charset=ascii\r (esc)
> + \r (esc)
> +
> + error: revision 13 is hidden
> +
>
>
> $ cd ..
> diff --git a/tests/test-obsolete.t b/tests/test-obsolete.t
> --- a/tests/test-obsolete.t
> +++ b/tests/test-obsolete.t
> @@ -747,7 +747,7 @@ check filelog view
> $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'rev/68'
> 200 Script output follows
> $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'rev/67'
> - 404 Not Found
> + 410 Gone
> [1]
>
> check that web.view config option:
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel
More information about the Mercurial-devel
mailing list