# Copyright (c) 2012-2014 The CEF Python authors. All rights reserved. # License: New BSD License. # Website: http://code.google.com/p/cefpython/ include "cefpython.pyx" class Request: Flags = { "None": cef_types.UR_FLAG_NONE, "SkipCache": cef_types.UR_FLAG_SKIP_CACHE, "AllowCachedCredentials": cef_types.UR_FLAG_ALLOW_CACHED_CREDENTIALS, "AllowCookies": 0, # keep for BC "ReportUploadProgress": cef_types.UR_FLAG_REPORT_UPLOAD_PROGRESS, "ReportLoadTiming": 0, # keep for BC "ReportRawHeaders": 0, # keep for BC "NoDownloadData": cef_types.UR_FLAG_NO_DOWNLOAD_DATA, "NoRetryOn5xx": cef_types.UR_FLAG_NO_RETRY_ON_5XX, } def __init__(self): # Request object is just a public API wrapper, # the real Request object is named PyRequest. raise Exception("Request object cannot be instantiated directly, " "use static method Request.CreateRequest()") @staticmethod def CreateRequest(): cdef CefRefPtr[CefRequest] cefRequest = CefRequest_Create() cdef PyRequest pyRequest = CreatePyRequest(cefRequest) return pyRequest cdef PyRequest CreatePyRequest(CefRefPtr[CefRequest] cefRequest): # This can't be named "GetPyRequest()" as CefRequest has # no unique identifier, so each time a different python object # must be returned. cdef PyRequest pyRequest = PyRequest() pyRequest.cefRequest = cefRequest return pyRequest cdef class PyRequest: cdef CefRefPtr[CefRequest] cefRequest cdef CefRefPtr[CefRequest] GetCefRequest(self) except *: if self.cefRequest != NULL and self.cefRequest.get(): return self.cefRequest raise Exception("PyRequest.GetCefRequest() failed: " "CefRequest was destroyed") cpdef str GetUrl(self): return CefToPyString(self.GetCefRequest().get().GetURL()) cpdef py_void SetUrl(self, py_string url): cdef CefString cefUrl PyToCefString(url, cefUrl) self.GetCefRequest().get().SetURL(cefUrl) cpdef str GetMethod(self): return CefToPyString(self.GetCefRequest().get().GetMethod()) cpdef py_void SetMethod(self, py_string method): cdef CefString cefMethod PyToCefString(method, cefMethod) self.GetCefRequest().get().SetMethod(cefMethod) cpdef object GetPostData(self): if self.GetMethod() != "POST": return {} cdef cpp_vector[CefRefPtr[CefPostDataElement]] elementVector cdef CefRefPtr[CefPostData] postData = ( self.GetCefRequest().get().GetPostData()) if postData.get().GetElementCount() == 0: return {} postData.get().GetElements(elementVector) cdef cpp_vector[CefRefPtr[CefPostDataElement]].iterator iterator = ( elementVector.begin()) cdef CefRefPtr[CefPostDataElement] postDataElement cdef list retMultipart = [] cdef dict retUrlEncoded = {} # 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 size_t bytesCount cdef void* voidData cdef str pyFile while iterator != elementVector.end(): postDataElement = deref(iterator) if postDataElement.get().GetType() == cef_types.PDE_TYPE_EMPTY: # May return an empty dict - retUrlEncoded. pass elif postDataElement.get().GetType() == cef_types.PDE_TYPE_BYTES: bytesCount = postDataElement.get().GetBytesCount() voidData = malloc(bytesCount) postDataElement.get().GetBytes(bytesCount, voidData) pyData = VoidPtrToString(voidData, bytesCount) free(voidData) if pyData.startswith('--') 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) else: raise Exception("Invalid type of CefPostDataElement") preinc(iterator) if retMultipart: return retMultipart else: return retUrlEncoded cpdef py_void SetPostData(self, object pyPostData): cdef CefRefPtr[CefPostData] postData = ( self.GetCefRequest().get().GetPostData()) postData.get().RemoveElements() cdef CefRefPtr[CefPostDataElement] postDataElement cdef py_string pyElement cdef CefString sfile if type(pyPostData) == list: for pyElement in pyPostData: if pyElement.startswith('--'): postDataElement = CefPostDataElement_Create() postDataElement.get().SetToBytes(len(pyElement), pyElement) elif pyElement.startswith('@'): postDataElement = CefPostDataElement_Create() PyToCefString(pyElement[1:], sfile) postDataElement.get().SetToFile(sfile) elif not pyElement: postDataElement = CefPostDataElement_Create() postDataElement.get().SetToEmpty() else: raise Exception("Invalid element in postData: %s" % ( pyElement)) postData.get().AddElement(postDataElement) elif type(pyPostData) == dict: pyElement = urllib.urlencode(pyPostData) pyElement = str(pyElement) postDataElement = CefPostDataElement_Create() postDataElement.get().SetToBytes(len(pyElement), pyElement) postData.get().AddElement(postDataElement) else: raise Exception("Invalid type of postData, only dict|list allowed") cpdef dict GetHeaderMap(self): cdef list headerMultimap = self.GetHeaderMultimap() cdef dict headerMap = {} cdef tuple headerTuple for headerTuple in headerMultimap: key = headerTuple[0] value = headerTuple[1] headerMap[key] = value return headerMap cpdef list GetHeaderMultimap(self): cdef cpp_multimap[CefString, CefString] cefHeaderMap self.GetCefRequest().get().GetHeaderMap(cefHeaderMap) cdef list pyHeaderMultimap = [] cdef cpp_multimap[CefString, CefString].iterator iterator = ( cefHeaderMap.begin()) cdef CefString cefKey cdef CefString cefValue cdef str pyKey cdef str pyValue while iterator != cefHeaderMap.end(): cefKey = deref(iterator).first cefValue = deref(iterator).second pyKey = CefToPyString(cefKey) pyValue = CefToPyString(cefValue) pyHeaderMultimap.append((pyKey, pyValue)) preinc(iterator) return pyHeaderMultimap cpdef py_void SetHeaderMap(self, dict headerMap): assert len(headerMap) > 0, "headerMap param is empty" cpdef list headerMultimap = [] cdef object key for key in headerMap: headerMultimap.append((str(key), str(headerMap[key]))) self.SetHeaderMultimap(headerMultimap) cpdef py_void SetHeaderMultimap(self, list headerMultimap): assert len(headerMultimap) > 0, "headerMultimap param is empty" cdef cpp_multimap[CefString, CefString] cefHeaderMap cdef CefString cefKey cdef CefString cefValue cdef cpp_pair[CefString, CefString] pair cdef tuple headerTuple for headerTuple in headerMultimap: PyToCefString(str(headerTuple[0]), cefKey) PyToCefString(str(headerTuple[1]), cefValue) pair.first, pair.second = cefKey, cefValue cefHeaderMap.insert(pair) self.GetCefRequest().get().SetHeaderMap(cefHeaderMap) cpdef int GetFlags(self) except *: return self.GetCefRequest().get().GetFlags() cpdef py_void SetFlags(self, int flags): self.GetCefRequest().get().SetFlags(flags) cpdef str GetFirstPartyForCookies(self): return CefToPyString( self.GetCefRequest().get().GetFirstPartyForCookies()) cpdef py_void SetFirstPartyForCookies(self, py_string url): self.GetCefRequest().get().SetFirstPartyForCookies( PyToCefStringValue(url))