Patchwork D2742: hgweb: parse and store HTTP request headers

login
register
mail settings
Submitter phabricator
Date March 9, 2018, 1:06 a.m.
Message ID <differential-rev-PHID-DREV-4eywlukrwdb2t3xlyxea-req@phab.mercurial-scm.org>
Download mbox | patch
Permalink /patch/29148/
State Superseded
Headers show

Comments

phabricator - March 9, 2018, 1:06 a.m.
indygreg created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  WSGI transmits HTTP request headers as HTTP_* environment variables.
  We teach our parser about these and hook up a dict-like data
  structure that supports case insensitive header manipulation.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D2742

AFFECTED FILES
  mercurial/hgweb/hgweb_mod.py
  mercurial/hgweb/request.py

CHANGE DETAILS




To: indygreg, #hg-reviewers
Cc: mercurial-devel

Patch

diff --git a/mercurial/hgweb/request.py b/mercurial/hgweb/request.py
--- a/mercurial/hgweb/request.py
+++ b/mercurial/hgweb/request.py
@@ -11,6 +11,7 @@ 
 import cgi
 import errno
 import socket
+import wsgiref.headers as wsgiheaders
 #import wsgiref.validate
 
 from .common import (
@@ -85,6 +86,9 @@ 
     querystringlist = attr.ib()
     # Dict of query string arguments. Values are lists with at least 1 item.
     querystringdict = attr.ib()
+    # wsgiref.headers.Headers instance. Operates like a dict with case
+    # insensitive keys.
+    headers = attr.ib()
 
 def parserequestfromenv(env):
     """Parse URL components from environment variables.
@@ -186,15 +190,26 @@ 
         else:
             querystringdict[k] = [v]
 
+    # HTTP_* keys contain HTTP request headers. The Headers structure should
+    # perform case normalization for us. We just rewrite underscore to dash
+    # so keys match what likely went over the wire.
+    headers = []
+    for k, v in env.iteritems():
+        if k.startswith('HTTP_'):
+            headers.append((k[len('HTTP_'):].replace('_', '-'), v))
+
+    headers = wsgiheaders.Headers(headers)
+
     return parsedrequest(url=fullurl, baseurl=baseurl,
                          advertisedurl=advertisedfullurl,
                          advertisedbaseurl=advertisedbaseurl,
                          apppath=apppath,
                          dispatchparts=dispatchparts, dispatchpath=dispatchpath,
                          havepathinfo='PATH_INFO' in env,
                          querystring=querystring,
                          querystringlist=querystringlist,
-                         querystringdict=querystringdict)
+                         querystringdict=querystringdict,
+                         headers=headers)
 
 class wsgirequest(object):
     """Higher-level API for a WSGI request.
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
@@ -351,7 +351,7 @@ 
                 if args:
                     wsgireq.form['file'] = args
 
-            ua = wsgireq.env.get('HTTP_USER_AGENT', '')
+            ua = req.headers.get('User-Agent', '')
             if cmd == 'rev' and 'mercurial' in ua:
                 wsgireq.form['style'] = ['raw']