Commit Graph

1048 Commits

Author SHA1 Message Date
Boris Feld
6965edf646 configitems: register the 'web.style' config 2017-06-30 03:45:52 +02:00
Boris Feld
80e5b426c6 configitems: register the 'web.stripes' config 2017-06-30 03:45:51 +02:00
Boris Feld
aec01b0c2a configitems: register the 'web.refreshinterval' config 2017-06-30 03:45:50 +02:00
Boris Feld
dd08c3c7c0 configitems: register the 'web.prefix' config 2017-06-30 03:45:49 +02:00
Boris Feld
88f87cb825 configitems: register the 'web.port' config 2017-06-30 03:45:48 +02:00
Boris Feld
67229c919a configitems: register the 'web.errorlog' config 2017-06-30 03:45:45 +02:00
Boris Feld
ac4da5873b configitems: register the 'web.encoding' config 2017-06-30 03:45:44 +02:00
Boris Feld
01eaec495b configitems: register the 'web.description' config 2017-06-30 03:45:43 +02:00
Boris Feld
bb6b276196 configitems: register the 'web.descend' config 2017-06-30 03:45:42 +02:00
Boris Feld
208bc8bf91 configitems: register the 'web.collapse' config 2017-06-30 03:45:38 +02:00
Boris Feld
9ac692bc8c configitems: register the 'web.address' config 2017-06-30 03:45:32 +02:00
Boris Feld
b22253c4ad configitems: register the 'web.accesslog' config 2017-06-30 03:45:31 +02:00
Boris Feld
ac80b45fb8 web: use '_unset' default value for proxy config method
This special value is needed to make sure registered default value are taken in
account.
2017-09-15 19:21:08 +02:00
Yuya Nishihara
a71f259bd2 doctest: bulk-replace string literals with b'' for Python 3
Our code transformer can't rewrite string literals in docstrings, and I
don't want to make the transformer more complex.
2017-09-03 14:32:11 +09:00
Martin von Zweigbergk
cb8b36b8aa cleanup: rename "matchfn" to "match" where obviously a matcher
We usually call matchers either "match" or "m" and reserve "matchfn"
for functions.

Differential Revision: https://phab.mercurial-scm.org/D641
2017-09-05 15:06:45 -07:00
Augie Fackler
e2774d9258 python3: wrap all uses of <exception>.strerror with strtolocal
Our string literals are bytes, and we mostly want to %-format a
strerror into a one of those literals, so this fixes a ton of issues.
2017-08-22 20:03:07 -04:00
Augie Fackler
cc479af38a httppeer: add support for httppostargs when we're sending a file
This is probably only used in the 'unbundle' command, but the code
ended up being cleaner to make it generic and treat *all* httppostargs
with a non-args request body as though they were file-like in
nature. It also means we get test coverage more or less for free. A
previous version of this change didn't use io.BytesIO, and it was a
lot more complicated.

This also fixes a server-side bug, so anyone using httppostargs should
update all of their servers to this revision or later *before* this
gets to their clients, otherwise servers will hang trying to over-read
the POST body.

Differential Revision: https://phab.mercurial-scm.org/D231
2017-07-26 17:58:19 -04:00
Gregory Szorc
64adaa7b62 revset: pass repo when passing ui
The repo instance is currently only used to provide a changeset
lookup function as part of parsing revsets. I /think/ this allows
node fragments to resolve. I'm not sure why we wouldn't want this
to always "just work" if parsing a revset string.

Plus, an upcoming commit will introduce a new consumer that needs a
handle on the repo. So passing it more often will make that code
work more.

Passing a repo instance in all callers of revset.match* results in
a bunch of test changes. Notably, branch and tags caches get
populated as part of evaluating revsets. I'm not sure if this is
desirable. So this patch takes the conservative approach and only
passes the repo if we're passing a ui instance.

Differential Revision: https://phab.mercurial-scm.org/D97
2017-07-15 15:51:57 -07:00
David Demelier
7369cb3896 hgweb: use ui._unset to prevent a warning in configitems 2017-07-03 13:04:35 +02:00
Pierre-Yves David
014dc08cb1 configitems: register the 'server.zliblevel' config 2017-06-30 03:44:16 +02:00
Denis Laxalde
831d4dcf5b hgweb: plug followlines action in annotate view
Add the followlines.js script and corresponding parameters as data attribute
on <tbody class="sourcelines"> element.
Extend CSS rules so that they also match the DOM structure of annotate view.

As previously, only address paper and gitweb styles (other styles do not have
followlines at all).
2017-06-21 17:17:17 +02:00
Yuya Nishihara
e75a42ecc9 dagop: move blockancestors() and blockdescendants() from context
context.py seems not a good place to host these functions.

  % wc -l mercurial/context.py mercurial/dagop.py
    2306 mercurial/context.py
     424 mercurial/dagop.py
    2730 total
2017-02-19 19:37:14 +09:00
Pierre-Yves David
2fdfd87513 profile: drop maybeprofile
It seems sufficiently simple to use "profile(enabled=X)" to not justify having
a dedicated context manager just to read the config.

(I do not have a too strong opinion about this).
2017-06-09 12:29:29 +01:00
Yuya Nishihara
877b7b1d1a help: pass commands module by argument
This removes import cycle.
2017-05-21 16:57:32 +09:00
Jun Wu
58df20579d webcommands: use fctx.isbinary 2017-05-03 18:04:43 -07:00
Denis Laxalde
d141711562 hgweb: do not show "descending" link in followlines UI for filelog heads
When on a filelog head, we are certain that there will be no descendant so the
target of the "descending" link will lead to an empty log result. Do not
display the link in this case.
2017-04-24 10:32:15 +02:00
Matt Harbison
0181beb642 hgwebdir: allow a repository to be hosted at "/"
This can be useful in general, but will also be useful for hosting subrepos,
with the main repo at /.
2017-03-31 23:00:41 -04:00
Denis Laxalde
bd52f5d831 hgweb: handle a "descend" query parameter in filelog command
When this "descend" query parameter is present along with "linerange"
parameter, we get revisions following line range in descending order. The
parameter has no effect without "linerange".
2017-04-10 16:23:41 +02:00
Denis Laxalde
927c1336ab mdiff: add a hunkinrange helper function
This factors out hunk filtering logic by line range that is similar in
mdiff.blocksinrange() and hgweb.webutil.diffs().
2017-04-01 12:24:59 +02:00
Gregory Szorc
64e2de02bd hgweb: extract path traversal checking into standalone function
A common exploit in web applications that access paths is to insert
path separator strings like ".." to try to get the server to serve up
files it shouldn't.

We have code for detecting this in staticfile(). A subsequent commit
will need to perform this test as well. Since this is security code,
let's factor the check so we don't have to reinvent the wheel.
2017-03-31 21:47:26 -07:00
Gregory Szorc
bfa11ec1e0 hgweb: use context manager for file I/O 2017-03-31 22:30:38 -07:00
Denis Laxalde
495eefece3 hgweb: prefix line id by ctx shortnode in filelog when patches are shown
When "patch" query parameter is present in requests to filelog view, line ids
in patches diff are no longer unique in the page since several patches are
shown on the same page. We now prefix line id by changeset shortnode when
several patches are displayed in the same page to have unique line ids
overall.
2017-03-30 21:40:10 +02:00
Denis Laxalde
6af640ec03 hgweb: fix diff hunks filtering by line range in webutil.diffs()
The previous clause for filter out a diff hunk was too restrictive. We need to
consider the following cases (assuming linerange=(lb, ub) and the @s2,l2
hunkrange):

            <-(s2)--------(s2+l2)->
      <-(lb)---(ub)->
               <-(lb)---(ub)->
                           <-(lb)---(ub)->

previously on the first and last situations were considered.

In test-hgweb-filelog.t, add a couple of lines at the beginning of file "b" so
that the line range we will follow does not start at the beginning of file.
This covers the change in aforementioned diff hunk filter clause.
2017-03-29 12:07:07 +02:00
Denis Laxalde
2702418496 hgweb: filter diff hunks when 'linerange' and 'patch' are specified in filelog 2017-03-13 15:17:20 +01:00
Denis Laxalde
69dcb458cd hgweb: add a 'linerange' parameter to webutil.diffs()
This is used to filter out hunks based on their range (with respect to 'node2'
for patch.diffhunks() call, i.e. 'ctx' for webutil.diffs()).

This is the simplest way to filter diff hunks, here done on server side. Later
on, it might be interesting to perform this filtering on client side and
expose a "toggle" action to alternate between full and filtered diff.
2017-03-13 15:15:49 +01:00
Denis Laxalde
996bd4af95 hgweb: handle a "linerange" request parameter in filelog command
We now handle a "linerange" URL query parameter to filter filelog using
a logic similar to followlines() revset.
The URL syntax is: log/<rev>/<file>?linerange=<fromline>:<toline>
As a result, filelog entries only consists of revision changing specified
line range.

The linerange information is propagated to "more"/"less" navigation links but
not to numeric navigation links as this would apparently require a dedicated
"revnav" class.

Only update the "paper" template in this patch.
2017-01-19 17:41:00 +01:00
Denis Laxalde
6b9779860f hgweb: add a "patch" query parameter to filelog command
Add support for a "patch" query parameter in filelog web command similar to
--patch option of `hg log` to display the diff of each changeset in the table
of revisions. The diff text is displayed in a dedicated row of the table that
follows the existing one for each entry and spans over all columns. Only
update "paper" template in this patch.
2017-03-13 10:41:13 +01:00
Denis Laxalde
53e1237344 hgweb: handle "parity" internally in webutil.diffs()
There's apparently no reason to have the "parity" of diff blocks that
webutil.diffs() generates coming from outside the function. So have it
internally managed. We thus now pass a "web" object to webutil.diffs() to get
access to both "repo" and "stripecount" attribute.
2017-03-13 10:40:19 +01:00
Matt Harbison
27ca0a8a5b hgwebdir: add support for explicit index files
This is useful for when repositories are nested in --web-conf, and in the future
with hosted subrepositories.  The previous behavior was only to render an index
at each virtual directory.  There is now an explicit 'index' child for each
virtual directory.  The name was suggested by Yuya, for consistency with the
other method names.

Additionally, there is now an explicit 'index' child for every repository
directory with a nested repository somewhere below it.  This seems more
consistent with each virtual directory hosting an index, and more discoverable
than to only have an index for a directory that directly hosts a nested
repository.  I couldn't figure out how to close the loop and provide one in each
directory without a deeper nested repository, without blocking a committed
'index' file.  Keeping that seems better than rendering an empty index.
2017-03-05 22:22:32 -05:00
Gregory Szorc
5ca0f908bf py3: add __bool__ to every class defining __nonzero__
__nonzero__ was renamed to __bool__ in Python 3. This patch simply
aliases __bool__ to __nonzero__ for every class implementing
__nonzero__.
2017-03-13 12:40:14 -07:00
Pierre-Yves David
50e7f5d5fd hgweb: explicitly tests for None
Changeset 11e325d162fe removed the mutable default value, but did not explicitly
tested for None. Such implicit testing can introduce semantic and performance
issue. We move to an explicit testing for None as recommended by PEP8:

https://www.python.org/dev/peps/pep-0008/#programming-recommendations
2017-03-15 15:11:04 -07:00
Pierre-Yves David
c05c73d498 hgweb: explicitly tests for None in webutil
Changeset 45c7a22dbdc0 removed the mutable default value, but did not explicitly
tested for None. Such implicit testing can introduce semantic and performance
issue. We move to an explicit testing for None as recommended by PEP8:

https://www.python.org/dev/peps/pep-0008/#programming-recommendations
2017-03-15 15:10:09 -07:00
Gregory Szorc
d2e9e46760 hgweb: don't use mutable default argument value 2017-03-12 21:52:17 -07:00
Gregory Szorc
5cc9a634fe hgweb: don't use mutable default argument value 2016-12-26 16:55:47 -07:00
Denis Laxalde
0ed26e5739 hgweb: use patch.diffhunks in webutil.diffs to simplify the algorithm
Function patch.diffhunks yields items for a "block" (i.e. a file) as a whole
so take advantage of this to simplify the algorithm and avoid parsing diff
lines to determine whether we're starting a new "block" or not. Thus we drop
to external block counter and rely on diffhunks iterations instead.
We also take advantage of the fact that patch.diffhunks() yields *lines* of
hunks (instead of a string) to avoid building a list that is ''.join-ed into a
string that is then split.

As lines in 'header' returned by patch.diffhunks() have no trailing new line,
we need to insert it ourselves to match template expectations.
2017-03-06 09:28:33 +01:00
Denis Laxalde
5d10a8a4b5 hgweb: start enumerate at 1 in webutil.diffs's inner function prettyprintlines 2017-03-06 09:44:39 +01:00
Denis Laxalde
be3d757c61 hgweb: explictly pass basectx in webutil.diffs
There's only one case where `basectx` parameter is None (over two usages), so
it's probably not worth handling the special case as it makes code-reading
harder.

Along the way, use ctx.p1() instead of checking for ctx.parents() being empty
which should not occur.
2017-01-17 17:25:48 +01:00
Yuya Nishihara
b2229f5117 revset: split language services to revsetlang module (API)
New revsetlang module hosts parser, tokenizer, and miscellaneous functions
working on parsed tree. It does not include functions for evaluation such as
getset() and match().

  2288 mercurial/revset.py
   684 mercurial/revsetlang.py
  2972 total

get*() functions are aliased since they are common in revset.py.
2017-02-19 18:19:33 +09:00
Yuya Nishihara
d63d83be69 revset: import set classes directly from smartset module
Follows up 97d0be4019ac.
2017-02-19 18:16:09 +09:00
Denis Laxalde
86ca3ec602 hgweb: simplify calculation of first revision in filelog command 2017-01-17 09:19:24 +01:00
Denis Laxalde
8eecb0ced7 hgweb: restore ascending iteration on revs in filelog web command
Follow-up on e082a1597833. Adjust back the "parity" generator's offset to keep
rendering the same.
2017-01-17 09:17:29 +01:00
Denis Laxalde
e0d6f05072 hgweb: build the "entries" list directly in filelog command
There's no apparent reason to have this "entries" generator function that
builds a list and then yields its elements in reverse order and which is only
called to build the "entries" list. So just build the list directly, in
reverse order.

Adjust "parity" generator's offset to keep rendering the same.
2017-01-13 10:22:25 +01:00
Gregory Szorc
9849c580fb hgweb: support Content Security Policy
Content-Security-Policy (CSP) is a web security feature that allows
servers to declare what loaded content is allowed to do. For example,
a policy can prevent loading of images, JavaScript, CSS, etc unless
the source of that content is whitelisted (by hostname, URI scheme,
hashes of content, etc). It's a nifty security feature that provides
extra mitigation against some attacks, notably XSS.

Mitigation against these attacks is important for Mercurial because
hgweb renders repository data, which is commonly untrusted. While we
make attempts to escape things, etc, there's the possibility that
malicious data could be injected into the site content. If this happens
today, the full power of the web browser is available to that
malicious content. A restrictive CSP policy (defined by the server
operator and sent in an HTTP header which is outside the control of
malicious content), could restrict browser capabilities and mitigate
security problems posed by malicious data.

CSP works by emitting an HTTP header declaring the policy that browsers
should apply. Ideally, this header would be emitted by a layer above
Mercurial (likely the HTTP server doing the WSGI "proxying"). This
works for some CSP policies, but not all.

For example, policies to allow inline JavaScript may require setting
a "nonce" attribute on <script>. This attribute value must be unique
and non-guessable. And, the value must be present in the HTTP header
and the HTML body. This means that coordinating the value between
Mercurial and another HTTP server could be difficult: it is much
easier to generate and emit the nonce in a central location.

This commit introduces support for emitting a
Content-Security-Policy header from hgweb. A config option defines
the header value. If present, the header is emitted. A special
"%nonce%" syntax in the value triggers generation of a nonce and
inclusion in <script> elements in templates. The inclusion of a
nonce does not occur unless "%nonce%" is present. This makes this
commit completely backwards compatible and the feature opt-in.

The nonce is a type 4 UUID, which is the flavor that is randomly
generated. It has 122 random bits, which should be plenty to satisfy
the guarantees of a nonce.
2017-01-10 23:37:08 -08:00
Gregory Szorc
f71c86b7e9 protocol: send application/mercurial-0.2 responses to capable clients
With this commit, the HTTP transport now parses the X-HgProto-<N>
header to determine what media type and compression engine to use for
responses. So far, we only compress responses that are already being
compressed with zlib today (stream response types to specific
commands). We can expand things to cover additional response types
later.

The practical side-effect of this commit is that non-zlib compression
engines will be used if both ends support them. This means if both
ends have zstd support, zstd - not zlib - will be used to compress
data!

When cloning the mozilla-unified repository between a local HTTP
server and client, the benefits of non-zlib compression are quite
noticeable:

  engine     server CPU (s)   client CPU (s)    bundle size
zlib (l=6)      174.1            283.2         1,148,547,026
zstd (l=1)       99.2            267.3         1,127,513,841
zstd (l=3)      103.1            266.9         1,018,861,363
zstd (l=7)      128.3            269.7           919,190,278
zstd (l=10)     162.0               -            894,547,179
none             95.3            277.2         4,097,566,064

The default zstd compression level is 3. So if you deploy zstd
capable Mercurial to your clients and servers and CPU time on
your server is dominated by "getbundle" requests (clients cloning
and pulling) - and my experience at Mozilla tells me this is often
the case - this commit could drastically reduce your server-side
CPU usage *and* save on bandwidth costs!

Another benefit of this change is that server operators can install
*any* compression engine. While it isn't enabled by default, the
"none" compression engine can now be used to disable wire protocol
compression completely. Previously, commands like "getbundle" always
zlib compressed output, adding considerable overhead to generating
responses. If you are on a high speed network and your server is under
high load, it might be advantageous to trade bandwidth for CPU.
Although, zstd at level 1 doesn't use that much CPU, so I'm not
convinced that disabling compression wholesale is worthwhile. And, my
data seems to indicate a slow down on the client without compression.
I suspect this is due to a lack of buffering resulting in an increase
in socket read() calls and/or the fact we're transferring an extra 3 GB
of data (parsing HTTP chunked transfer and processing extra TCP packets
can add up). This is definitely worth investigating and optimizing. But
since the "none" compressor isn't enabled by default, I'm inclined to
punt on this issue.

This commit introduces tons of tests. Some of these should arguably
have been implemented on previous commits. But it was difficult to
test without the server functionality in place.
2016-12-24 15:29:32 -07:00
Gregory Szorc
52ab84abd8 httppeer: extract code for HTTP header spanning
A second consumer of HTTP header spanning will soon be introduced.
Factor out the code to do this so it can be reused.
2016-12-24 14:46:02 -07:00
Anton Shestakov
836493ef5e hgweb: use archivespecs for links on repo index page too
Moving archivespecs to the module level allows using it from other modules
(such as hgwebdir_mod), and keeping a reference to it in requestcontext allows
current code to just work.
2017-01-10 23:41:58 +08:00
Anton Shestakov
22ec8d9ae5 hgweb: use util.sortdict for archivespecs
Thus we allow dict-like indexing and "in" checks, and also preserve the order
of archive types and can generate links in a certain order (so
requestcontext.archives is no longer needed).
2017-01-10 23:34:39 +08:00
Anton Shestakov
8d71b91ef9 hgweb: generate archive links in order
It would be nice for archive links to always be in a certain commonly used
order, such as 'zip', 'bz', 'gzip2'. Repo index page (hgwebdir_mod) already
shows archive links in this order, let's do the same in hgweb_mod.

Sadly, archivespecs is a regular unordered dict, and collections.OrderedDict is
new in 2.7. But requestcontext.archives is a tuple of archive types, so it can
be used as an index to archivespecs.
2017-01-08 00:52:54 +08:00
Anton Shestakov
5dfa3509d4 hgweb: use archivespecs (dict) instead of archives (tuple) for "in" check 2017-01-08 01:24:45 +08:00
Pulkit Goyal
4780c32e4c py3: replace os.name with pycompat.osname (part 1 of 2)
os.name returns unicodes on py3 and we have pycompat.osname which returns
bytes. This series of 2 patches will change every ocurrence of os.name with
pycompat.osname.
2016-12-19 00:16:52 +05:30
Pulkit Goyal
bb08d44667 py3: replace os.environ with encoding.environ (part 3 of 5) 2016-12-18 01:54:36 +05:30
Pulkit Goyal
c109648881 py3: replace os.altsep with pycompat.altsep
All the occurences of os.altsep are replaced with pycompat.altsep which
returns bytes.
2016-12-18 01:17:12 +05:30
Pulkit Goyal
5629f71f5b py3: replace os.sep with pycompat.ossep (part 3 of 4) 2016-12-17 20:14:24 +05:30
Gregory Szorc
2220c845b2 protocol: declare transport protocol name
We add an attribute to the HTTP and SSH protocol implementations
identifying the transport so future patches can conditionally
expose capabilities on a per-transport basis.
2016-11-28 20:46:59 -08:00
Yuya Nishihara
1d44bd2bbb ui: factor out ui.load() to create a ui without loading configs (API)
This allows us to write doctests depending on a ui object, but not on global
configs.

ui.load() is a class method so we can do wsgiui.load(). All ui() calls but
for doctests are replaced with ui.load(). Some of them could be changed to
not load configs later.
2016-10-22 14:35:10 +09:00
Yuya Nishihara
cd5b8b18a0 server: move service factory from hgweb 2016-10-15 14:09:36 +09:00
Yuya Nishihara
7a38271c60 hgweb: extract app factory
I'll move createservice() to the server module, but createapp() seems good to
remain in the hgweb module because of its dependency on hgweb/hgwebdir_mod.
2016-10-15 14:06:46 +09:00
Yuya Nishihara
47f9c8b52e py3: bulk replace sys.stdin/out/err by util's
Almost all sys.stdin/out/err in hgext/ and mercurial/ are replaced by util's.
There are a few exceptions:

 - lsprof.py and statprof.py are untouched since they are a kind of vendor
   code and they never import mercurial modules right now.
 - ui._readline() needs to replace sys.stdin and stdout to pass them to
   raw_input(). We'll need another workaround here.
2016-10-20 23:53:36 +09:00
Gregory Szorc
2112fb0fd2 wireproto: perform chunking and compression at protocol layer (API)
Currently, the "streamres" response type is populated with a generator
of chunks with compression possibly already applied. This puts the onus
on commands to perform chunking and compression. Architecturally, I
think this is the wrong place to perform this work. I think commands
should say "here is the data" and the protocol layer should take care
of encoding the final bytes to put on the wire.

Additionally, upcoming commits will improve wire protocol support for
compression. Having a central place for performing compression in the
protocol transport layer will be easier than having to deal with
compression at the commands layer.

This commit refactors the "streamres" response type to accept either
a generator or an object with "read." Additionally, the type now
accepts a flag indicating whether the response is a "version 1
compressible" response. This basically identifies all commands
currently performing compression. I could have used a special type
for this, but a flag works just as well. The argument name
foreshadows the introduction of wire protocol changes, hence the "v1."

The code for chunking and compressing has been moved to the output
generation function for each protocol transport. Some code has been
inlined, resulting in the deletion of now unused methods.
2016-11-20 13:50:45 -08:00
Augie Fackler
73f7abdd33 merge with stable 2016-11-16 23:29:28 -05:00
Gregory Szorc
085fa86140 hgweb: cache fctx.parents() in annotate command (issue5414)
43e3fb1c484e introduced a call to fctx.parents() for each line in
annotate output. This function call isn't cheap, as it requires
linkrev adjustment.

Since multiple lines in annotate output tend to belong to the same
file revision, a cache of fctx.parents() lookups for each input
should be effective in the common case. So we implement one.

Since the cache has to precompute parents so an aborted generator
doesn't leave an incomplete cache, we could just return a list.
However, we preserve the generator for backwards compatibility.

The effect of this change when requesting /annotate/96ca0ecdcfa/
browser/locales/en-US/chrome/browser/downloads/downloads.dtd on
the mozilla-aurora repo is significant:

p1(43e3fb1c484e)  5.5s
43e3fb1c484e:    66.3s
this patch:      10.8s

We're still slower than before. But only by ~2x instead of ~12x.

On the tip revisions of layout/base/nsCSSFrameConstructor.cpp file in
the mozilla-unified repo, time went from 12.5s to 14.5s and back to
12.5s. I'm not sure why the mozilla-aurora repo is so slow.

Looking at the code of basefilectx.parents(), there is room for
further improvements. Notably, we still perform redundant calls to
filelog.renamed() and basefilectx._parentfilectx(). And
basefilectx.annotate() also makes similar calls, so there is potential
for object reuse. However, introducing caches here are not appropriate
for the stable branch.
2016-11-05 09:38:07 -07:00
Gregory Szorc
1538b87cfc wireproto: compress data from a generator
Currently, the "getbundle" wire protocol command obtains a generator of
data, converts it to a util.chunkbuffer, then converts it back to a
generator via the protocol's groupchunks() implementation. For the SSH
protocol, groupchunks() simply reads 4kb chunks then write()s the
data to a file descriptor. For the HTTP protocol, groupchunks() reads
32kb chunks, feeds those into a zlib compressor, emits compressed data
as it is available, and that is sent to the WSGI layer, where it is
likely turned into HTTP chunked transfer chunks as is or further
buffered and turned into a larger chunk.

For both the SSH and HTTP protocols, there is inefficiency from using
util.chunkbuffer.

For SSH, emitting consistent 4kb chunks sounds nice. However, the file
descriptor it is writing to is almost certainly buffered. That means
that a Python .write() probably doesn't translate into exactly what is
written to the I/O layer.

For HTTP, we're going through an intermediate layer to zlib compress
data. So all util.chunkbuffer is doing is ensuring that the chunks we
feed into the zlib compressor are of uniform size. This means more CPU
time in Python buffering and emitting chunks in util.chunkbuffer but
fewer function calls to zlib.

This patch introduces and implements a new wire protocol abstract
method: compresschunks(). It is like groupchunks() except it operates
on a generator instead of something with a .read(). The SSH
implementation simply proxies chunks. The HTTP implementation uses
zlib compression.

To avoid duplicate code, the HTTP groupchunks() has been reimplemented
in terms of compresschunks().

To prove this all works, the "getbundle" wire protocol command has been
switched to compresschunks(). This removes the util.chunkbuffer from
that command. Now, data essentially streams straight from the
changegroup emitter to the wire, possibly through a zlib compressor.
Generators all the way, baby.

There were slim to no performance changes on the server as measured
with the mozilla-central repository. This is likely because CPU
time is dominated by reading revlogs, producing the changegroup, and
zlib compressing the output stream. Still, this brings us a little
closer to our ideal of using generators everywhere.
2016-10-16 11:10:21 -07:00
Martijn Pieters
de1f10a894 hgweb: fix the MRO in Python 3
object should appear at the end, otherwise it tries to pre-empt the other
new-style classes in the MRO, resulting in an unresolvable MRO in Py3. We still
need to include object because otherwise in 2.7 we end up with an old-style
class if threading is not supported, new-style if it is.
2016-10-08 19:11:19 +02:00
Jun Wu
a68511813b hgweb: make fctx.annotate a separated function so it could be wrapped
This patch moves "fctx.annotate" used by the "annotate" webcommand, along
with the diffopts to a separated function which takes a ui and a fctx.
So it could be replaced by other implementations which don't want to replace
the core "fctx.annotate" directly.
2016-10-08 16:10:34 +01:00
Gregory Szorc
36f039b85b wireproto: rename argument to groupchunks()
groupchunks() is a generic "turn a file object into a generator"
function. It isn't limited to changegroups. Rename the argument
and update the docstring to reflect this.
2016-09-25 12:20:31 -07:00
Durham Goode
52b8095f37 manifest: remove last uses of repo.manifest
Now that all the functionality has been moved to manifestlog/manifestrevlog/etc,
we can finally change all the uses of repo.manifest to use the new versions. A
future diff will then delete repo.manifest.

One additional change in this commit is to change repo.manifestlog to be a
@storecache property instead of @property. This is required by some uses of
repo.manifest require that it be settable (contrib/perf.py and the static http
server). We can't do this in a prior change because we can't use @storecache on
this until repo.manifest is no longer used anywhere.
2016-11-10 02:13:19 -08:00
Augie Fackler
5229cbbf19 protocol: drop unused import of zlib
Something weird is happening that breaks pyflakes installed via 'pip
install --user'. I haven't had a chance to finish debugging this, but
this at least fixes the build.
2016-11-10 15:14:05 -05:00
Gregory Szorc
f8bef20b48 hgweb: use compression engine API for zlib compression
More low-level compression code elimination because we now have nice
APIs.

This patch also demonstrates why we needed and implemented the
"level" option on the "compressstream" API.
2016-11-07 18:54:35 -08:00
Gregory Szorc
312f42b6e4 hgweb: tweak zlib chunking behavior
When doing streaming compression with zlib, zlib appears to emit chunks
with data after ~20-30kb on average is available. In other words, most
calls to compress() return an empty string. On the mozilla-unified repo,
only 48,433 of 921,167 (5.26%) of calls to compress() returned data.
In other words, we were sending hundreds of thousands of empty chunks
via a generator where they touched who knows how many frames (my guess
is millions). Filtering out the empty chunks from the generator
cuts down on overhead.

In addition, we were previously feeding 8kb chunks into zlib
compression. Since this function tends to emit *compressed* data after
20-30kb is available, it would take several calls before data was
produced. We increase the amount of data fed in at a time to 32kb.
This reduces the number of calls to compress() from 921,167 to
115,146. It also reduces the number of output chunks from 48,433 to
31,377. This does increase the average output chunk size by a little.
But I don't think this will matter in most scenarios.

The combination of these 2 changes appears to shave ~6s CPU time
or ~3% from a server serving the mozilla-unified repo.
2016-08-14 21:29:46 -07:00
Gregory Szorc
118980f02b hgweb: document why we don't allow untrusted settings to control zlib
Added comment per discussion on mercurial-devel.
2016-08-15 20:39:33 -07:00
Gregory Szorc
4cfd8623b8 hgweb: profile HTTP requests
Currently, running `hg serve --profile` doesn't yield anything useful:
when the process is terminated the profiling output displays results
from the main thread, which typically spends most of its time in
select.select(). Furthermore, it has no meaningful results from
mercurial.* modules because the threads serving HTTP requests don't
actually get profiled.

This patch teaches the hgweb wsgi applications to profile individual
requests. If profiling is enabled, the profiler kicks in after
HTTP/WSGI environment processing but before Mercurial's main request
processing.

The profile results are printed to the configured profiling output.
If running `hg serve` from a shell, they will be printed to stderr,
just before the HTTP request line is logged. If profiling to a file,
we only write a single profile to the file because the file is not
opened in append mode. We could add support for appending to files
in a future patch if someone wants it.

Per request profiling doesn't work with the statprof profiler because
internally that profiler collects samples from the thread that
*initially* requested profiling be enabled. I have plans to address
this by vendoring Facebook's customized statprof and then improving
it.
2016-08-14 18:37:24 -07:00
Gregory Szorc
2ed4e485bc hgweb: abstract call to hgwebdir wsgi function
The function names and behavior now matches hgweb. The reason for this
will be obvious in the next patch.
2016-08-14 16:03:30 -07:00
Gregory Szorc
8720bcb69f hgweb: config option to control zlib compression level
Before this patch, the HTTP transport protocol would always zlib
compress certain responses (notably "getbundle" wire protocol commands)
at zlib compression level 6.

zlib can be a massive CPU resource sink for servers. Some server
operators may wish to reduce server-side CPU requirements while
requiring more bandwidth. This is common on corporate intranets, for
example. Others may wish to use more CPU but reduce bandwidth.

This patch introduces a config option to allow server operators
to control the zlib compression level.

On the "mozilla-unified" generaldelta repository, setting this
value to "0" (disable compression) results in server-side CPU
utilization for a `hg clone` going from ~180s to ~124s CPU time on
my i7-6700K.  A level of "1" (which increases the transfer size from
~1,074 MB at level 6 to ~1,222 MB) utilizes ~132s CPU time.
2016-08-07 18:09:58 -07:00
Anton Shestakov
72f684f821 paper: make different blocks of annotated lines have different colors 2016-07-16 14:49:07 +08:00
Pulkit Goyal
6b3bc52b40 py3: conditionalize BaseHTTPServer, SimpleHTTPServer and CGIHTTPServer import
The BaseHTTPServer, SimpleHTTPServer and CGIHTTPServer has been merged into
http.server in python 3. All of them has been merged as util.httpserver to use
in both python 2 and 3. This patch adds a regex to check-code to warn against
the use of BaseHTTPServer. Moreover this patch also includes updates to lower
part of test-check-py3-compat.t which used to remain unchanged.
2016-07-13 23:38:29 +05:30
Gregory Szorc
c023f774e6 hgweb: use sslutil.wrapserversocket()
This patch transitions the built-in HTTPS server to use sslutil for
creating the server socket.

As part of this transition, we implement developer-only config options
to control CA loading and whether to require client certificates. This
eliminates the need for the custom extension in test-https.t to define
these.

There is a slight change in behavior with regards to protocol
selection. Before, we would always use the TLS 1.0 constant to define
the protocol version. This would *only* use TLS 1.0. sslutil defaults
to TLS 1.0+. So this patch improves the security of `hg serve` out of
the box by allowing it to use TLS 1.1 and 1.2 (if available).
2016-07-12 23:12:03 -07:00
Gregory Szorc
6052136b07 hgweb: pass ui into preparehttpserver
Upcoming patches will need the built-in HTTPS server to be more
configurable.
2016-07-13 00:14:50 -07:00
Anton Shestakov
2f0cc33284 hgweb: enumerate lines in loop header, not before
Doing this will allow access to the lines in arbitrary order (because the
result of enumerate() is an iterator), and that will help calculating rowspan
for annotate blocks.
2016-07-14 12:33:44 +08:00
Denis Laxalde
07a35f6357 hgweb: add link to parents of annotated revision in annotate view
The link is embedded into a div with class="annotate-info" that only shows up
upon hover of the annotate column. To avoid duplicate hover-overs (this new
one and the one coming from link's title), drop "title" attribute from a
element and put it in the annotate-info element.
2016-06-28 11:42:42 +02:00
Anton Shestakov
662db21d2e hgweb: emit a valid, weak ETag
Previously, ETag headers from hgweb weren't correctly formed, because rfc2616
(section 14, header definitions) requires double quotes around the content of
the header. str(web.mtime) didn't do that.

Additionally, strong ETags signify that the resource representations are
byte-for-byte identical. That is, they can be reconstructed from byte ranges if
client so wishes. Considering ETags for all hgweb pages is just mtime of
00changelog.i and doesn't consider of e.g. .hg/hgrc with description, contact
and other fields, it's clearly shouldn't be strong. The W/ prefix marks it as
weak, which still allows caching the whole served file/page, but doesn't allow
byte-range requests.
2016-07-09 03:26:24 +08:00
Gregory Szorc
5255c3f24b hgweb: expose list of per-repo labels to templates
hgweb currently offers limited functionality for "classifying"
repositories. This patch aims to change that.

The web.labels config option list is introduced. Its values
are exposed to the "index" and "summary" templates. Custom
templates can use template features like ifcontains() to e.g.
look for the presence of a specific label and engage specific
behavior. For example, a site operator may wish to assign a
"defunct" label to a repository so the repository is prominently
marked as dead in repository indexes.
2016-06-30 18:59:53 -07:00
Pulkit Goyal
38a359ce5c py3: conditionalize SocketServer import
The SocketServer is renamed to socketserver in python 3
2016-06-27 16:48:54 +05:30
Denis Laxalde
2acd032eb6 hgweb: display blamed revision once per block in annotate view
I.e. when a revision blames a block of source lines, only display the
revision link on the first line of the block (this is identified by the
"blockhead" key in annotate context).

This addresses item "Visual grouping of changesets" of the blame improvements
plan (https://www.mercurial-scm.org/wiki/BlamePlan) which states: "Typically
there are block of lines all attributed to the same revision. Instead of
rendering the revision/changeset for every line, we could only render it once
per block."
2016-06-07 12:10:01 +02:00
Laura Médioni
d95b4f5e78 templates: add support for summary webcommand in json style
Change summary webcommand to yield each element of the shortlog instead of the
entire list.

This makes generated json more readable since each entry can be formatted
separately, instead of returning all the shortlog content in a single string.
2016-06-06 15:14:11 +02:00
Denis Laxalde
675f39ef38 hgweb: remove unused code in annotate web command 2016-06-01 15:16:38 +02:00
timeless
a1cb3173a2 py3: convert to next() function
next(..) was introduced in py2.6 and .next() is not available in py3

https://docs.python.org/2/library/functions.html#next
2016-05-16 21:30:53 +00:00
Yuya Nishihara
2d4abff2d9 hgweb: make log streams compatible with command server
Even though it would be useless to start a web server by a command server,
it should be doable in principle. Also, we can't use sys.stdout/err directly
on Python 3 because they are unicode streams.
2014-06-28 13:13:32 +09:00
Yuya Nishihara
3f981af86b templater: separate function to create templater from map file (API)
New frommapfile() function will make it clear when template aliases will be
loaded. They should be applied to command arguments and templates in hgrc,
but not to map files. Otherwise, our stock styles and web templates
(i.e map-file templates) could be modified unintentionally.

Future patches will add "aliases" argument to __init__(), but not to
frommapfile().
2016-04-03 23:26:48 +09:00
timeless
109fcbc79e pycompat: switch to util.urlreq/util.urlerr for py3 compat 2016-04-06 23:22:12 +00:00
timeless
f77cdcd3b1 pycompat: switch to util.stringio for py3 compat 2016-04-10 20:55:37 +00:00