Skip to content

Commit 4c5cf09

Browse files
committed
Fix Request.SetPostData in Python 3 (cztomczak#228)
1 parent 18c4a58 commit 4c5cf09

File tree

6 files changed

+57
-24
lines changed

6 files changed

+57
-24
lines changed

api/Request.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,10 @@ Set the request method type.
9595
| --- | --- |
9696
| __Return__ | list/dict |
9797

98-
Get the post data. If the form content type is "multipart/form-data"
99-
then the post data will be returned as a list. If the form content
100-
type is "application/x-www-form-urlencoded" then the post data will
98+
Get the post data. All strings are byte strings. If the form content
99+
type is "multipart/form-data" then the post data will be returned
100+
as a list. If the form content type is
101+
"application/x-www-form-urlencoded" then the post data will
101102
be returned as a dict.
102103

103104

@@ -108,8 +109,8 @@ be returned as a dict.
108109
| postData | list/dict |
109110
| __Return__ | void |
110111

111-
Set the post data. See GetPostData() for an explanation of the
112-
postData type.
112+
Set the post data. All strings are expected to be byte strings.
113+
See GetPostData() for an explanation of the postData type.
113114

114115
### GetHeaderMap
115116

src/cefpython.pyx

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -135,19 +135,23 @@ import random
135135
# noinspection PyUnresolvedReferences
136136
import struct
137137

138-
if sys.version_info.major == 2:
138+
# Must use compile-time condition instead of checking sys.version_info.major
139+
# otherwise results in "ImportError: cannot import name urlencode" strange
140+
# error in Python 3.6.
141+
IF PY_MAJOR_VERSION == 2:
139142
# noinspection PyUnresolvedReferences
140143
import urlparse
141-
else:
142-
# noinspection PyUnresolvedReferences
143-
from urllib import parse as urlparse
144-
145-
if sys.version_info.major == 2:
146144
# noinspection PyUnresolvedReferences
147145
from urllib import pathname2url as urllib_pathname2url
148-
else:
146+
# noinspection PyUnresolvedReferences
147+
from urllib import urlencode as urllib_urlencode
148+
ELSE:
149+
# noinspection PyUnresolvedReferences
150+
from urllib import parse as urlparse
149151
# noinspection PyUnresolvedReferences
150152
from urllib.request import pathname2url as urllib_pathname2url
153+
# noinspection PyUnresolvedReferences
154+
from urllib.parse import urlencode as urllib_urlencode
151155

152156
# noinspection PyUnresolvedReferences
153157
from cpython.version cimport PY_MAJOR_VERSION

src/extern/cef/cef_string.pxd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,5 @@ cdef extern from "include/internal/cef_string.h":
2121
cpp_bool FromString(cpp_string& str)
2222
cpp_string ToString()
2323
cpp_wstring ToWString()
24-
char* c_str()
24+
const char* c_str()
2525
size_t length()

src/request.pyx

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,10 @@ cdef class PyRequest:
9999
# pyData is really of type "str", but Cython will throw
100100
# an error if we use that type: "Cannot convert 'bytes'
101101
# object to str implicitly. This is not portable to Py3."
102-
cdef object pyData
102+
cdef bytes pyData
103103
cdef size_t bytesCount
104104
cdef void* voidData
105-
cdef str pyFile
105+
cdef bytes pyFile
106106
while iterator != elementVector.end():
107107
postDataElement = deref(iterator)
108108
if postDataElement.get().GetType() == cef_types.PDE_TYPE_EMPTY:
@@ -112,18 +112,18 @@ cdef class PyRequest:
112112
bytesCount = postDataElement.get().GetBytesCount()
113113
voidData = <void*>malloc(bytesCount)
114114
postDataElement.get().GetBytes(bytesCount, voidData)
115-
pyData = VoidPtrToString(voidData, bytesCount)
115+
pyData = VoidPtrToBytes(voidData, bytesCount)
116116
free(voidData)
117-
if pyData.startswith('--') or retMultipart:
117+
if pyData.startswith(b'--') or retMultipart:
118118
# Content-Type: multipart/form-data
119119
retMultipart.append(pyData)
120120
else:
121121
# Content-Type: application/x-www-form-urlencoded
122122
retUrlEncoded.update(urlparse.parse_qsl(qs=pyData,
123123
keep_blank_values=True))
124124
elif postDataElement.get().GetType() == cef_types.PDE_TYPE_FILE:
125-
pyFile = CefToPyString(postDataElement.get().GetFile())
126-
retMultipart.append("@"+pyFile)
125+
pyFile = CefToPyBytes(postDataElement.get().GetFile())
126+
retMultipart.append(b"@"+pyFile)
127127
else:
128128
raise Exception("Invalid type of CefPostDataElement")
129129
preinc(iterator)
@@ -135,15 +135,15 @@ cdef class PyRequest:
135135
cpdef py_void SetPostData(self, object pyPostData):
136136
cdef CefRefPtr[CefPostData] postData = CefPostData_Create()
137137
cdef CefRefPtr[CefPostDataElement] postDataElement
138-
cdef py_string pyElement
138+
cdef bytes pyElement
139139
cdef CefString sfile
140140
if type(pyPostData) == list:
141141
for pyElement in pyPostData:
142-
if pyElement.startswith('--'):
142+
if pyElement.startswith(b'--'):
143143
postDataElement = CefPostDataElement_Create()
144144
postDataElement.get().SetToBytes(len(pyElement),
145145
<char*>pyElement)
146-
elif pyElement.startswith('@'):
146+
elif pyElement.startswith(b'@'):
147147
postDataElement = CefPostDataElement_Create()
148148
PyToCefString(pyElement[1:], sfile)
149149
postDataElement.get().SetToFile(sfile)
@@ -156,8 +156,7 @@ cdef class PyRequest:
156156
postData.get().AddElement(postDataElement)
157157
self.GetCefRequest().get().SetPostData(postData)
158158
elif type(pyPostData) == dict:
159-
pyElement = urllib.urlencode(pyPostData)
160-
pyElement = str(pyElement)
159+
pyElement = urllib_urlencode(pyPostData).encode()
161160
postDataElement = CefPostDataElement_Create()
162161
postDataElement.get().SetToBytes(len(pyElement), <char*>pyElement)
163162
postData.get().AddElement(postDataElement)

src/string_utils.pyx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ cdef py_string CefToPyString(
9494
g_applicationSettings["string_encoding"],
9595
errors=BYTES_DECODE_ERRORS))
9696

97+
cdef bytes CefToPyBytes(
98+
ConstCefString& cefString):
99+
return <bytes>cefString.ToString()
100+
97101
cdef void PyToCefString(
98102
py_string pyString,
99103
CefString& cefString
@@ -148,3 +152,7 @@ cdef py_string VoidPtrToString(const void* data, size_t dataLength):
148152
return <unicode>((<bytes>(<char*>data)[:dataLength]).decode(
149153
g_applicationSettings["string_encoding"],
150154
errors=BYTES_DECODE_ERRORS))
155+
156+
cdef bytes VoidPtrToBytes(const void* data, size_t dataLength):
157+
return <bytes>((<char*>data)[:dataLength])
158+

unittests/main_test.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from cefpython3 import cefpython as cef
1212
import time
1313
import base64
14+
import os
1415
import sys
1516

1617
# To show the window for an extended period of time increase this number.
@@ -159,6 +160,26 @@ def test_main(self):
159160
browser.SetJavascriptBindings(bindings)
160161
subtest_message("browser.SetJavascriptBindings() ok")
161162

163+
# Test Request.SetPostData(list)
164+
req = cef.Request.CreateRequest()
165+
req_file = os.path.dirname(os.path.abspath(__file__))
166+
req_file = os.path.join(req_file, "main_test.py")
167+
if sys.version_info.major > 2:
168+
req_file = req_file.encode()
169+
req_data = [b"--key=value", b"@"+req_file]
170+
req.SetMethod("POST")
171+
req.SetPostData(req_data)
172+
self.assertEqual(req_data, req.GetPostData())
173+
subtest_message("cef.Request.SetPostData(list) ok")
174+
175+
# Test Request.SetPostData(dict)
176+
req = cef.Request.CreateRequest()
177+
req_data = {b"key": b"value"}
178+
req.SetMethod("POST")
179+
req.SetPostData(req_data)
180+
self.assertEqual(req_data, req.GetPostData())
181+
subtest_message("cef.Request.SetPostData(dict) ok")
182+
162183
# Run message loop for some time.
163184
# noinspection PyTypeChecker
164185
for i in range(MESSAGE_LOOP_RANGE):

0 commit comments

Comments
 (0)