Index: Lib/httplib.py =================================================================== --- Lib/httplib.py (revision 54136) +++ Lib/httplib.py (working copy) @@ -635,6 +635,8 @@ self._set_hostport(host, port) if strict is not None: self.strict = strict + # sended headers + self.sended_hdrs = [] def _set_hostport(self, host, port): if port is None: @@ -780,6 +782,7 @@ str = '%s %s %s' % (method, url, self._http_vsn_str) self._output(str) + self.sended_hdrs = [str] if self._http_vsn == 11: # Issue some standard headers for better HTTP/1.1 compliance @@ -852,6 +855,7 @@ str = '%s: %s' % (header, value) self._output(str) + self.sended_hdrs.append((header,value)) def endheaders(self): """Indicate that the last header line has been sent to the server.""" Index: Lib/test/test_urllib2.py =================================================================== --- Lib/test/test_urllib2.py (revision 54136) +++ Lib/test/test_urllib2.py (working copy) @@ -229,6 +229,7 @@ self.proto, self.args = proto, args class MockFile: + history = [] def read(self, count=None): pass def readline(self, count=None): pass def close(self): pass @@ -683,6 +684,7 @@ self.req_headers = [] self.data = None self.raise_on_endheaders = False + self.sended_hdrs = ["GET /unknown.html HTTP/1.1\n"] def __call__(self, host): self.host = host return self @@ -693,6 +695,8 @@ self.selector = url self.req_headers += headers.items() self.req_headers.sort() + self.sended_headers = ['%s %s HTTP/1.1\n' % (method,url)] + self.sended_headers.extend(headers.iteritems()) if body: self.data = body if self.raise_on_endheaders: @@ -1052,3 +1056,4 @@ if __name__ == "__main__": test_main(verbose=True) + Index: Lib/test/test_urllib2net.py =================================================================== --- Lib/test/test_urllib2net.py (revision 54136) +++ Lib/test/test_urllib2net.py (working copy) @@ -103,7 +103,7 @@ def test_basic(self): # Simple test expected to pass. open_url = urllib2.urlopen("http://www.python.org/") - for attr in ("read", "close", "info", "geturl"): + for attr in ("read", "close", "info", "geturl","history"): self.assert_(hasattr(open_url, attr), "object returned from " "urlopen lacks the %s attribute" % attr) try: @@ -146,7 +146,23 @@ # urllib2.urlopen, "http://www.sadflkjsasadf.com/") urllib2.urlopen, "http://www.python.invalid./") +class HistoryAndHeaderTests(unittest.TestCase): + def test_head_request(self): + r = urllib2.Request("http://www.python.org/",request_cmd = "HEAD") + fd = urllib2.urlopen(r) + self.assertEqual(len(fd.read()),0) # head request must not return data + def test_history(self): + fd = urllib2.urlopen("http://www.python.org/") + self.assert_(hasattr(fd,'history')) + hist = fd.history + self.assert_(isinstance(hist,list)) + self.assert_(len(hist) > 0) + fhist_el = hist[0] + self.assert_(isinstance(fhist_el,urllib2.Headers)) + for name in ('sended','recived','request_line','res_code'): + self.assert_(hasattr(fhist_el,name)) + class OtherNetworkTests(unittest.TestCase): def setUp(self): if 0: # for debugging @@ -289,6 +305,7 @@ AuthTests, OtherNetworkTests, CloseSocketTest, + HistoryAndHeaderTests ) if __name__ == "__main__": Index: Lib/urllib2.py =================================================================== --- Lib/urllib2.py (revision 54136) +++ Lib/urllib2.py (working copy) @@ -182,10 +182,34 @@ host = _cut_port_re.sub("", host, 1) return host.lower() +class Headers(object): + def __init__(self,request_line,res_code, + sended = None,recived = None, + total_bytes = None): + if sended is None: + self.sended = [] + else: + self.sended = sended[:] + if recived is None: + self.recived = [] + else: + self.recived = recived[:] + self.request_line = request_line + self.res_code = res_code + self.total_bytes = total_bytes + def set_sended(self,request_line,headers): + self.request_line = request_line + self.sended = headers[:] + def set_recived(self,res_code,headers): + self.res_code = res_code + self.recived = headers[:] + class Request: def __init__(self, url, data=None, headers={}, - origin_req_host=None, unverifiable=False): + origin_req_host=None, unverifiable=False, + request_cmd = "GET", + history = None): # unwrap('') --> 'type://host/path' self.__original = unwrap(url) self.type = None @@ -194,6 +218,7 @@ self.port = None self.data = data self.headers = {} + self.request_cmd = request_cmd for key, value in headers.items(): self.add_header(key, value) self.unredirected_hdrs = {} @@ -201,6 +226,8 @@ origin_req_host = request_host(self) self.origin_req_host = origin_req_host self.unverifiable = unverifiable + # this field used only in temporary http redirection requests + self.history = history or [] def __getattr__(self, attr): # XXX this is a fallback mechanism to guard against these @@ -218,7 +245,7 @@ if self.has_data(): return "POST" else: - return "GET" + return self.request_cmd # XXX these helper methods are lame @@ -529,7 +556,9 @@ return Request(newurl, headers=req.headers, origin_req_host=req.get_origin_req_host(), - unverifiable=True) + unverifiable=True, + request_cmd = req.request_cmd, + history = fp.history) else: raise HTTPError(req.get_full_url(), code, msg, headers, fp) @@ -1092,6 +1121,18 @@ resp = addinfourl(fp, r.msg, req.get_full_url()) resp.code = r.status resp.msg = r.reason + recived = [] + info = resp.info() + for i in info: + recived.append((i,info[i])) + if req.history: + hist = req.history[:] + else: + hist = [] + hist.append(Headers(h.sended_hdrs[0], + r.status,h.sended_hdrs[1:], + recived = recived)) + resp.history = hist return resp