def _processRequest(self): """ Process the request by sending it to the relevant server. @return: the HTTP response. @rtype: L{Response} """ store = self.storeMap[self.server.details()] j = json.loads(self.data) if self.stream is not None: j["stream"] = self.stream j["streamType"] = self.streamType try: if store.conduit.isStreamAction(j): stream = ProducerStream() class StreamProtocol(Protocol): def connectionMade(self): stream.registerProducer(self.transport, False) def dataReceived(self, data): stream.write(data) def connectionLost(self, reason): stream.finish() result = yield store.conduit.processRequestStream( j, StreamProtocol()) try: ct, name = result except ValueError: code = responsecode.BAD_REQUEST else: headers = {"content-type": MimeType.fromString(ct)} headers["content-disposition"] = MimeDisposition( "attachment", params={"filename": name}) returnValue(Response(responsecode.OK, headers, stream)) else: result = yield store.conduit.processRequest(j) code = responsecode.OK except Exception as e: # Send the exception over to the other side result = { "result": "exception", "class": ".".join(( e.__class__.__module__, e.__class__.__name__, )), "details": str(e), } code = responsecode.BAD_REQUEST response = JSONResponse(code, result) returnValue(response)
def createRequest(self): self.stream = ProducerStream(self.length) self.response = Response(self.code, self.inHeaders, self.stream) self.stream.registerProducer(self, True) del self.inHeaders
def http_POST(self, request): """ The server-to-server POST method. """ # Check shared secret if not self.store.directoryService().serversDB().getThisServer( ).checkSharedSecret(request.headers): self.log.error("Invalid shared secret header in cross-pod request") raise HTTPError( StatusResponse(responsecode.FORBIDDEN, "Not authorized to make this request")) # Look for XPOD header xpod = request.headers.getRawHeaders("XPOD") contentType = request.headers.getHeader("content-type") if xpod is not None: # Attachments are sent in the request body with the JSON data in a header. We # decode the header and add the request.stream as an attribute of the JSON object. xpod = xpod[0] try: j = json.loads(base64.b64decode(xpod)) except (TypeError, ValueError) as e: self.log.error("Invalid JSON header in request: {ex}\n{xpod}", ex=e, xpod=xpod) raise HTTPError( StatusResponse( responsecode.BAD_REQUEST, "Invalid JSON header in request: {}\n{}".format( e, xpod))) j["stream"] = request.stream j["streamType"] = contentType else: # Check content first if "{}/{}".format(contentType.mediaType, contentType.mediaSubtype) != "application/json": self.log.error("MIME type {mime} not allowed in request", mime=contentType) raise HTTPError( StatusResponse( responsecode.BAD_REQUEST, "MIME type {} not allowed in request".format( contentType))) body = (yield allDataFromStream(request.stream)) try: j = json.loads(body) except ValueError as e: self.log.error("Invalid JSON data in request: {ex}\n{body}", ex=e, body=body) raise HTTPError( StatusResponse( responsecode.BAD_REQUEST, "Invalid JSON data in request: {}\n{}".format(e, body))) # Log extended item if not hasattr(request, "extendedLogItems"): request.extendedLogItems = {} request.extendedLogItems[ "xpod"] = j["action"] if "action" in j else "unknown" # Look for a streaming action which needs special handling if self.store.conduit.isStreamAction(j): # Get the conduit to process the data stream try: stream = ProducerStream() class StreamProtocol(Protocol): def connectionMade(self): stream.registerProducer(self.transport, False) def dataReceived(self, data): stream.write(data) def connectionLost(self, reason): stream.finish() result = yield self.store.conduit.processRequestStream( j, StreamProtocol()) try: ct, name = result except ValueError: code = responsecode.BAD_REQUEST else: headers = {"content-type": MimeType.fromString(ct)} headers["content-disposition"] = MimeDisposition( "attachment", params={"filename": name}) returnValue(Response(responsecode.OK, headers, stream)) except Exception as e: # Send the exception over to the other side result = { "result": "exception", "class": ".".join(( e.__class__.__module__, e.__class__.__name__, )), "details": str(e), } code = responsecode.BAD_REQUEST else: # Get the conduit to process the data try: result = yield self.store.conduit.processRequest(j) code = responsecode.OK if result[ "result"] == "ok" else responsecode.BAD_REQUEST except Exception as e: # Send the exception over to the other side result = { "result": "exception", "class": ".".join(( e.__class__.__module__, e.__class__.__name__, )), "details": str(e), } code = responsecode.BAD_REQUEST response = JSONResponse(code, result) returnValue(response)