2016-06-28 70 views
1

我有蟒蛇實現使用100 PUT一個簡單的HTTP服務器繼續:蟒蛇停留在100 HTTP客戶端繼續

class TestHandler(SimpleHTTPRequestHandler): 
    def do_PUT(self): 
     length = int(self.headers.get('Content-Length')) 
     self.send_response_only(100) 
     self.end_headers() 
     data = self.rfile.read(length) 
     res = manipulate(data) 
     new_length = len(res) 
     self.send_response(200) 
     self.send_header("Content-Length", new_length) 
     self.end_headers() 
     self.wfile.write(res) 

server = HTTPServer(("localhost", 8080), TestHandler) 
server.serve_forever() 

我嘗試使用該客戶端來連接到服務器:

def send_put(data): 
    c = HTTPConnection('localhost', 8080) 
    c.request('PUT', 'http://localhost:8080/', headers={'Content-Length': len(data), 'Expect': '100-continue'}) 
    r = c.getresponse() 
    if 100 != r.status: 
     return 
    c.request('PUT', 'http://localhost:8080/', body=data) 
    r = c.getresponse() 
    print(r.read()) 

但是即使我可以在wireshark上看到100個繼續響應,代碼也總是陷入第一個'getresponse'中,我在這裏做錯了什麼? python http甚至支持100-繼續?


編輯:在看了一些python http代碼後,我發現爲什麼getresponse卡住了; Python的HTTP只是忽略了100繼續並永遠不會出現的下一個等待響應(來自python3.4/HTTP/client.py):

# read until we get a non-100 response 
while True: 
    version, status, reason = self._read_status() 
    if status != CONTINUE: 
     break 
    # skip the header from the 100 response 
    while True: 
     skip = self.fp.readline(_MAXLINE + 1) 
     if len(skip) > _MAXLINE: 
      raise LineTooLong("header line") 
     skip = skip.strip() 
     if not skip: 
      break 
     if self.debuglevel > 0: 
      print("header:", skip) 
+0

您是否嘗試過發送'wget localhost:8080'。也試着用'sudo'運行你的python代碼..我運行你的代碼並得到了'AttributeError:TestHandler實例沒有'send_response_only'屬性。另外AFAIK python請求不支持100-繼續 –

+0

你用python3運行它嗎? send_response_only被添加到python 3.2中以支持100次繼續。 – CforLinux

回答

1

我遇到了這個問題,以及;這是一個nine year old Python issue。我想出了下面的毛,而「只是讓它運行」的解決辦法,這似乎是在我的情況下工作(Python的3.5,僅HTTPS):

class ContinueHTTPResponse(http.client.HTTPResponse): 
    def _read_status(self, *args, **kwargs): 
     version, status, reason = super()._read_status(*args, **kwargs) 
     if status == 100: 
      status = 199 
     return version, status, reason 

    def begin(self, *args, **kwargs): 
     super().begin(*args, **kwargs) 
     if self.status == 199: 
      self.status = 100 

    def _check_close(self, *args, **kwargs): 
     return super()._check_close(*args, **kwargs) and self.status != 100 


class ContinueHTTPSConnection(http.client.HTTPSConnection): 
    response_class = ContinueHTTPResponse 

    def getresponse(self, *args, **kwargs): 
     logging.debug('running getresponse') 
     response = super().getresponse(*args, **kwargs) 
     if response.status == 100: 
      setattr(self, '_HTTPConnection__state', http.client._CS_REQ_SENT) 
      setattr(self, '_HTTPConnection__response', None) 
     return response 

我有點使用它像這樣:

conn = ContinueHTTPSConnection(host) 
conn.request(...) 
resp = conn.getresponse() 

if resp.status == http.client.CONTINUE: 
    resp.read() 
    conn.send(body) 
    resp = conn.getresponse() 

# do something with resp if you want... 

警告:超級哈克。可能充滿了錯誤。使用風險自負。