Permalink
Browse files

Improving support of inspire download service within WCS 2.0.

Now using msOWSPrintInspireCommonExtendedCapabilities.
Added msOWSLanguageNegotiation function to negotiate the response language.
  • Loading branch information...
constantinius committed Mar 13, 2018
1 parent ab661e2 commit 459d5a8b93dfbd5dd272f37aed8e8635373178d6
Showing with 178 additions and 62 deletions.
  1. +40 −1 mapows.c
  2. +3 −1 mapows.h
  3. +1 −0 mapwcs.h
  4. +134 −60 mapwcs20.c
@@ -1302,6 +1302,45 @@ char *msOWSGetLanguageFromList(mapObj *map, const char *namespaces, const char *
return language;
}
/* msOWSLanguageNegotiation
**
** Returns a language according to the accepted languages requested by the client
**
** Returns a malloced char* which must be freed by the caller, or NULL
*/
char *msOWSLanguageNegotiation(mapObj *map, const char *namespaces, char **accept_languages, int num_accept_languages)
{
int num_languages = 0;
char **languages = NULL;
char *result_language = NULL;
languages = msOWSGetLanguageList(map, namespaces, &num_languages);
if (languages && num_languages > 0) {
for (int i = 0; i < num_accept_languages; ++i) {
const char *accept_language = accept_languages[0];
/* '*' means any language */
if (EQUAL(accept_language, "*")) {
result_language = msStrdup(languages[0]);
break;
} else if (msStringInArray(accept_language, languages, num_languages)) {
result_language = msStrdup(accept_language);
break;
}
}
if (result_language == NULL) {
result_language = msStrdup(languages[0]);
}
}
msFreeCharArray(languages, num_languages);
return result_language;
}
/* msOWSPrintInspireCommonExtendedCapabilities
**
** Output INSPIRE common extended capabilities items to stream
@@ -1385,7 +1424,7 @@ int msOWSPrintInspireCommonMetadata(FILE *stream, mapObj *map, const char *names
msOWSPrintEncodeMetadata(stream, &(map->web.metadata), namespaces, "inspire_mpoc_email", OWS_WARN, " <inspire_common:EmailAddress>%s</inspire_common:EmailAddress>\n", "");
msIO_fprintf(stream, " </inspire_common:MetadataPointOfContact>\n");
msOWSPrintEncodeMetadata(stream, &(map->web.metadata), namespaces, "inspire_metadatadate", OWS_WARN, " <inspire_common:MetadataDate>%s</inspire_common:MetadataDate>\n", "");
if( service == OWS_WFS )
if( service == OWS_WFS || service == OWS_WCS )
msIO_fprintf(stream," <inspire_common:SpatialDataServiceType>download</inspire_common:SpatialDataServiceType>\n");
else
msIO_fprintf(stream," <inspire_common:SpatialDataServiceType>view</inspire_common:SpatialDataServiceType>\n");
@@ -189,6 +189,7 @@ MS_DLL_EXPORT const char *msOWSGetInspireSchemasLocation(mapObj *map);
MS_DLL_EXPORT const char *msOWSGetLanguage(mapObj *map, const char *context);
MS_DLL_EXPORT char **msOWSGetLanguageList(mapObj *map, const char *namespaces, int *numitems);
MS_DLL_EXPORT char *msOWSGetLanguageFromList(mapObj *map, const char *namespaces, const char *requested_language);
MS_DLL_EXPORT char *msOWSLanguageNegotiation(mapObj *map, const char *namespaces, char **accept_languages, int num_accept_languages);
/* OWS_NOERR and OWS_WARN passed as action_if_not_found to printMetadata() */
@@ -200,7 +201,8 @@ MS_DLL_EXPORT char *msOWSGetLanguageFromList(mapObj *map, const char *namespaces
typedef enum
{
OWS_WMS = 1,
OWS_WFS = 2
OWS_WFS = 2,
OWS_WCS = 3
} OWSServiceType;
MS_DLL_EXPORT int msOWSPrintInspireCommonExtendedCapabilities(FILE *stream, mapObj *map, const char *namespaces,
@@ -176,6 +176,7 @@ typedef struct {
char *request; /* GetCapabilities|DescribeCoverage|GetCoverage */
char *service; /* MUST be WCS */
char **accept_versions; /* NULL terminated list of Accepted versions */
char **accept_languages; /* NULL terminated list of Accepted versions */
char **sections; /* NULL terminated list of GetCapabilities sections */
char *updatesequence; /* GetCapabilities updatesequence */
char **ids; /* NULL terminated list of coverages (in the case of a GetCoverage there will only be 1) */
@@ -57,6 +57,37 @@
/************************************************************************/
/* msXMLStripIndentation */
/************************************************************************/
static void msXMLStripIndentation(char* ptr)
{
/* Remove spaces between > and < to get properly indented result */
char* afterLastClosingBracket = NULL;
if( *ptr == ' ' )
afterLastClosingBracket = ptr;
while( *ptr != '\0' )
{
if( *ptr == '<' && afterLastClosingBracket != NULL )
{
memmove(afterLastClosingBracket, ptr, strlen(ptr) + 1);
ptr = afterLastClosingBracket;
}
else if( *ptr == '>' )
{
afterLastClosingBracket = ptr + 1;
}
else if( *ptr != ' ' && *ptr != '\n' )
afterLastClosingBracket = NULL;
ptr ++;
}
}
/************************************************************************/
/* msStringParseInteger() */
/* */
@@ -275,6 +306,7 @@ wcs20ParamsObjPtr msWCSCreateParamsObj20()
params->request = NULL;
params->service = NULL;
params->accept_versions = NULL;
params->accept_languages = NULL;
params->sections = NULL;
params->updatesequence = NULL;
params->ids = NULL;
@@ -317,6 +349,7 @@ void msWCSFreeParamsObj20(wcs20ParamsObjPtr params)
msFree(params->request);
msFree(params->service);
CSLDestroy(params->accept_versions);
CSLDestroy(params->accept_languages);
CSLDestroy(params->sections);
msFree(params->updatesequence);
CSLDestroy(params->ids);
@@ -785,7 +818,7 @@ static int msWCSParseRequest20_XMLGetCapabilities(
/* Maybe not necessary, since only format is xml. */
/* At least ignore it, to not generate an error. */
} else if(EQUAL((char *)child->name, "AcceptLanguages")) {
/* ignore */
params->accept_languages = CSLAddString(params->accept_languages, content);
} else {
XML_UNKNOWN_NODE_ERROR(child);
}
@@ -1467,7 +1500,10 @@ int msWCSParseRequest20(mapObj *map,
} else if (EQUAL(key, "ACCEPTFORMATS")) {
/* ignore */
} else if (EQUAL(key, "ACCEPTLANGUAGES")) {
/* ignore */
if (params->accept_languages != NULL) {
CSLDestroy(params->accept_languages);
}
params->accept_languages = CSLTokenizeString2(value, ",", 0);
} else if (EQUAL(key, "COVERAGEID")) {
if (params->ids != NULL) {
msSetError(MS_WCSERR, "Parameter 'CoverageID' is already set. "
@@ -3198,6 +3234,55 @@ static int msWCSGetCapabilities20_CoverageSummary(
return MS_SUCCESS;
}
/************************************************************************/
/* msWCSAddInspireDSID20 */
/************************************************************************/
static void msWCSAddInspireDSID20(mapObj *map,
xmlNsPtr psNsInspireDls,
xmlNsPtr psNsInspireCommon,
xmlNodePtr pDlsExtendedCapabilities)
{
const char* dsid_code = msOWSLookupMetadata(&(map->web.metadata), "CO", "inspire_dsid_code");
const char* dsid_ns = msOWSLookupMetadata(&(map->web.metadata), "CO", "inspire_dsid_ns");
if( dsid_code == NULL )
{
xmlAddChild(pDlsExtendedCapabilities, xmlNewComment(BAD_CAST "WARNING: Required metadata \"inspire_dsid_code\" missing"));
}
else
{
int ntokensCode = 0, ntokensNS = 0;
char** tokensCode;
char** tokensNS = NULL;
int i;
tokensCode = msStringSplit(dsid_code, ',', &ntokensCode);
if( dsid_ns != NULL )
tokensNS = msStringSplitComplex( dsid_ns, ",", &ntokensNS, MS_ALLOWEMPTYTOKENS);
if( ntokensNS > 0 && ntokensNS != ntokensCode )
{
xmlAddChild(pDlsExtendedCapabilities,
xmlNewComment(BAD_CAST "WARNING: \"inspire_dsid_code\" and \"inspire_dsid_ns\" have not the same number of elements. Ignoring inspire_dsid_ns"));
msFreeCharArray(tokensNS, ntokensNS);
tokensNS = NULL;
ntokensNS = 0;
}
for(i = 0; i<ntokensCode; i++ )
{
xmlNodePtr pSDSI = xmlNewNode(psNsInspireDls, BAD_CAST "SpatialDataSetIdentifier");
xmlAddChild(pDlsExtendedCapabilities, pSDSI);
xmlNewTextChild(pSDSI, psNsInspireCommon, BAD_CAST "Code", BAD_CAST tokensCode[i]);
if( ntokensNS > 0 && tokensNS[i][0] != '\0' )
xmlNewTextChild(pSDSI, psNsInspireCommon, BAD_CAST "Namespace", BAD_CAST tokensNS[i]);
}
msFreeCharArray(tokensCode, ntokensCode);
if( ntokensNS > 0 )
msFreeCharArray(tokensNS, ntokensNS);
}
}
/************************************************************************/
/* msWCSGetCapabilities20() */
/* */
@@ -3224,6 +3309,8 @@ int msWCSGetCapabilities20(mapObj *map, cgiRequestObj *req,
const char *inspire_capabilities = msOWSLookupMetadata(&(map->web.metadata), "CO", "inspire_capabilities");
char *validated_language = msOWSLanguageNegotiation(map, "CO", params->accept_languages, CSLCount(params->accept_languages));
/* -------------------------------------------------------------------- */
/* Create document. */
/* -------------------------------------------------------------------- */
@@ -3278,14 +3365,14 @@ int msWCSGetCapabilities20(mapObj *map, cgiRequestObj *req,
/* -------------------------------------------------------------------- */
if ( MS_WCS_20_CAPABILITIES_INCLUDE_SECTION(params, "ServiceIdentification") ) {
psNode = xmlAddChild(psRootNode, msOWSCommonServiceIdentification(
psOwsNs, map, "OGC WCS", "2.0.1,1.1.1,1.0.0", "CO", NULL));
psOwsNs, map, "OGC WCS", "2.0.1,1.1.1,1.0.0", "CO", validated_language));
msWCSGetCapabilities20_CreateProfiles(map, psNode, psOwsNs);
}
/* Service Provider */
if ( MS_WCS_20_CAPABILITIES_INCLUDE_SECTION(params, "ServiceProvider") ) {
xmlAddChild(psRootNode,
msOWSCommonServiceProvider(psOwsNs, psXLinkNs, map, "CO", NULL));
msOWSCommonServiceProvider(psOwsNs, psXLinkNs, map, "CO", validated_language));
}
/* -------------------------------------------------------------------- */
@@ -3348,70 +3435,56 @@ int msWCSGetCapabilities20(mapObj *map, cgiRequestObj *req,
/* -------------------------------------------------------------------- */
if (inspire_capabilities) {
msIOContext* old_context;
msIOContext* new_context;
msIOBuffer* buffer;
xmlNodePtr pRoot;
xmlNodePtr pOWSExtendedCapabilities;
xmlNodePtr pDlsExtendedCapabilities;
xmlNodePtr pChild;
xmlDocPtr pInspireTmpDoc = NULL;
xmlNsPtr psInspireCommonNs = xmlSearchNs( psDoc, psRootNode, BAD_CAST MS_INSPIRE_COMMON_NAMESPACE_PREFIX );
xmlNsPtr psIDLNs = xmlSearchNs( psDoc, psRootNode, BAD_CAST MS_INSPIRE_DLS_NAMESPACE_PREFIX );
xmlNodePtr psExtendedCapabilitiesNode = xmlAddChild(
xmlAddChild(
psOperationsNode,
xmlAddChild(psOperationsNode, xmlNewNode(psOwsNs, BAD_CAST "ExtendedCapabilities"))
),
xmlNewNode(psInspireCommonNs, BAD_CAST "ExtendedCapabilities")
);
/* ------------------------------------------------------------------ */
/* Scenario 1: URL reference to inspire docs */
/* ------------------------------------------------------------------ */
if (EQUAL(inspire_capabilities, "url")) {
const char *href = msOWSLookupMetadata(&(map->web.metadata), "CO", "inspire_metadataurl_href");
const char *format = msOWSLookupMetadata(&(map->web.metadata), "CO", "inspire_metadataurl_format");
xmlNodePtr psMetadataUrl = xmlAddChild(
psExtendedCapabilitiesNode,
xmlNewNode(psInspireCommonNs, BAD_CAST "MetadataUrl")
);
if (href) {
xmlNodePtr psUrlNode = xmlAddChild(
psMetadataUrl,
xmlNewNode(psInspireCommonNs, BAD_CAST "URL")
);
xmlNodeSetContent(psUrlNode, BAD_CAST href);
} else {
xmlAddChild(
psMetadataUrl,
xmlNewComment(BAD_CAST "Missing 'inspire_metadataurl_href'.")
);
}
xmlNsPtr psInspireDlsNs = xmlSearchNs( psDoc, psRootNode, BAD_CAST MS_INSPIRE_DLS_NAMESPACE_PREFIX );
if (format) {
xmlNodePtr psUrlNode = xmlAddChild(
psMetadataUrl,
xmlNewNode(psInspireCommonNs, BAD_CAST "MediaType")
);
xmlNodeSetContent(psUrlNode, BAD_CAST format);
} else {
xmlAddChild(
psMetadataUrl,
xmlNewComment(BAD_CAST "Missing 'inspire_metadataurl_format'.")
);
}
}
/* ------------------------------------------------------------------ */
/* Scenario 2: Directly embedded metadata */
/* ------------------------------------------------------------------ */
old_context = msIO_pushStdoutToBufferAndGetOldContext();
msOWSPrintInspireCommonExtendedCapabilities(stdout, map, "CO", OWS_WARN,
"foo",
"xmlns:" MS_INSPIRE_COMMON_NAMESPACE_PREFIX "=\"" MS_INSPIRE_COMMON_NAMESPACE_URI "\" "
"xmlns:" MS_INSPIRE_DLS_NAMESPACE_PREFIX "=\"" MS_INSPIRE_DLS_NAMESPACE_URI "\" "
"xmlns:xsi=\"" MS_OWSCOMMON_W3C_XSI_NAMESPACE_URI "\"", validated_language, OWS_WCS);
else if (EQUAL(inspire_capabilities, "embed")) {
new_context = msIO_getHandler(stdout);
buffer = (msIOBuffer *) new_context->cbData;
}
/* Remove spaces between > and < to get properly indented result */
msXMLStripIndentation( (char*) buffer->data );
else {
xmlAddChild(
psExtendedCapabilitiesNode,
xmlNewComment(BAD_CAST "Invalid setting for 'inspire_capabilities'. Must be either 'url' or 'embed'.")
);
pInspireTmpDoc = xmlParseDoc((const xmlChar *)buffer->data);
pRoot = xmlDocGetRootElement(pInspireTmpDoc);
xmlReconciliateNs(psDoc, pRoot);
pOWSExtendedCapabilities = xmlNewNode(psOwsNs, BAD_CAST "ExtendedCapabilities");
xmlAddChild(psOperationsNode, pOWSExtendedCapabilities);
pDlsExtendedCapabilities = xmlNewNode(psInspireDlsNs, BAD_CAST "ExtendedCapabilities");
xmlAddChild(pOWSExtendedCapabilities, pDlsExtendedCapabilities);
pChild = pRoot->children;
while(pChild != NULL)
{
xmlNodePtr pNext = pChild->next;
xmlUnlinkNode(pChild);
xmlAddChild(pDlsExtendedCapabilities, pChild);
pChild = pNext;
}
msWCSAddInspireDSID20(map, psInspireDlsNs, psInspireCommonNs, pDlsExtendedCapabilities);
msIO_restoreOldStdoutContext(old_context);
}
}
@@ -3499,6 +3572,7 @@ int msWCSGetCapabilities20(mapObj *map, cgiRequestObj *req,
/* Write out the document and clean up. */
/* -------------------------------------------------------------------- */
msWCSWriteDocument20(map, psDoc);
msFree(validated_language);
xmlFreeDoc(psDoc);
xmlCleanupParser();
return MS_SUCCESS;

0 comments on commit 459d5a8

Please sign in to comment.