def test__get_response_restores_files_across_requests(self): handler = views.WebApplicationHandler(3) file_content = sample_binary_data file_name = 'content' recorder = [] def get_response_read_content_files(self, request): # Simple get_response method which returns the 'file_name' file # from the request in the response. content = request.FILES[file_name].read() # Record calls. recorder.append(content) response = HttpResponse(content=content, content_type=b"text/plain; charset=utf-8") handler._WebApplicationHandler__retry.add(response) return response self.patch(WSGIHandler, "get_response", get_response_read_content_files) body, headers = encode_multipart_data( [], [[file_name, io.BytesIO(file_content)]]) env = { 'REQUEST_METHOD': 'POST', 'wsgi.input': wsgi._InputStream(io.BytesIO(body.encode("utf-8"))), 'CONTENT_TYPE': headers['Content-Type'], 'CONTENT_LENGTH': headers['Content-Length'], 'HTTP_MIME_VERSION': headers['MIME-Version'], } request = make_request(env) response = handler.get_response(request) self.assertEqual(file_content, response.content) self.assertEqual(recorder, [file_content] * 3)
def make_request(env=None, oauth_env=None, missing_oauth_param=None): # Return a minimal WSGIRequest. if oauth_env is None: oauth_env = {} base_env = { "REQUEST_METHOD": "GET", "wsgi.input": wsgi._InputStream(io.BytesIO()), "SERVER_NAME": "server", "SERVER_PORT": 80, "HTTP_AUTHORIZATION": factory.make_oauth_header(missing_param=missing_oauth_param, **oauth_env), } if env is not None: base_env.update(env) request = WSGIRequest(base_env) return request
def gotMessage(self, payload, topic): # noqa message = pickle.loads(payload) now = time.time() deferred_guards = [] for guard, settings in (message.get("guards") or {}).items(): if guard in self._guards and now < self._guards[guard]["expires"]: if set(settings["tokens"]) & set( self._guards[guard]["tokens"]): continue # OK and continue to check the next guard else: return # Forbidden (according to cached guard) environ = deepcopy(self._environ) environ["REQUEST_METHOD"] = "GET" environ["PATH_INFO"] = settings["method"] environ["wsgi.errors"] = _ErrorStream() environ["wsgi.input"] = _InputStream(BytesIO(b"")) # DeferredLock should is used to limit to only ever use single working # thread for guard checks call = Deferred() WS_GUARD_CALL_MUTEX.acquire( ).addCallback(lambda _, d=call: threads.deferToThread( self._publish_module, environ, lambda *args: None, _request_factory=WebSocketRequest, ).addBoth(lambda _: [WS_GUARD_CALL_MUTEX.release(), d.callback(_)])) deferred_guards.append(call) if deferred_guards: dl = DeferredList(deferred_guards) dl.addCallback( lambda result: self.gotMessageFinished(message, result)) else: super(PubSubServerProtocol, self).sendMessage(message["payload"], isBinary=False)
def make_environ(request): if request.prepath: script_name = b"/" + b"/".join(request.prepath) else: script_name = b"" if request.postpath: path_info = b"/" + b"/".join(request.postpath) else: path_info = b"" parts = request.uri.split(b"?", 1) if len(parts) == 1: query_string = b"" else: query_string = parts[1] # All keys and values need to be native strings, i.e. of type str in # *both* Python 2 and Python 3, so says PEP-3333. environ = { "REQUEST_METHOD": _wsgiString(request.method), "REMOTE_ADDR": _wsgiString(request.getClientAddress().host), "SCRIPT_NAME": _wsgiString(script_name), "PATH_INFO": _wsgiString(path_info), "QUERY_STRING": _wsgiString(query_string), "CONTENT_TYPE": _wsgiString(request.getHeader(b"content-type") or ""), "CONTENT_LENGTH": _wsgiString(request.getHeader(b"content-length") or ""), "HTTPS": request.isSecure() and '1' or False, "SERVER_NAME": _wsgiString(request.getRequestHostname()), "SERVER_PORT": _wsgiString(str(request.getHost().port)), "SERVER_PROTOCOL": _wsgiString(request.clientproto), "SERVER_SOFTWARE": "Zope/%s ZServer/%s %s" % (ZOPE_VERSION, ZSERVER_VERSION, version.decode("utf-8")), } # The application object is entirely in control of response headers; # disable the default Content-Type value normally provided by # twisted.web.server.Request. request.defaultContentType = None for name, values in request.requestHeaders.getAllRawHeaders(): name = "HTTP_" + _wsgiString(name).upper().replace("-", "_") # It might be preferable for http.HTTPChannel to clear out # newlines. environ[name] = ",".join(_wsgiString(v) for v in values).replace("\n", " ") environ.update({ "wsgi.version": (1, 0), "wsgi.url_scheme": request.isSecure() and "https" or "http", "wsgi.run_once": False, "wsgi.multithread": True, "wsgi.multiprocess": False, "wsgi.errors": _ErrorStream(), # Attend: request.content was owned by the I/O thread up until # this point. By wrapping it and putting the result into the # environment dictionary, it is effectively being given to # another thread. This means that whatever it is, it has to be # safe to access it from two different threads. The access # *should* all be serialized (first the I/O thread writes to # it, then the WSGI thread reads from it, then the I/O thread # closes it). However, since the request is made available to # arbitrary application code during resource traversal, it's # possible that some other code might decide to use it in the # I/O thread concurrently with its use in the WSGI thread. # More likely than not, this will break. This seems like an # unlikely possibility to me, but if it is to be allowed, # something here needs to change. -exarkun "wsgi.input": _InputStream(request.content), }) return environ