在接受100 continue标头后尝试发送Python HTTPConnection内容



我一直在尝试调试我继承的Python脚本。它试图通过HTTPLib将CSV发布到网站上。据我所知,问题是HTTPLib无法处理接收100 continue响应,因为python http客户端被困在100 continue上。类似于该帖子;Just Works";通过Curl,但由于各种原因,我们需要从Python脚本运行它。

我曾试图采用该帖子的回答中详细描述的解决方案,但在接受100个继续回复后,我找不到一种方法来提交CSV

一般流程需要如下:

  • ->建立连接
  • ->发送包括";期望:100继续";头,但还不包括JSON主体
  • <-接收";100继续">
  • ->使用相同的连接,发送请求的JSON正文
  • <-接收包含其他信息的JSON响应中的200 OK消息

这是当前状态下的代码,删除了我的10多个其他尝试解决方法的注释残余:

#!/usr/bin/env python
import os
import ssl
import http.client
import binascii
import logging
import json
#classes taken from https://stackoverflow.com/questions/38084993/python-http-client-stuck-on-100-continue
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

def uploadTradeIngest(ingestFile, certFile, certPass, host, port, url):
boundary = binascii.hexlify(os.urandom(16)).decode("ascii")
headers = {
"accept": "application/json",
"Content-Type": "multipart/form-data; boundary=%s" % boundary,
"Expect": "100-continue",
}
context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
context.load_cert_chain(certfile=certFile, password=certPass)
connection = ContinueHTTPSConnection(
host, port=port, context=context)
with open(ingestFile, "r") as fh:
ingest = fh.read()
## Create form-data boundary
ingest = "--%srnContent-Disposition: form-data; " % boundary + 
"name="file"; filename="%s"" % os.path.basename(ingestFile) + 
"rnrn%srn--%s--rn" % (ingest, boundary)
print("pre-request")
connection.request(
method="POST", url=url, headers=headers)
print("post-request")
#resp = connection.getresponse()
resp = connection.getresponse()
if resp.status == http.client.CONTINUE:
resp.read()
print("pre-send ingest")
ingest = json.dumps(ingest)
ingest = ingest.encode()
print(ingest)
connection.send(ingest)
print("post-send ingest")
resp = connection.getresponse()
print("response1")
print(resp)
print("response2")
print(resp.read())
print("response3")
return resp.read()

但这只是返回一个400";坏请求";回答问题(我认为(在于";摄取";变量如果我不通过json.dumps((和encoder((运行它,那么HTTPConnection.send((方法会拒绝它:

ERROR: Got error: memoryview: a bytes-like object is required, not 'str'

我曾考虑过使用请求库,但我无法让它使用我的本地证书捆绑包来接受网站的证书。我有一个带有加密密钥的完整链,我确实对其进行了解密,但仍然遇到来自请求的SSL_VIFY错误。如果你有什么建议可以解决我目前的请求问题,我也很乐意走这条路。

我如何使用HTTPLib或Request(或任何其他库(来实现我需要实现的目标?

如果将来有人遇到这个问题,我最终会用一点笨拙的方法来解决它。我尝试过HTTPLib、Request和URLLib3都不处理100 continue头,所以……我只是通过subprocess.run((函数为Curl编写了一个Python包装,如下所示:

def sendReq(upFile):
sendFile=f"file=@{upFile}"
completed = subprocess.run([
curlPath,
'--cert',
args.cert,
'--key',
args.key,
targetHost,
'-H',
'accept: application/json',
'-H',
'Content-Type: multipart/form-data',
'-H',
'Expect: 100-continue',
'-F',
sendFile,
'-s'
], stdout=subprocess.PIPE, universal_newlines=True)
return completed.stdout

我遇到的唯一问题是,如果Curl是针对NSS库构建的,它就会失败。我通过在包中包含一个静态构建的Curl二进制文件来解决这个问题,该二进制文件的路径包含在代码中的curlPath变量中。我从这个Github回购中获得了这个二进制文件。

最新更新