def normal_dispatch(app, context, data=None, loop=None): """ Request handler app dispatcher :param app: request handler app :type app: types.Callable :param context: request context :type context: request.RequestContext :param data: request body :type data: io.BufferedIOBase :param loop: asyncio event loop :type loop: asyncio.AbstractEventLoop :return: raw response :rtype: response.RawResponse """ try: rs = app(context, data=data, loop=loop) if isinstance(rs, response.RawResponse): return rs elif isinstance(rs, types.CoroutineType): return loop.run_until_complete(rs) elif isinstance(rs, str): return response.RawResponse(context.version, 200, 'OK', {}, rs) elif isinstance(rs, bytes): return response.RawResponse( context.version, 200, 'OK', {'content-type': 'application/octet-stream'}, rs.decode("utf8")) else: return response.RawResponse(context.version, 200, 'OK', {'content-type': 'application/json'}, json.dumps(rs)) except errors.DispatchException as e: return e.response() except Exception as e: return response.RawResponse(context.version, 500, 'ERROR', {}, str(e))
def run(app, loop=None): """ Request handler app dispatcher entry point :param app: request handler app :type app: types.Callable :param loop: asyncio event loop :type loop: asyncio.AbstractEventLoop :return: None """ if not os.isatty(sys.stdin.fileno()): with os.fdopen(sys.stdin.fileno(), 'rb') as stdin: with os.fdopen(sys.stdout.fileno(), 'wb') as stdout: rq = request.RawRequest(stdin) while True: try: context, data = rq.parse_raw_request() rs = normal_dispatch(app, context, data=data, loop=loop) rs.dump(stdout) except EOFError: # The Fn platform has closed stdin; there's no way to # get additional work. return except errors.DispatchException as ex: # If the user's raised an error containing an explicit # response, use that ex.response().dump(stdout) except Exception as ex: traceback.print_exc(file=sys.stderr) response.RawResponse((1, 1), 500, "Internal Server Error", {}, str(ex)).dump(stdout)
def data_received(self, data): print('received: {!r}'.format(data), file=sys.stderr, flush=True) data = data.decode() req = request.RawRequest(data) (method, url, dict_params, headers, http_version, req_data) = req.parse_raw_request() rs = response.RawResponse(http_version, 200, "OK", response_data=req_data) print(rs.dump(), file=sys.stdout, flush=True) super(MyProtocol, self).data_received(data)
async def app(context, **kwargs): """ This is just an echo function :param context: request context :type context: hotfn.http.request.RequestContext :param kwargs: contains request body by `data` key, in case of coroutine contains event loop by `loop` key :type kwargs: dict :return: echo of request body :rtype: object """ headers = { "Content-Type": "plain/text", } return response.RawResponse(context.version, 200, "OK", http_headers=headers, response_data="OK")
def response(self): return http_response.RawResponse( (1, 1), self.status, 'ERROR', {}, self.message)