/**
  *
  */
 public function process()
 {
     $this->emit('process:before', [['request' => $this->httpRequest]]);
     // set Content Security Policy and CORS headers
     $this->httpResponse->addHeader('Content-Security-Policy', "default-src *");
     $this->httpResponse->addHeader('X-Content-Security-Policy', "default-src *");
     if ($this->httpRequest->hasHeader('Origin')) {
         // TODO: allow to configure allowed origins
         $this->httpResponse->addHeader('Access-Control-Allow-Origin', "*");
     }
     // FIXME: respond to OPTIONS requests directly and without validation
     if ($this->httpRequest->getMethod() == 'OPTIONS') {
         $this->httpResponse->addHeader('Access-Control-Request-Method', 'GET, POST, OPTIONS');
         $this->httpResponse->addHeader('Access-Control-Allow-Headers', $this->httpRequest->getHeader('Access-Control-Request-Headers'));
         $this->httpResponse->setStatus(204);
         $this->sapi->sendResponse($this->httpResponse);
         return;
     }
     // extract route from request (jmap, auth|.well-known/jmap, upload)
     if ($route = $this->getRouteMatch($this->httpRequest->getPath())) {
         try {
             call_user_func($this->routes[$route], $this->httpRequest, $this->httpResponse);
         } catch (\RuntimeException $e) {
             if ($e instanceof Exception\ProcessorException) {
                 $this->httpResponse->setStatus($e->getStatusCode());
             } else {
                 $this->httpResponse->setStatus(500);
             }
             $this->logger->err(strval($e));
             $this->emit('process:error', [['request' => $this->httpRequest, 'exception' => $e]]);
         }
     } else {
         // TODO: throw invalid route error
         $this->httpResponse->setStatus(404);
     }
     $this->emit('process:after', [['response' => $this->httpResponse]]);
     $this->sapi->sendResponse($this->httpResponse);
 }