[Python-checkins] python/dist/src/Lib httplib.py,1.56,1.57

jhylton@users.sourceforge.net jhylton@users.sourceforge.net
Sun, 07 Jul 2002 09:51:39 -0700


Update of /cvsroot/python/python/dist/src/Lib
In directory usw-pr-cvs1:/tmp/cvs-serv14230

Modified Files:
	httplib.py 
Log Message:
Fix for SF bug #432621: httplib: multiple Set-Cookie headers

If multiple header fields with the same name occur, they are combined
according to the rules in RFC 2616 sec 4.2:

Appending each subsequent field-value to the first, each separated by
a comma. The order in which header fields with the same field-name are
received is significant to the interpretation of the combined field
value.



Index: httplib.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/httplib.py,v
retrieving revision 1.56
retrieving revision 1.57
diff -C2 -d -r1.56 -r1.57
*** httplib.py	6 Jul 2002 18:55:01 -0000	1.56
--- httplib.py	7 Jul 2002 16:51:37 -0000	1.57
***************
*** 94,97 ****
--- 94,203 ----
  _CS_REQ_SENT = 'Request-sent'
  
+ class HTTPMessage(mimetools.Message):
+ 
+     def addheader(self, key, value):
+         """Add header for field key handling repeats."""
+         prev = self.dict.get(key)
+         if prev is None:
+             self.dict[key] = value
+         else:
+             combined = ", ".join((prev, value))
+             self.dict[key] = combined
+ 
+     def addcontinue(self, key, more):
+         """Add more field data from a continuation line."""
+         prev = self.dict[key]
+         self.dict[key] = prev + "\n " + more
+ 
+     def readheaders(self):
+         """Read header lines.
+ 
+         Read header lines up to the entirely blank line that terminates them.
+         The (normally blank) line that ends the headers is skipped, but not
+         included in the returned list.  If a non-header line ends the headers,
+         (which is an error), an attempt is made to backspace over it; it is
+         never included in the returned list.
+ 
+         The variable self.status is set to the empty string if all went well,
+         otherwise it is an error message.  The variable self.headers is a
+         completely uninterpreted list of lines contained in the header (so
+         printing them will reproduce the header exactly as it appears in the
+         file).
+ 
+         If multiple header fields with the same name occur, they are combined
+         according to the rules in RFC 2616 sec 4.2:
+ 
+         Appending each subsequent field-value to the first, each separated
+         by a comma. The order in which header fields with the same field-name
+         are received is significant to the interpretation of the combined
+         field value.
+         """
+         # XXX The implementation overrides the readheaders() method of
+         # rfc822.Message.  The base class design isn't amenable to
+         # customized behavior here so the method here is a copy of the
+         # base class code with a few small changes.
+ 
+         self.dict = {}
+         self.unixfrom = ''
+         self.headers = list = []
+         self.status = ''
+         headerseen = ""
+         firstline = 1
+         startofline = unread = tell = None
+         if hasattr(self.fp, 'unread'):
+             unread = self.fp.unread
+         elif self.seekable:
+             tell = self.fp.tell
+         while 1:
+             if tell:
+                 try:
+                     startofline = tell()
+                 except IOError:
+                     startofline = tell = None
+                     self.seekable = 0
+             line = self.fp.readline()
+             if not line:
+                 self.status = 'EOF in headers'
+                 break
+             # Skip unix From name time lines
+             if firstline and line.startswith('From '):
+                 self.unixfrom = self.unixfrom + line
+                 continue
+             firstline = 0
+             if headerseen and line[0] in ' \t':
+                 # XXX Not sure if continuation lines are handled properly
+                 # for http and/or for repeating headers
+                 # It's a continuation line.
+                 list.append(line)
+                 x = self.dict[headerseen] + "\n " + line.strip()
+                 self.addcontinue(headerseen, line.strip())
+                 continue
+             elif self.iscomment(line):
+                 # It's a comment.  Ignore it.
+                 continue
+             elif self.islast(line):
+                 # Note! No pushback here!  The delimiter line gets eaten.
+                 break
+             headerseen = self.isheader(line)
+             if headerseen:
+                 # It's a legal header line, save it.
+                 list.append(line)
+                 self.addheader(headerseen, line[len(headerseen)+1:].strip())
+                 continue
+             else:
+                 # It's not a header line; throw it back and stop here.
+                 if not self.dict:
+                     self.status = 'No headers'
+                 else:
+                     self.status = 'Non-header line where header expected'
+                 # Try to undo the read.
+                 if unread:
+                     unread(line)
+                 elif tell:
+                     self.fp.seek(startofline)
+                 else:
+                     self.status = self.status + '; bad seek'
+                 break
+     
  
  class HTTPResponse:
***************
*** 187,194 ****
              self.chunked = 0
              self.will_close = 1
!             self.msg = mimetools.Message(StringIO())
              return
  
!         self.msg = mimetools.Message(self.fp, 0)
          if self.debuglevel > 0:
              for hdr in self.msg.headers:
--- 293,300 ----
              self.chunked = 0
              self.will_close = 1
!             self.msg = HTTPMessage(StringIO())
              return
  
!         self.msg = HTTPMessage(self.fp, 0)
          if self.debuglevel > 0:
              for hdr in self.msg.headers: