1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
|
Serving Bazaar with FastCGI
===========================
This document describes one way to set up a Bazaar HTTP smart server,
using Apache 2.0 and FastCGI or mod_python.
For more information on the smart server, and other ways to configure it
see the main `smart server documentation`_.
.. _smart server documentation: #running-a-smart-server
Example
-------
You have a webserver already publishing `/srv/example.com/www/code` as
`http://example.com/code/...` with plain HTTP. It contains bzr branches and
directories like `/srv/example.com/www/code/branch-one` and
`/srv/example.com/www/code/my-repo/branch-two`. You want to provide read-only
smart server access to these directories in addition to the existing HTTP
access.
Configuring Apache 2.0
----------------------
FastCGI
~~~~~~~
First, configure mod_fastcgi, e.g. by adding lines like these to your
httpd.conf::
LoadModule fastcgi_module /usr/lib/apache2/modules/mod_fastcgi.so
FastCgiIpcDir /var/lib/apache2/fastcgi
In our example, we're already serving `/srv/example.com/www/code` at
`http://example.com/code`, so our existing Apache configuration would look
like::
Alias /code /srv/example.com/www/code
<Directory /srv/example.com/www/code>
Options Indexes
# ...
</Directory>
We need to change it to handle all requests for URLs ending in `.bzr/smart`. It
will look like::
Alias /code /srv/example.com/www/code
<Directory /srv/example.com/www/code>
Options Indexes FollowSymLinks
RewriteEngine On
RewriteBase /code
RewriteRule ^(.*/|)\.bzr/smart$ /srv/example.com/scripts/bzr-smart.fcgi
</Directory>
# bzr-smart.fcgi isn't under the DocumentRoot, so Alias it into the URL
# namespace so it can be executed.
Alias /srv/example.com/scripts/bzr-smart.fcgi /srv/example.com/scripts/bzr-smart.fcgi
<Directory /srv/example.com/scripts>
Options ExecCGI
<Files bzr-smart.fcgi>
SetHandler fastcgi-script
</Files>
</Directory>
This instructs Apache to hand requests for any URL ending with `/.bzr/smart`
inside `/code` to a Bazaar smart server via FastCGI.
Refer to the mod_rewrite_ and mod_fastcgi_ documentation for further
information.
.. _mod_rewrite: http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html
.. _mod_fastcgi: http://www.fastcgi.com/mod_fastcgi/docs/mod_fastcgi.html
mod_python
~~~~~~~~~~
First, configure mod_python, e.g. by adding lines like these to your
httpd.conf::
LoadModule python_module /usr/lib/apache2/modules/mod_python.so
Define the rewrite rules with mod_rewrite the same way as for FastCGI, except
change::
RewriteRule ^(.*/|)\.bzr/smart$ /srv/example.com/scripts/bzr-smart.fcgi
to::
RewriteRule ^(.*/|)\.bzr/smart$ /srv/example.com/scripts/bzr-smart.py
Like with mod_fastcgi, we also define how our script is to be handled::
Alias /srv/example.com/scripts/bzr-smart.py /srv/example.com/scripts/bzr-smart.py
<Directory /srv/example.com/scripts>
<Files bzr-smart.py>
PythonPath "sys.path+['/srv/example.com/scripts']"
AddHandler python-program .py
PythonHandler bzr-smart::handler
</Files>
</Directory>
This instructs Apache to hand requests for any URL ending with `/.bzr/smart`
inside `/code` to a Bazaar smart server via mod_python.
NOTE: If you don't have bzrlib in your PATH, you will be need to change the
following line::
PythonPath "sys.path+['/srv/example.com/scripts']"
To::
PythonPath "['/path/to/bzr']+sys.path+['/srv/example.com/scripts']"
Refer to the mod_python_ documentation for further information.
.. _mod_python: http://www.modpython.org/
Configuring Bazaar
------------------
FastCGI
~~~~~~~
We've configured Apache to run the smart server at
`/srv/example.com/scripts/bzr-smart.fcgi`. This is just a simple script we need
to write to configure a smart server, and glue it to the FastCGI gateway.
Here's what it looks like::
import fcgi
from bzrlib.transport.http import wsgi
smart_server_app = wsgi.make_app(
root='/srv/example.com/code',
prefix='/code/',
path_var='REQUEST_URI',
readonly=True)
fcgi.WSGIServer(smart_server_app).run()
The `fcgi` module can be found at http://svn.saddi.com/py-lib/trunk/fcgi.py. It
is part of flup_.
.. _flup: http://www.saddi.com/software/flup/
mod_python
~~~~~~~~~~
We've configured Apache to run the smart server at
`/srv/example.com/scripts/bzr-smart.py`. This is just a simple script we need
to write to configure a smart server, and glue it to the mod_python gateway.
Here's what it looks like::
import modpywsgi
from bzrlib.transport.http import wsgi
smart_server_app = wsgi.make_app(
root='/srv/example.com/code',
prefix='/code/',
path_var='REQUEST_URI',
readonly=True)
def handler(request):
"""Handle a single request."""
wsgi_server = modpywsgi.WSGIServer(smart_server_app)
return wsgi_server.run(request)
The `modpywsgi` module can be found at http://trac.pocoo.org/wiki/ModPyWsgi. It
is part of pocoo_.
You sould make sure you place modpywsgi.py in the same directory as
bzr-smart.py (ie. /srv/example.com/scripts/).
.. _pocoo: http://trac.pocoo.org/wiki/
Clients
-------
Now you can use `bzr+http://` URLs, e.g.::
bzr log bzr+http://example.com/code/my-branch
Plain HTTP access should continue to work::
bzr log http://example.com/code/my-branch
Advanced configuration
----------------------
Because the Bazaar HTTP smart server is a WSGI application, it can be used with
any 3rd-party WSGI middleware or server that conforms the WSGI standard. The
only requirements are:
* to construct a `SmartWSGIApp`, you need to specify a **root transport** that it
will serve.
* each request's `environ` dict must have a **'bzrlib.relpath'** variable set.
The `make_app` helper used in the example constructs a `SmartWSGIApp` with a
transport based on the `root` path given to it, and calculates the
'bzrlib.relpath` for each request based on the `prefix` and `path_var`
arguments. In the example above, it will take the 'REQUEST_URI' (which is set
by Apache), strip the '/code/' prefix and the '/.bzr/smart' suffix, and set that
as the 'bzrlib.relpath', so that a request for '/code/foo/bar/.bzr/smart' will
result in a 'bzrlib.relpath' of 'foo/bzr'.
It's possible to configure a smart server for a non-local transport, or that
does arbitrary path translations, etc, by constructing a `SmartWSGIApp`
directly. Refer to the docstrings of `bzrlib.transport.http.wsgi` and the `WSGI
standard`_ for further information.
.. _WSGI standard: http://www.python.org/dev/peps/pep-0333/
Pushing over ``bzr+http://``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
It is possible to allow pushing data over the http smart server. The
easiest way to do this, is to just supply ``readonly=False`` to the
``wsgi.make_app()`` call. But be careful, because the smart protocol does
not contain any Authentication. So if you enable write support, you will
want to restrict access to ``.bzr/smart`` URLs to restrict who can
actually write data on your system. At this time, it is not possible to
allow some people to have read-only access and others to have read-write
access to the same urls. Because at the HTTP layer (which is doing the
Authenticating), everything is just a POST request. However, it would
certainly be possible to have HTTPS require authentication and use a
writable server, and plain HTTP allow read-only access.
..
vim: ft=rst tw=74 et
|