public function setUp()
 {
     parent::setUp();
     //setup the general object graph
     Phockito::when($this->mockService->getHost())->return($this->mockServiceHost);
     Phockito::when($this->mockService->getConfiguration())->return($this->mockServiceConfiguration);
 }
예제 #2
0
 /**
  * Checks whether client request contains any odata query options.
  * 
  * @return void
  * 
  * @throws ODataException Throws bad request error if client request 
  *                        includes any odata query option.
  */
 private function _checkForEmptyQueryArguments()
 {
     $serviceHost = $this->service->getHost();
     if (!is_null($serviceHost->getQueryStringItem(ODataConstants::HTTPQUERY_STRING_FILTER)) || !is_null($serviceHost->getQueryStringItem(ODataConstants::HTTPQUERY_STRING_EXPAND)) || !is_null($serviceHost->getQueryStringItem(ODataConstants::HTTPQUERY_STRING_INLINECOUNT)) || !is_null($serviceHost->getQueryStringItem(ODataConstants::HTTPQUERY_STRING_ORDERBY)) || !is_null($serviceHost->getQueryStringItem(ODataConstants::HTTPQUERY_STRING_SELECT)) || !is_null($serviceHost->getQueryStringItem(ODataConstants::HTTPQUERY_STRING_SKIP)) || !is_null($serviceHost->getQueryStringItem(ODataConstants::HTTPQUERY_STRING_SKIPTOKEN)) || !is_null($serviceHost->getQueryStringItem(ODataConstants::HTTPQUERY_STRING_TOP))) {
         throw ODataException::createBadRequestError(Messages::queryProcessorNoQueryOptionsApplicable());
     }
 }
예제 #3
0
 /**
  * Builds the string corresponding to query parameters for top level results 
  * (result set identified by the resource path) to be put in next page link.
  * 
  * @return string|null string representing the query parameters in the URI 
  *                     query parameter format, NULL if there 
  *                     is no query parameters
  *                     required for the next link of top level result set.
  */
 protected function getNextPageLinkQueryParametersForRootResourceSet()
 {
     $queryParameterString = null;
     foreach (array(ODataConstants::HTTPQUERY_STRING_FILTER, ODataConstants::HTTPQUERY_STRING_EXPAND, ODataConstants::HTTPQUERY_STRING_ORDERBY, ODataConstants::HTTPQUERY_STRING_INLINECOUNT, ODataConstants::HTTPQUERY_STRING_SELECT) as $queryOption) {
         $value = $this->service->getHost()->getQueryStringItem($queryOption);
         if (!is_null($value)) {
             if (!is_null($queryParameterString)) {
                 $queryParameterString = $queryParameterString . '&';
             }
             $queryParameterString .= $queryOption . '=' . $value;
         }
     }
     $topCountValue = $this->request->getTopOptionCount();
     if (!is_null($topCountValue)) {
         $remainingCount = $topCountValue - $this->request->getTopCount();
         if (!is_null($queryParameterString)) {
             $queryParameterString .= '&';
         }
         $queryParameterString .= ODataConstants::HTTPQUERY_STRING_TOP . '=' . $remainingCount;
     }
     if (!is_null($queryParameterString)) {
         $queryParameterString .= '&';
     }
     return $queryParameterString;
 }
예제 #4
0
 /**
  * Common function to handle exceptions in the data service.
  * 
  * @param \Exception    $exception    exception
  * @param IService      $service service
  * 
  * @return void
  */
 public static function handleException($exception, IService $service)
 {
     $acceptTypesText = $service->getHost()->getRequestAccept();
     $responseContentType = null;
     try {
         $responseContentType = HttpProcessUtility::selectMimeType($acceptTypesText, array(MimeTypes::MIME_APPLICATION_XML, MimeTypes::MIME_APPLICATION_JSON));
     } catch (HttpHeaderFailure $exception) {
         $exception = new ODataException($exception->getMessage(), $exception->getStatusCode());
     } catch (\Exception $exception) {
         // Never come here
     }
     if (is_null($responseContentType)) {
         $responseContentType = MimeTypes::MIME_APPLICATION_XML;
     }
     if (!$exception instanceof ODataException) {
         $exception = new ODataException($exception->getMessage(), HttpStatus::CODE_INTERNAL_SERVER_ERROR);
     }
     $service->getHost()->setResponseVersion(ODataConstants::DATASERVICEVERSION_1_DOT_0 . ';');
     // At this point all kind of exceptions will be converted
     //to 'ODataException'
     if ($exception->getStatusCode() == HttpStatus::CODE_NOT_MODIFIED) {
         $service->getHost()->setResponseStatusCode(HttpStatus::CODE_NOT_MODIFIED);
     } else {
         $service->getHost()->setResponseStatusCode($exception->getStatusCode());
         $service->getHost()->setResponseContentType($responseContentType);
         $responseBody = null;
         if (strcasecmp($responseContentType, MimeTypes::MIME_APPLICATION_XML) == 0) {
             $responseBody = AtomODataWriter::serializeException($exception, true);
         } else {
             $responseBody = JsonODataV2Writer::serializeException($exception, true);
         }
         $service->getHost()->getOperationContext()->outgoingResponse()->setStream($responseBody);
     }
 }
예제 #5
0
 /**
  * Pushes a segment for the current navigation property being written out.
  * Note: Refer 'ObjectModelSerializerNotes.txt' for more details about
  * 'Segment Stack' and this method.
  * Note: Calls to this method should be balanced with calls to popSegment.
  *
  * @param ResourceProperty &$resourceProperty Current navigation property 
  *                                            being written out
  *
  * @return bool true if a segment was pushed, false otherwise
  *
  * @throws InvalidOperationException If this function invoked with non-navigation
  *                                   property instance.
  */
 private function _pushSegmentForNavigationProperty(ResourceProperty &$resourceProperty)
 {
     if ($resourceProperty->getTypeKind() == ResourceTypeKind::ENTITY) {
         $this->assert(!empty($this->_segmentNames), '!is_empty($this->_segmentNames');
         $currentResourceSetWrapper = $this->_getCurrentResourceSetWrapper();
         $currentResourceType = $currentResourceSetWrapper->getResourceType();
         $currentResourceSetWrapper = $this->service->getProvidersWrapper()->getResourceSetWrapperForNavigationProperty($currentResourceSetWrapper, $currentResourceType, $resourceProperty);
         $this->assert(!is_null($currentResourceSetWrapper), '!null($currentResourceSetWrapper)');
         return $this->_pushSegment($resourceProperty->getName(), $currentResourceSetWrapper);
     } else {
         throw new InvalidOperationException('pushSegmentForNavigationProperty should not be called with non-entity type');
     }
 }
예제 #6
0
 /**
  * Process the request Uri and creates an instance of
  * RequestDescription from the processed uri.
  * 
  * @param IService $service        Reference to the data service instance.
  *
  * @return RequestDescription
  * 
  * @throws ODataException If any exception occurs while processing the segments
  *                        or in case of any version incompatibility.
  */
 public static function process(IService $service)
 {
     $host = $service->getHost();
     $absoluteRequestUri = $host->getAbsoluteRequestUri();
     $absoluteServiceUri = $host->getAbsoluteServiceUri();
     $requestUriSegments = array_slice($absoluteRequestUri->getSegments(), $absoluteServiceUri->getSegmentCount());
     $segments = SegmentParser::parseRequestUriSegments($requestUriSegments, $service->getProvidersWrapper(), true);
     $request = new RequestDescription($segments, $absoluteRequestUri, $service->getConfiguration()->getMaxDataServiceVersion(), $host->getRequestVersion(), $host->getRequestMaxVersion());
     $kind = $request->getTargetKind();
     if ($kind == TargetKind::METADATA() || $kind == TargetKind::BATCH() || $kind == TargetKind::SERVICE_DIRECTORY()) {
         return $request;
     }
     if ($kind == TargetKind::PRIMITIVE_VALUE() || $kind == TargetKind::MEDIA_RESOURCE()) {
         // http://odata/NW.svc/Orders/$count
         // http://odata/NW.svc/Orders(123)/Customer/CustomerID/$value
         // http://odata/NW.svc/Employees(1)/$value
         // http://odata/NW.svc/Employees(1)/ThumbNail_48X48/$value
         $request->setContainerName($segments[count($segments) - 2]->getIdentifier());
     } else {
         $request->setContainerName($request->getIdentifier());
     }
     if ($request->getIdentifier() === ODataConstants::URI_COUNT_SEGMENT) {
         if (!$service->getConfiguration()->getAcceptCountRequests()) {
             throw ODataException::createBadRequestError(Messages::configurationCountNotAccepted());
         }
         $request->queryType = QueryType::COUNT();
         // use of $count requires request DataServiceVersion
         // and MaxDataServiceVersion greater than or equal to 2.0
         $request->raiseResponseVersion(2, 0);
         $request->raiseMinVersionRequirement(2, 0);
     } else {
         if ($request->isNamedStream()) {
             $request->raiseMinVersionRequirement(3, 0);
         } else {
             if ($request->getTargetKind() == TargetKind::RESOURCE()) {
                 if (!$request->isLinkUri()) {
                     $resourceSetWrapper = $request->getTargetResourceSetWrapper();
                     //assert($resourceSetWrapper != null)
                     $hasNamedStream = $resourceSetWrapper->hasNamedStreams($service->getProvidersWrapper());
                     $hasBagProperty = $resourceSetWrapper->hasBagProperty($service->getProvidersWrapper());
                     if ($hasNamedStream || $hasBagProperty) {
                         $request->raiseResponseVersion(3, 0);
                     }
                 }
             } else {
                 if ($request->getTargetKind() == TargetKind::BAG()) {
                     $request->raiseResponseVersion(3, 0);
                 }
             }
         }
     }
     return $request;
 }
예제 #7
0
 /**
  * Gets the response format for the requested resource.
  * 
  * @param RequestDescription $request The request submitted by client and it's execution result.
  * @param UriProcessor $uriProcessor The reference to the UriProcessor.
  * @param IService $service Reference to the service implementation instance
  *
  * @return string the response content-type, a null value means the requested resource
  * is named stream and IDSSP2::getStreamContentType returned null
  * 
  * @throws ODataException, HttpHeaderFailure
  */
 public static function getResponseContentType(RequestDescription $request, UriProcessor $uriProcessor, IService $service)
 {
     // The Accept request-header field specifies media types which are acceptable for the response
     $host = $service->getHost();
     $requestAcceptText = $host->getRequestAccept();
     $requestVersion = $request->getResponseVersion();
     //if the $format header is present it overrides the accepts header
     $format = $host->getQueryStringItem(ODataConstants::HTTPQUERY_STRING_FORMAT);
     if (!is_null($format)) {
         //There's a strange edge case..if application/json is supplied and it's V3
         if ($format == MimeTypes::MIME_APPLICATION_JSON && $requestVersion == Version::v3()) {
             //then it's actual minimalmetadata
             //TODO: should this be done with the header text too?
             $format = MimeTypes::MIME_APPLICATION_JSON_MINIMAL_META;
         }
         $requestAcceptText = ServiceHost::translateFormatToMime($requestVersion, $format);
     }
     //The response format can be dictated by the target resource kind. IE a $value will be different then expected
     //getTargetKind doesn't deal with link resources directly and this can change things
     $targetKind = $request->isLinkUri() ? TargetKind::LINK() : $request->getTargetKind();
     switch ($targetKind) {
         case TargetKind::METADATA():
             return HttpProcessUtility::selectMimeType($requestAcceptText, array(MimeTypes::MIME_APPLICATION_XML));
         case TargetKind::SERVICE_DIRECTORY():
             return HttpProcessUtility::selectMimeType($requestAcceptText, array(MimeTypes::MIME_APPLICATION_XML, MimeTypes::MIME_APPLICATION_ATOMSERVICE, MimeTypes::MIME_APPLICATION_JSON, MimeTypes::MIME_APPLICATION_JSON_FULL_META, MimeTypes::MIME_APPLICATION_JSON_NO_META, MimeTypes::MIME_APPLICATION_JSON_MINIMAL_META, MimeTypes::MIME_APPLICATION_JSON_VERBOSE));
         case TargetKind::PRIMITIVE_VALUE():
             $supportedResponseMimeTypes = array(MimeTypes::MIME_TEXTPLAIN);
             if ($request->getIdentifier() != '$count') {
                 $projectedProperty = $request->getProjectedProperty();
                 self::assert(!is_null($projectedProperty), '!is_null($projectedProperty)');
                 $type = $projectedProperty->getInstanceType();
                 self::assert(!is_null($type) && $type instanceof IType, '!is_null($type) && $type instanceof IType');
                 if ($type instanceof Binary) {
                     $supportedResponseMimeTypes = array(MimeTypes::MIME_APPLICATION_OCTETSTREAM);
                 }
             }
             return HttpProcessUtility::selectMimeType($requestAcceptText, $supportedResponseMimeTypes);
         case TargetKind::PRIMITIVE():
         case TargetKind::COMPLEX_OBJECT():
         case TargetKind::BAG():
         case TargetKind::LINK():
             return HttpProcessUtility::selectMimeType($requestAcceptText, array(MimeTypes::MIME_APPLICATION_XML, MimeTypes::MIME_TEXTXML, MimeTypes::MIME_APPLICATION_JSON, MimeTypes::MIME_APPLICATION_JSON_FULL_META, MimeTypes::MIME_APPLICATION_JSON_NO_META, MimeTypes::MIME_APPLICATION_JSON_MINIMAL_META, MimeTypes::MIME_APPLICATION_JSON_VERBOSE));
         case TargetKind::RESOURCE():
             return HttpProcessUtility::selectMimeType($requestAcceptText, array(MimeTypes::MIME_APPLICATION_ATOM, MimeTypes::MIME_APPLICATION_JSON, MimeTypes::MIME_APPLICATION_JSON_FULL_META, MimeTypes::MIME_APPLICATION_JSON_NO_META, MimeTypes::MIME_APPLICATION_JSON_MINIMAL_META, MimeTypes::MIME_APPLICATION_JSON_VERBOSE));
         case TargetKind::MEDIA_RESOURCE():
             if (!$request->isNamedStream() && !$request->getTargetResourceType()->isMediaLinkEntry()) {
                 throw ODataException::createBadRequestError(Messages::badRequestInvalidUriForMediaResource($host->getAbsoluteRequestUri()->getUrlAsString()));
             }
             $uriProcessor->execute();
             $request->setExecuted();
             // DSSW::getStreamContentType can throw error in 2 cases
             // 1. If the required stream implementation not found
             // 2. If IDSSP::getStreamContentType returns NULL for MLE
             $responseContentType = $service->getStreamProviderWrapper()->getStreamContentType($request->getTargetResult(), $request->getResourceStreamInfo());
             // Note StreamWrapper::getStreamContentType can return NULL if the requested named stream has not
             // yet been uploaded. But for an MLE if IDSSP::getStreamContentType returns NULL then StreamWrapper will throw error
             if (!is_null($responseContentType)) {
                 $responseContentType = HttpProcessUtility::selectMimeType($requestAcceptText, array($responseContentType));
             }
             return $responseContentType;
     }
     //If we got here, we just don't know what it is...
     throw new ODataException(Messages::unsupportedMediaType(), 415);
 }
예제 #8
0
 /**
  * Write in specific format 
  * 
  * @param IService $service
  * @param RequestDescription $request the OData request
  * @param mixed $entityModel OData model instance
  * @param String $responseContentType Content type of the response
  * 
  */
 public static function write(IService $service, RequestDescription $request, $entityModel, $responseContentType)
 {
     $responseBody = null;
     $dataServiceVersion = $request->getResponseVersion();
     $targetKind = $request->getTargetKind();
     if ($targetKind == TargetKind::METADATA()) {
         // /$metadata
         $writer = new MetadataWriter($service->getProvidersWrapper());
         $responseBody = $writer->writeMetadata();
         $dataServiceVersion = $writer->getDataServiceVersion();
     } else {
         if ($targetKind == TargetKind::PRIMITIVE_VALUE() && $responseContentType != MimeTypes::MIME_APPLICATION_OCTETSTREAM) {
             //This second part is to exclude binary properties
             // /Customer('ALFKI')/CompanyName/$value
             // /Customers/$count
             $responseBody = utf8_encode($request->getTargetResult());
         } else {
             if ($responseContentType == MimeTypes::MIME_APPLICATION_OCTETSTREAM || $targetKind == TargetKind::MEDIA_RESOURCE()) {
                 // Binary property or media resource
                 if ($request->getTargetKind() == TargetKind::MEDIA_RESOURCE()) {
                     $result = $request->getTargetResult();
                     $streamInfo = $request->getResourceStreamInfo();
                     $provider = $service->getStreamProviderWrapper();
                     $eTag = $provider->getStreamETag($result, $streamInfo);
                     $service->getHost()->setResponseETag($eTag);
                     $responseBody = $provider->getReadStream($result, $streamInfo);
                 } else {
                     $responseBody = $request->getTargetResult();
                 }
                 if (is_null($responseContentType)) {
                     $responseContentType = MimeTypes::MIME_APPLICATION_OCTETSTREAM;
                 }
             } else {
                 $writer = $service->getODataWriterRegistry()->getWriter($request->getResponseVersion(), $responseContentType);
                 //TODO: move ot Messages
                 if (is_null($writer)) {
                     throw new \Exception("no writer can handle the request");
                 }
                 if (is_null($entityModel)) {
                     //TODO: this seems like a weird way to know that the request is for a service document..i'd think we know this some other way
                     $responseBody = $writer->writeServiceDocument($service->getProvidersWrapper())->getOutput();
                 } else {
                     $responseBody = $writer->write($entityModel)->getOutput();
                 }
             }
         }
     }
     $service->getHost()->setResponseStatusCode(HttpStatus::CODE_OK);
     $service->getHost()->setResponseContentType($responseContentType);
     $service->getHost()->setResponseVersion($dataServiceVersion->toString() . ';');
     $service->getHost()->setResponseCacheControl(ODataConstants::HTTPRESPONSE_HEADER_CACHECONTROL_NOCACHE);
     $service->getHost()->getOperationContext()->outgoingResponse()->setStream($responseBody);
 }
 public function setUp()
 {
     parent::setUp();
     Phockito::when($this->mockService->getHost())->return($this->mockHost);
 }
예제 #10
0
 /**
  * Check whether implementor modified content type or etag header
  * if so throw InvalidOperationException.
  * 
  * @param string $methodName NAme of the method
  * 
  * @return void
  * 
  * @throws InvalidOperationException
  */
 private function _verifyContentTypeOrETagModified($methodName)
 {
     if ($this->_responseContentType !== $this->_service->getHost()->getResponseContentType() || $this->_responseETag !== $this->_service->getHost()->getResponseETag()) {
         throw new InvalidOperationException(Messages::streamProviderWrapperMustNotSetContentTypeAndEtag($methodName));
     }
 }