def handle_rpc(self, request): initial_ctx = TwistedHttpMethodContext(self.http_transport, request, self.http_transport.app.out_protocol.mime_type) if _has_fd(request.content): f = request.content # it's best to avoid empty mappings. if fstat(f.fileno()).st_size == 0: initial_ctx.in_string = [''] else: initial_ctx.in_string = [mmap(f.fileno(), 0)] else: request.content.seek(0) initial_ctx.in_string = [request.content.read()] initial_ctx.transport.file_info = _get_file_info(initial_ctx) contexts = self.http_transport.generate_contexts(initial_ctx) p_ctx, others = contexts[0], contexts[1:] p_ctx.active = True p_ctx.out_stream = request # TODO: Rate limiting p_ctx.active = True if p_ctx.in_error: return self.handle_rpc_error(p_ctx, others, p_ctx.in_error, request) else: self.http_transport.get_in_object(p_ctx) if p_ctx.in_error: return self.handle_rpc_error(p_ctx, others, p_ctx.in_error, request) self.http_transport.get_out_object(p_ctx) if p_ctx.out_error: return self.handle_rpc_error(p_ctx, others, p_ctx.out_error, request) ret = p_ctx.out_object[0] retval = NOT_DONE_YET if isinstance(ret, Deferred): ret.addCallback(_cb_deferred, request, p_ctx, others, resource=self) ret.addErrback(_eb_deferred, request, p_ctx, others, resource=self) elif isinstance(ret, PushBase): self.http_transport.init_root_push(ret, p_ctx, others) else: try: retval = _cb_deferred(p_ctx.out_object, request, p_ctx, others, self, cb=False) except Exception as e: logger_server.exception(e) _eb_deferred(Failure(), request, p_ctx, others, resource=self) return retval
def _eb_deferred(ret, request, p_ctx, others, resource): app = p_ctx.app # DRY this with what's in Application.process_request if issubclass(ret.type, Redirect): try: ret.value.do_redirect() # Now that the processing is switched to the outgoing message, # point ctx.protocol to ctx.out_protocol p_ctx.protocol = p_ctx.outprot_ctx _cb_deferred(None, request, p_ctx, others, resource, cb=False) # fire events app.event_manager.fire_event('method_redirect', p_ctx) if p_ctx.service_class is not None: p_ctx.service_class.event_manager.fire_event( 'method_redirect', p_ctx) except Exception as e: logger_server.exception(e) p_ctx.out_error = Fault('Server', get_fault_string_from_exception(e)) # fire events app.event_manager.fire_event('method_redirect_exception', p_ctx) if p_ctx.service_class is not None: p_ctx.service_class.event_manager.fire_event( 'method_redirect_exception', p_ctx) elif issubclass(ret.type, Fault): p_ctx.out_error = ret.value ret = resource.handle_rpc_error(p_ctx, others, p_ctx.out_error, request) # fire events app.event_manager.fire_event('method_exception_object', p_ctx) if p_ctx.service_class is not None: p_ctx.service_class.event_manager.fire_event( 'method_exception_object', p_ctx) request.write(ret) else: p_ctx.out_error = ret.value ret.printTraceback() p_ctx.out_error = InternalError(ret.value) # fire events app.event_manager.fire_event('method_exception_object', p_ctx) if p_ctx.service_class is not None: p_ctx.service_class.event_manager.fire_event( 'method_exception_object', p_ctx) request.finish()
def _eb_deferred(ret, request, p_ctx, others, resource): # DRY this with what's in Application.process_request if ret.check(Redirect): try: ret.value.do_redirect() # Now that the processing is switched to the outgoing message, # point ctx.protocol to ctx.out_protocol p_ctx.protocol = p_ctx.outprot_ctx _cb_deferred(None, request, p_ctx, others, resource, cb=False) p_ctx.fire_event('method_redirect') except Exception as e: logger_server.exception(e) p_ctx.out_error = Fault('Server', get_fault_string_from_exception(e)) p_ctx.fire_event('method_redirect_exception') elif ret.check(Fault): p_ctx.out_error = ret.value ret = resource.handle_rpc_error(p_ctx, others, p_ctx.out_error, request) p_ctx.fire_event('method_exception_object') request.write(ret) else: p_ctx.out_error = InternalError(ret.value) logger.error(ret.getTraceback()) ret = resource.handle_rpc_error(p_ctx, others, p_ctx.out_error, request) p_ctx.fire_event('method_exception_object') request.write(ret) request.finish()
def _cb_deferred(ret, request, p_ctx, others, resource, cb=True): ### set response headers resp_code = p_ctx.transport.resp_code # If user code set its own response code, don't touch it. if resp_code is None: resp_code = HTTP_200 request.setResponseCode(int(resp_code[:3])) _set_response_headers(request, p_ctx.transport.resp_headers) ### normalize response data om = p_ctx.descriptor.out_message single_class = None if cb: if p_ctx.descriptor.is_out_bare(): p_ctx.out_object = [ret] elif (not issubclass(om, ComplexModelBase)) or len(om._type_info) <= 1: p_ctx.out_object = [ret] if len(om._type_info) == 1: single_class, = om._type_info.values() else: p_ctx.out_object = ret else: p_ctx.out_object = ret ### start response retval = NOT_DONE_YET if isinstance(ret, PushBase): resource.http_transport.init_root_push(ret, p_ctx, others) elif ((isclass(om) and issubclass(om, File)) or (isclass(single_class) and issubclass(single_class, File))) and \ isinstance(p_ctx.out_protocol, HttpRpc) and \ getattr(ret, 'abspath', None) is not None: file = static.File(ret.abspath, defaultType=str(ret.type) or 'application/octet-stream') retval = _render_file(file, request) if retval != NOT_DONE_YET and cb: request.write(retval) request.finish() p_ctx.close() else: def _close_only_context(ret): p_ctx.close() request.notifyFinish() \ .addCallback(_close_only_context) \ .addErrback(_eb_request_finished, request, p_ctx) \ .addErrback(log_and_let_go, logger) else: ret = resource.http_transport.get_out_string(p_ctx) if not isinstance(ret, Deferred): producer = Producer(p_ctx.out_string, request) producer.deferred \ .addCallback(_cb_request_finished, request, p_ctx) \ .addErrback(_eb_request_finished, request, p_ctx) \ .addErrback(log_and_let_go, logger) try: request.registerProducer(producer, False) except Exception as e: logger_server.exception(e) try: _eb_deferred(Failure(), request, p_ctx, others, resource) except Exception as e: logger_server.exception(e) raise else: def _cb(ret): if isinstance(ret, Deferred): return ret \ .addCallback(_cb) \ .addErrback(_eb_request_finished, request, p_ctx) \ .addErrback(log_and_let_go, logger) else: return _cb_request_finished(ret, request, p_ctx) ret \ .addCallback(_cb) \ .addErrback(_eb_request_finished, request, p_ctx) \ .addErrback(log_and_let_go, logger) process_contexts(resource.http_transport, others, p_ctx) return retval
def _cb_deferred(ret, request, p_ctx, others, resource, cb=True): ### set response headers resp_code = p_ctx.transport.resp_code # If user code set its own response code, don't touch it. if resp_code is None: resp_code = HTTP_200 request.setResponseCode(int(resp_code[:3])) _set_response_headers(request, p_ctx.transport.resp_headers) ### normalize response data om = p_ctx.descriptor.out_message single_class = None if cb: if p_ctx.descriptor.is_out_bare(): p_ctx.out_object = [ret] elif (not issubclass(om, ComplexModelBase)) or len(om._type_info) <= 1: p_ctx.out_object = [ret] if len(om._type_info) == 1: single_class, = om._type_info.values() else: p_ctx.out_object = ret else: p_ctx.out_object = ret ### start response retval = NOT_DONE_YET if isinstance(ret, PushBase): resource.http_transport.init_root_push(ret, p_ctx, others) elif ((isclass(om) and issubclass(om, File)) or (isclass(single_class) and issubclass(single_class, File))) and \ isinstance(p_ctx.out_protocol, HttpRpc) and \ getattr(ret, 'abspath', None) is not None: file = static.File(ret.abspath, defaultType=str(ret.type) or 'application/octet-stream') retval = _render_file(file, request) if retval != NOT_DONE_YET and cb: request.write(retval) request.finish() p_ctx.close() else: def _close_only_context(ret): p_ctx.close() request.notifyFinish().addCallback(_close_only_context) request.notifyFinish().addErrback(_eb_request_finished, request, p_ctx) else: ret = resource.http_transport.get_out_string(p_ctx) if not isinstance(ret, Deferred): producer = Producer(p_ctx.out_string, request) producer.deferred.addCallback(_cb_request_finished, request, p_ctx) producer.deferred.addErrback(_eb_request_finished, request, p_ctx) try: request.registerProducer(producer, False) except Exception as e: logger_server.exception(e) _eb_deferred(Failure(), request, p_ctx, others, resource) else: def _cb(ret): if isinstance(ret, Deferred): return ret \ .addCallback(_cb) \ .addErrback(_eb_request_finished, request, p_ctx) else: return _cb_request_finished(ret, request, p_ctx) ret \ .addCallback(_cb) \ .addErrback(_eb_request_finished, request, p_ctx) process_contexts(resource.http_transport, others, p_ctx) return retval