/** * HTTP REPORT method implementation * * Although the REPORT method is not part of the standard WebDAV spec (it's from rfc3253) * It's used in a lot of extensions, so it made sense to implement it into the core. * * @param RequestInterface $request * @param ResponseInterface $response * @return bool */ function httpReport(RequestInterface $request, ResponseInterface $response) { $path = $request->getPath(); $result = $this->server->xml->parse($request->getBody(), $request->getUrl(), $rootElementName); if ($this->server->emit('report', [$rootElementName, $result, $path])) { // If emit returned true, it means the report was not supported throw new Exception\ReportNotSupported(); } // Sending back false will interupt the event chain and tell the server // we've handled this method. return false; }
/** * Turns a RequestInterface object into an array with settings that can be * fed to curl_setopt * * @param RequestInterface $request * @return array */ protected function createCurlSettingsArray(RequestInterface $request) { $settings = $this->curlSettings; switch ($request->getMethod()) { case 'HEAD': $settings[CURLOPT_NOBODY] = true; $settings[CURLOPT_CUSTOMREQUEST] = 'HEAD'; $settings[CURLOPT_POSTFIELDS] = ''; $settings[CURLOPT_PUT] = false; break; case 'GET': $settings[CURLOPT_CUSTOMREQUEST] = 'GET'; $settings[CURLOPT_POSTFIELDS] = ''; $settings[CURLOPT_PUT] = false; break; default: $body = $request->getBody(); if (is_resource($body)) { // This needs to be set to PUT, regardless of the actual // method used. Without it, INFILE will be ignored for some // reason. $settings[CURLOPT_PUT] = true; $settings[CURLOPT_INFILE] = $request->getBody(); } else { // For security we cast this to a string. If somehow an array could // be passed here, it would be possible for an attacker to use @ to // post local files. $settings[CURLOPT_POSTFIELDS] = (string) $body; } $settings[CURLOPT_CUSTOMREQUEST] = $request->getMethod(); break; } $nHeaders = []; foreach ($request->getHeaders() as $key => $values) { foreach ($values as $value) { $nHeaders[] = $key . ': ' . $value; } } $settings[CURLOPT_HTTPHEADER] = $nHeaders; $settings[CURLOPT_URL] = $request->getUrl(); // FIXME: CURLOPT_PROTOCOLS is currently unsupported by HHVM if (defined('CURLOPT_PROTOCOLS')) { $settings[CURLOPT_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS; } // FIXME: CURLOPT_REDIR_PROTOCOLS is currently unsupported by HHVM if (defined('CURLOPT_REDIR_PROTOCOLS')) { $settings[CURLOPT_REDIR_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS; } return $settings; }
/** * This method handles POST requests to the schedule-outbox. * * Currently, two types of requests are support: * * FREEBUSY requests from RFC 6638 * * Simple iTIP messages from draft-desruisseaux-caldav-sched-04 * * The latter is from an expired early draft of the CalDAV scheduling * extensions, but iCal depends on a feature from that spec, so we * implement it. * * @param IOutbox $outboxNode * @param RequestInterface $request * @param ResponseInterface $response * @return void */ function outboxRequest(IOutbox $outboxNode, RequestInterface $request, ResponseInterface $response) { $outboxPath = $request->getPath(); // Parsing the request body try { $vObject = VObject\Reader::read($request->getBody()); } catch (VObject\ParseException $e) { throw new BadRequest('The request body must be a valid iCalendar object. Parse error: ' . $e->getMessage()); } // The incoming iCalendar object must have a METHOD property, and a // component. The combination of both determines what type of request // this is. $componentType = null; foreach ($vObject->getComponents() as $component) { if ($component->name !== 'VTIMEZONE') { $componentType = $component->name; break; } } if (is_null($componentType)) { throw new BadRequest('We expected at least one VTODO, VJOURNAL, VFREEBUSY or VEVENT component'); } // Validating the METHOD $method = strtoupper((string) $vObject->METHOD); if (!$method) { throw new BadRequest('A METHOD property must be specified in iTIP messages'); } // So we support one type of request: // // REQUEST with a VFREEBUSY component $acl = $this->server->getPlugin('acl'); if ($componentType === 'VFREEBUSY' && $method === 'REQUEST') { $acl && $acl->checkPrivileges($outboxPath, '{' . self::NS_CALDAV . '}schedule-query-freebusy'); $this->handleFreeBusyRequest($outboxNode, $vObject, $request, $response); } else { throw new NotImplemented('We only support VFREEBUSY (REQUEST) on this endpoint'); } }
/** * We intercept this to handle POST requests on shared resources * * @param RequestInterface $request * @param ResponseInterface $response * @return null|bool */ function httpPost(RequestInterface $request, ResponseInterface $response) { $path = $request->getPath(); $contentType = $request->getHeader('Content-Type'); // We're only interested in the davsharing content type. if (strpos($contentType, 'application/davsharing+xml') === false) { return; } $message = $this->server->xml->parse($request->getBody(), $request->getUrl(), $documentType); switch ($documentType) { case '{DAV:}share-resource': $this->shareResource($path, $message->sharees); $response->setStatus(200); // Adding this because sending a response body may cause issues, // and I wanted some type of indicator the response was handled. $response->setHeader('X-Sabre-Status', 'everything-went-well'); // Breaking the event chain return false; default: throw new BadRequest('Unexpected document type: ' . $documentType . ' for this Content-Type'); } }