Skip to content

Commit

Permalink
Fix Request.SetPostData in Python 3 (#228)
Browse files Browse the repository at this point in the history
  • Loading branch information
cztomczak committed Aug 13, 2018
1 parent 18c4a58 commit 4c5cf09
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 24 deletions.
11 changes: 6 additions & 5 deletions api/Request.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,10 @@ Set the request method type.
| --- | --- |
| __Return__ | list/dict |

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


Expand All @@ -108,8 +109,8 @@ be returned as a dict.
| postData | list/dict |
| __Return__ | void |

Set the post data. See GetPostData() for an explanation of the
postData type.
Set the post data. All strings are expected to be byte strings.
See GetPostData() for an explanation of the postData type.

### GetHeaderMap

Expand Down
18 changes: 11 additions & 7 deletions src/cefpython.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -135,19 +135,23 @@ import random
# noinspection PyUnresolvedReferences
import struct

if sys.version_info.major == 2:
# Must use compile-time condition instead of checking sys.version_info.major
# otherwise results in "ImportError: cannot import name urlencode" strange
# error in Python 3.6.
IF PY_MAJOR_VERSION == 2:
# noinspection PyUnresolvedReferences
import urlparse
else:
# noinspection PyUnresolvedReferences
from urllib import parse as urlparse

if sys.version_info.major == 2:
# noinspection PyUnresolvedReferences
from urllib import pathname2url as urllib_pathname2url
else:
# noinspection PyUnresolvedReferences
from urllib import urlencode as urllib_urlencode
ELSE:
# noinspection PyUnresolvedReferences
from urllib import parse as urlparse
# noinspection PyUnresolvedReferences
from urllib.request import pathname2url as urllib_pathname2url
# noinspection PyUnresolvedReferences
from urllib.parse import urlencode as urllib_urlencode

# noinspection PyUnresolvedReferences
from cpython.version cimport PY_MAJOR_VERSION
Expand Down
2 changes: 1 addition & 1 deletion src/extern/cef/cef_string.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ cdef extern from "include/internal/cef_string.h":
cpp_bool FromString(cpp_string& str)
cpp_string ToString()
cpp_wstring ToWString()
char* c_str()
const char* c_str()
size_t length()
21 changes: 10 additions & 11 deletions src/request.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,10 @@ cdef class PyRequest:
# pyData is really of type "str", but Cython will throw
# an error if we use that type: "Cannot convert 'bytes'
# object to str implicitly. This is not portable to Py3."
cdef object pyData
cdef bytes pyData
cdef size_t bytesCount
cdef void* voidData
cdef str pyFile
cdef bytes pyFile
while iterator != elementVector.end():
postDataElement = deref(iterator)
if postDataElement.get().GetType() == cef_types.PDE_TYPE_EMPTY:
Expand All @@ -112,18 +112,18 @@ cdef class PyRequest:
bytesCount = postDataElement.get().GetBytesCount()
voidData = <void*>malloc(bytesCount)
postDataElement.get().GetBytes(bytesCount, voidData)
pyData = VoidPtrToString(voidData, bytesCount)
pyData = VoidPtrToBytes(voidData, bytesCount)
free(voidData)
if pyData.startswith('--') or retMultipart:
if pyData.startswith(b'--') or retMultipart:
# Content-Type: multipart/form-data
retMultipart.append(pyData)
else:
# Content-Type: application/x-www-form-urlencoded
retUrlEncoded.update(urlparse.parse_qsl(qs=pyData,
keep_blank_values=True))
elif postDataElement.get().GetType() == cef_types.PDE_TYPE_FILE:
pyFile = CefToPyString(postDataElement.get().GetFile())
retMultipart.append("@"+pyFile)
pyFile = CefToPyBytes(postDataElement.get().GetFile())
retMultipart.append(b"@"+pyFile)
else:
raise Exception("Invalid type of CefPostDataElement")
preinc(iterator)
Expand All @@ -135,15 +135,15 @@ cdef class PyRequest:
cpdef py_void SetPostData(self, object pyPostData):
cdef CefRefPtr[CefPostData] postData = CefPostData_Create()
cdef CefRefPtr[CefPostDataElement] postDataElement
cdef py_string pyElement
cdef bytes pyElement
cdef CefString sfile
if type(pyPostData) == list:
for pyElement in pyPostData:
if pyElement.startswith('--'):
if pyElement.startswith(b'--'):
postDataElement = CefPostDataElement_Create()
postDataElement.get().SetToBytes(len(pyElement),
<char*>pyElement)
elif pyElement.startswith('@'):
elif pyElement.startswith(b'@'):
postDataElement = CefPostDataElement_Create()
PyToCefString(pyElement[1:], sfile)
postDataElement.get().SetToFile(sfile)
Expand All @@ -156,8 +156,7 @@ cdef class PyRequest:
postData.get().AddElement(postDataElement)
self.GetCefRequest().get().SetPostData(postData)
elif type(pyPostData) == dict:
pyElement = urllib.urlencode(pyPostData)
pyElement = str(pyElement)
pyElement = urllib_urlencode(pyPostData).encode()
postDataElement = CefPostDataElement_Create()
postDataElement.get().SetToBytes(len(pyElement), <char*>pyElement)
postData.get().AddElement(postDataElement)
Expand Down
8 changes: 8 additions & 0 deletions src/string_utils.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ cdef py_string CefToPyString(
g_applicationSettings["string_encoding"],
errors=BYTES_DECODE_ERRORS))

cdef bytes CefToPyBytes(
ConstCefString& cefString):
return <bytes>cefString.ToString()

cdef void PyToCefString(
py_string pyString,
CefString& cefString
Expand Down Expand Up @@ -148,3 +152,7 @@ cdef py_string VoidPtrToString(const void* data, size_t dataLength):
return <unicode>((<bytes>(<char*>data)[:dataLength]).decode(
g_applicationSettings["string_encoding"],
errors=BYTES_DECODE_ERRORS))

cdef bytes VoidPtrToBytes(const void* data, size_t dataLength):
return <bytes>((<char*>data)[:dataLength])

21 changes: 21 additions & 0 deletions unittests/main_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from cefpython3 import cefpython as cef
import time
import base64
import os
import sys

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

# Test Request.SetPostData(list)
req = cef.Request.CreateRequest()
req_file = os.path.dirname(os.path.abspath(__file__))
req_file = os.path.join(req_file, "main_test.py")
if sys.version_info.major > 2:
req_file = req_file.encode()
req_data = [b"--key=value", b"@"+req_file]
req.SetMethod("POST")
req.SetPostData(req_data)
self.assertEqual(req_data, req.GetPostData())
subtest_message("cef.Request.SetPostData(list) ok")

# Test Request.SetPostData(dict)
req = cef.Request.CreateRequest()
req_data = {b"key": b"value"}
req.SetMethod("POST")
req.SetPostData(req_data)
self.assertEqual(req_data, req.GetPostData())
subtest_message("cef.Request.SetPostData(dict) ok")

# Run message loop for some time.
# noinspection PyTypeChecker
for i in range(MESSAGE_LOOP_RANGE):
Expand Down

0 comments on commit 4c5cf09

Please sign in to comment.