Setting up hgwebdir.cgi on Apache which then proxied through Nginx at the front. SSL was enabled at Nginx level but not apache since it just running at localhost. Work perfectly fine except when pushing, I got this error:-

searching for changes
ssl required

Turn out that mercurial check for ‘https’ url scheme when pushing and refused if we just using plain HTTP. So I just set scheme header in the nginx config:-

location / {
    proxy_pass   http://127.0.0.1:81;
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Url-Scheme $scheme;
}

But it still won’t work. After searching for a while, find out that I need to set the wsgi environment variable for url scheme. In WSGI, we can alter it behavior by wrapping it with our own wsgi application. For more complete application, it called middleware. Our app however was simple. We just need to add the variable.

The original hgwebdir.cgi contain this:-

def make_web_app():
    return hgwebdir("hgweb.config")

wsgicgi.launch(wsgiapplication(make_web_app))

Which we wrapped inside our own:-

def make_web_app():
    return hgwebdir("hgweb.config")

def myapplication(environ, start_response): environ['wsgi.url_scheme'] = environ.get('HTTP_X_URL_SCHEME', 'http') app = wsgiapplication(make_web_app) return app(environ, start_response)

wsgicgi.launch(myapplication)

Briefly, WSGI application is just a callable that accept 2 arguments (environ, start_response) that return an iterable. Here, instead of passing the hgwebdir application to the wsgicgi.launch, we passed our own application (which a simply a function that take 2 arguments). Our function then call the actual application which also a callable that accept 2 arguments and return what ever output it has.