Skip to content

Commit 208f358

Browse files
authored
Improve error message when OverpassQL query mistakenly specifies [out:xml] (#1142)
1 parent 184a0f1 commit 208f358

File tree

1 file changed

+63
-13
lines changed

1 file changed

+63
-13
lines changed

app/org/maproulette/provider/ChallengeProvider.scala

+63-13
Original file line numberDiff line numberDiff line change
@@ -460,11 +460,36 @@ class ChallengeProvider @Inject() (
460460
case None => osmQLProvider.requestTimeout
461461
}
462462

463+
val modifiedQuery = rewriteQuery(ql)
464+
logger.info(modifiedQuery)
465+
463466
val jsonFuture =
464-
this.ws.url(osmQLProvider.providerURL).withRequestTimeout(timeout).post(parseQuery(ql))
467+
this.ws.url(osmQLProvider.providerURL).withRequestTimeout(timeout).post(modifiedQuery)
465468
jsonFuture onComplete {
466469
case Success(result) =>
467470
if (result.status == Status.OK) {
471+
val contentType = result.header("Content-Type")
472+
473+
// check that the Overpass API returned JSON
474+
if (contentType.isDefined && contentType != Some("application/json")) {
475+
this.challengeDAL.update(
476+
Json.obj(
477+
"status" -> Challenge.STATUS_FAILED,
478+
"statusMessage" -> s"""
479+
|Overpass API returned response with Content-Type: ${contentType.get}
480+
|
481+
|MapRoulette requires OverpassQL queries to return JSON.
482+
|
483+
|If your query contained [out:xml] or [out:csv], replace it with [out:json] and try again.
484+
""".stripMargin
485+
),
486+
user
487+
)(challenge.id)
488+
throw new InvalidException(
489+
s"Overpass API returned unexpected Content-Type: ${contentType.get}"
490+
)
491+
}
492+
468493
this.db.withTransaction { implicit c =>
469494
var partial = false
470495
val payload = result.json
@@ -730,23 +755,48 @@ class ChallengeProvider @Inject() (
730755
}
731756

732757
/**
733-
* parse the query, replace various extended overpass query parameters see https://wiki.openstreetmap.org/wiki/Overpass_turbo/Extended_Overpass_Queries
734-
* Currently do not support {{bbox}} or {{center}}
758+
* rewrite the user-provided OverpassQL query, adding output format and timeout settings if they are missing.
735759
*
736-
* @param query The query to parse
737-
* @return
760+
* @param query the input query as a string
761+
* @return a modified query string
738762
*/
739-
private def parseQuery(query: String): String = {
763+
private def rewriteQuery(query: String): String = {
740764
val osmQLProvider = config.getOSMQLProvider
741-
// User can set their own custom timeout if the want
742-
if (query.indexOf("[out:json]") == 0) {
743-
query
744-
} else if (query.indexOf("[timeout:") == 0) {
745-
s"[out:json]$query"
765+
val timeout = osmQLProvider.requestTimeout.toSeconds
766+
767+
val split = query.trim.split("\n", 2)
768+
var (firstLine, restOfQuery) = {
769+
split.length match {
770+
case 0 => ("", "")
771+
case 1 => (split(0).trim, "")
772+
case _ => (split(0).trim, split(1))
773+
}
774+
}
775+
776+
if (firstLine.startsWith("[") && firstLine.endsWith(";")) {
777+
// first line looks like OverpassQL settings statement
778+
// https://wiki.openstreetmap.org/wiki/Overpass_API/Overpass_QL#Settings
779+
780+
if (!firstLine.contains("[out:")) {
781+
// if no output format was given by the user, add [out:json]
782+
firstLine = "[out:json]" + firstLine
783+
}
784+
if (!firstLine.contains("[timeout:")) {
785+
// if no timeout was specified by the user, add one
786+
firstLine = s"[timeout:${timeout}]" + firstLine
787+
}
788+
789+
s"${firstLine}\n${restOfQuery}"
746790
} else {
747-
s"[out:json][timeout:${osmQLProvider.requestTimeout.toSeconds}];$query"
791+
// first line doesn't look like OverpassQL settings, so assume no settings were provided,
792+
// and prepend the required ones.
793+
// NOTE: this branch will incorrectly be reached if the query started with a comment,
794+
// or if the settings were split across multiple lines (OverpassQL allows both)
795+
s"[out:json][timeout:${timeout}];\n$query"
748796
}
749-
// execute regex matching against {{data:string}}, {{geocodeId:name}}, {{geocodeArea:name}}, {{geocodeBbox:name}}, {{geocodeCoords:name}}
797+
798+
// TODO: execute regex matching against {{data:string}}, {{geocodeId:name}}, {{geocodeArea:name}}, {{geocodeBbox:name}}, {{geocodeCoords:name}}
799+
// see https://wiki.openstreetmap.org/wiki/Overpass_turbo/Extended_Overpass_Queries
750800
}
751801

752802
/**

0 commit comments

Comments
 (0)