def generic(self, method, path, data='', content_type='application/octet-stream', **extra): parsed = urlparse(path) data = force_bytes(data, DEFAULT_CHARSET) r = { 'PATH_INFO': self._get_path(parsed), 'REQUEST_METHOD': str(method), } if data: r.update({ 'CONTENT_LENGTH': len(data), 'CONTENT_TYPE': str(content_type), 'wsgi.input': FakePayload(data), }) r.update(extra) # If QUERY_STRING is absent or empty, we want to extract it from the URL. if not r.get('QUERY_STRING'): query_string = force_bytes(parsed[4]) # WSGI requires latin-1 encoded strings. See get_path_info(). if six.PY3: query_string = query_string.decode('iso-8859-1') r['QUERY_STRING'] = query_string return self.request(**r)
def encode_file(boundary, key, file): to_bytes = lambda s: force_bytes(s, DEFAULT_CHARSET) content_type = mimetypes.guess_type(file.name)[0] if content_type is None: content_type = 'application/octet-stream' return [ to_bytes('--%s' % boundary), to_bytes('Content-Disposition: form-data; name="%s"; filename="%s"' \ % (key, os.path.basename(file.name))), to_bytes('Content-Type: %s' % content_type), b'', file.read() ]
def _encode_data(self, data, content_type, ): if content_type is MULTIPART_CONTENT: return encode_multipart(BOUNDARY, data) if content_type is X_WWW_FORM_URLENCODED: return encode_www_form_data(data) else: # Encode the content so that the byte representation is correct. match = CONTENT_TYPE_RE.match(content_type) if match: charset = match.group(1) else: charset = DEFAULT_CHARSET return force_bytes(data, encoding=charset)
def encode_multipart(boundary, data): """ Encodes multipart POST data from a dictionary of form values. The key will be used as the form data name; the value will be transmitted as content. If the value is a file, the contents of the file will be sent as an application/octet-stream; otherwise, str(value) will be sent. """ lines = [] to_bytes = lambda s: force_bytes(s, DEFAULT_CHARSET) # Not by any means perfect, but good enough for our purposes. is_file = lambda thing: hasattr(thing, "read") and callable(thing.read) # Each bit of the multipart form data could be either a form value or a # file, or a *list* of form values and/or files. Remember that HTTP field # names can be duplicated! for (key, value) in data.items(): if is_file(value): lines.extend(encode_file(boundary, key, value)) elif not isinstance(value, six.string_types) and is_iterable(value): for item in value: if is_file(item): lines.extend(encode_file(boundary, key, item)) else: lines.extend([ to_bytes(val) for val in [ '--%s' % boundary, 'Content-Disposition: form-data; name="%s"' % key, '', item ] ]) else: lines.extend([ to_bytes(val) for val in [ '--%s' % boundary, 'Content-Disposition: form-data; name="%s"' % key, '', value ] ]) lines.extend([ to_bytes('--%s--' % boundary), b'', ]) return b'\r\n'.join(lines)
def write(self, content): if self.read_started: raise ValueError("Unable to write a payload after he's been read") content = force_bytes(content) self.__content.write(content) self.__len += len(content)
def encode_www_form_data(data): result = {} for (key, value) in data.items(): result[key] = force_bytes(value) return urlencode(result)