Hello everyone,

The version control system mercurial (hg) has some functionality to allow 
its repositories to be viewed via the web. However, it does not have a 
builtin authentication system.

I'm trying to get a setup working where I can put Django in front. Jesper 
Noehr of bitbucket.org has some code that looks like it would do what I 
want. Basically, it has Django act as a proxy (I hope I have the 
terminology right), which sents a request to the hgweb code, and gets back 
a response object.

However, this code is currently giving errors, and they are at the Django 
end, so I'm CCing here in the hope that someone can set me straight about 
what is going on.

I'm posting the view code from the hgwebproxy app in 
https://bitbucket.org/jespern/cx/.

This basically does everything. I then follow it with the error
message I see in Django. The error message comes from the line

self.inp = self.env['wsgi.input']

Jesper thinks that a generic Django request should contain such keys, but 
the request I'm seeing doesn't.

He thinks I need to upgrade Django, but before I do that, I thought I 
would write and ask if the behavior has really changed so much in recent 
versions. I've currently using a version from late May, and was waiting 
for 1.0 to upgrade.

I looked at my current version, and it has a wsgi.py, though I have no 
idea how to use it, and could not find any documentation.

>From what I understand from Jesper, _hgReqWrap wraps the Django
request object into the sort of request that hgwebdir
expects. However, I thought the whole point of wsgi was to provide a
low-level compatability layer between different Python web
applications, so shouldn't these kind of manipulations be unnecessary?

To summarize, I'm asking two things

a) What is the simplest/most direct way to fix the current code?

b) Is there a simpler way to do the same thing? Ie. get django to
proxy for hgweb?

Please CC me on any reply.
                                                        Thanks, Faheem.

*********************************************************************
self.env = req.META where req is a django request (see__init__ of
hgReqWrap below).
*********************************************************************

self.env is {'AUTH_TYPE': None, 'HTTP_COOKIE': 
'bixfile=d1e2ea28f5cc1d4f43a9a14e0db4970f', 'SERVER_SOFTWARE': 
'mod_python', 'SCRIPT_NAME':
None, 'REQUEST_METHOD': 'GET', 'PATH_INFO': '', 'SERVER_PROTOCOL': 
'HTTP/1.1', 'QUERY_STRING': None, 'CONTENT_LENGTH': 0L,
'HTTP_ACCEPT_CHARSET': 'ISO-8859-1,utf-8;q=0.7,*;q=0.7', 'REMOTE_USER': 
None, 'HTTP_CONNECTION': 'keep-alive', 'SERVER_NAME':
'msi.home.earth', 'REMOTE_ADDR': '192.168.1.204', 'P ATH_TRANSLATED': 
None, 'SERVER_PORT': 443, 'HTTP_USER_AGENT': 'Mozilla/5.0 (X11; U;
Linux i686; en-US; rv:1.8. 0.14eol) Gecko/20070505 
(Debian-1.8.0.15~pre080614d-0etch1) Epiphany/2.14', 'HTTP_HOST': 'msi',
'HTTP_CACHE_CONTROL': 'max-age=0', 'HTTP_ACCEPT': 
'text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain
;q=0.8,image/png,*/*;q=0.5', 'GATEWAY_INTERFACE': 'CGI/1.1', 
'HTTP_ACCEPT_LANGUAGE': 'en-us,en;q=0.5', 'REMOTE_IDENT': None, 
'CONTENT_TYPE':
None, 'REMOTE_HOST': None, 'HTTP_ACCEPT_ENCODING': 'gzip,deflate', 
'HTTP_KEEP_A LIVE': '300'}

********************************************************************

********************************************************************
views.py
********************************************************************
import os, re, cgi
from django.http import HttpResponseRedirect, HttpResponse
from django.conf import settings
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.contrib.auth.models import User
from datetime import datetime

from mercurial.hgweb.hgwebdir_mod import hgwebdir
from mercurial import hg, ui
from mercurial import __version__

try:
     from hashlib import md5 as md5
except ImportError:
     from md5 import md5

class _hgReqWrap(object):
     def __init__(self, req, resp):
         self.django_req = req
         self.env = req.META
         self.response = resp

         # Remove the prefix so HG will think it's running on its own.
         self.env['PATH_INFO'] = self.env['PATH_INFO'].lstrip("/hg")

         # Make sure there's a content-length.
         if not self.env.has_key('CONTENT_LENGTH'):
             self.env['CONTENT_LENGTH'] = 0

         self.inp = self.env['wsgi.input']
         self.form = cgi.parse(self.inp, self.env, keep_blank_values=1)

         self.headers = [ ]
         self.err = self.env['wsgi.errors']

         self.out = [ ]

     def set_user(self, username):
         self.env['REMOTE_USER'] = username

     def read(self, count=-1):
         return self.inp.read(count)

     def flush(self):
         return None

     def respond(self, code, content_type=None, path=None, length=0):
         self.response.status_code = code

         self.response['content-type'] = content_type

         if path is not None and length is not None:
             self.response['content-type'] = content_type
             self.response['content-length'] = length
             self.response['content-disposition'] = 'inline; filename=%s' % path

         for directive, value in self.headers:
             self.response[directive.lower()] = value

     def header(self, headers=[('Content-Type','text/html')]):
         self.headers.extend(headers)

     def write(self, *a):
         for thing in a:
             if hasattr(thing, '__iter__'):
                 for p in thing:
                     self.write(p)
             else:
                 thing = str(thing)
                 self.response.write(thing)

def digest_auth(request, realm, opaque, users):
     auth_string = request.META.get('HTTP_AUTHORIZATION', None)

     if auth_string is None and not str(auth_string).startswith("Digest"):
         return False

     parts = auth_string.lstrip("Digest ").split(",")

     auth = { }

     for part in parts: # `partition' only in 2.5
         segs = part.lstrip().split("=")
         auth[segs[0]] = '='.join(segs[1:]).strip('"')

     # Quick opaque check
     if not opaque == auth['opaque']:
         return False

     for ha1 in users:
         ha2 = md5("%(method)s:%(path)s" % { 'method': request.method,
                                             'path': request.get_full_path() })

         response = 
md5("%(ha_one)s:%(nonce)s:%(nc)s:%(cnonce)s:%(qop)s:%(ha_two)s" \
             % { 'ha_one': ha1, 'ha_two': ha2.hexdigest(),
                 'nonce': auth['nonce'], 'nc': auth['nc'],
                 'cnonce': auth['cnonce'], 'qop': auth['qop'] })

         if response.hexdigest() == auth['response']:
             return auth['username']

     return False

def hgroot(request, *args):
     resp = HttpResponse()
     hgr = _hgReqWrap(request, resp)

     config = os.path.join(settings.BASE_DIR, 'apps', 'hgwebproxy', 
'hgweb.conf')
     os.environ['HGRCPATH'] = config

     if request.method == "POST":
         realm = "[EMAIL PROTECTED]" % settings.SITE_NAME
         nonce = md5(str(datetime.now())+realm).hexdigest()
         opaque = md5(settings.SITE_NAME).hexdigest()

         users = settings.HG_DIGEST_USERS
         authed = digest_auth(request, realm, opaque, users)

         if not authed:
             resp.status_code = 401
             resp['WWW-Authenticate'] = '''Digest realm="%s", qop="auth", 
nonce="%s", opaque="%s"''' % (realm, nonce, opaque)
             return resp
         else:
             hgr.set_user(authed)

     try:
         hgwebdir(config).run_wsgi(hgr)
     except KeyError:
         resp['content-type'] = 'text/html'
         resp.write('hgweb crashed.')
         pass # hgweb tends to throw these on invalid requests..?
              # nothing to do but ignore it. hg >1.0 might fix.

     if resp.has_header('content-type'):
         if not resp['content-type'].startswith("text/html"):
             return resp

     return render_to_response("hgwebproxy/flat.html", {
         'content': resp.content, 'slugpath': request.path.lstrip("/hg"),
         'hg_version': __version__.version, 'is_root': request.path == '/hg/' },
         RequestContext(request))

******************************************************************************

Traceback:
File "/usr/local/lib/python2.4/site-packages/django/core/handlers/base.py"
in get_response
   82.                 response = callback(request, *callback_args,
**callback_kwargs)
File "/var/django/hg/hgwebproxy/views.py" in hgroot
   111.     hgr = _hgReqWrap(request, resp)
File "/var/django/hg/hgwebproxy/views.py" in __init__
   35.         self.inp = self.env['wsgi.input']
Exception Type: KeyError at /hg/
Exception Value: 'wsgi.input'


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To post to this group, send email to django-users@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/django-users?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to