Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 62 additions & 27 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"bytes"
_ "embed"
"encoding/json"
"errors"
"flag"
"fmt"
"github.com/getsentry/sentry-go"
Expand Down Expand Up @@ -251,36 +252,73 @@ func GetPixel(image image.Image, z int, x int, y int) float64 {
}
}

func parseInput(body io.Reader) (orb.Geometry, string, string, json.RawMessage, error) {
decoder := json.NewDecoder(body)

var input Input
err := decoder.Decode(&input)
if err != nil {
return nil, "", "", nil, errors.New("input GeoJSON is invalid")
}

var geom orb.Geometry
var sanitizedData json.RawMessage

if input.RegionType == "geojson" {
geojsonGeom, err := geojson.UnmarshalGeometry(input.RegionData)
if err != nil {
return nil, "", "", nil, errors.New("input GeoJSON is invalid")
}
geom = geojsonGeom.Geometry()
switch v := geom.(type) {
case orb.Polygon:
if len(v) == 0 {
return nil, "", "", nil, errors.New("geom does not have enough rings")
}
for _, ring := range v {
if len(ring) < 4 {
return nil, "", "", nil, errors.New("ring does not have enough coordinates")
}
}
case orb.MultiPolygon:
if len(v) == 0 {
return nil, "", "", nil, errors.New("geom does not have enough rings")
}
for _, polygon := range v {
if len(polygon) == 0 {
return nil, "", "", nil, errors.New("geom does not have enough rings")
}
for _, ring := range polygon {
if len(ring) < 4 {
return nil, "", "", nil, errors.New("ring does not have enough coordinates")
}
}
}
}
sanitizedData, _ = geojsonGeom.MarshalJSON()
} else if input.RegionType == "bbox" {
var coords []float64
json.Unmarshal(input.RegionData, &coords)
if len(coords) < 4 {
return nil, "", "", nil, errors.New("input does not have >3 coordinates")
}
geom = orb.MultiPoint{orb.Point{coords[1], coords[0]}, orb.Point{coords[3], coords[2]}}.Bound()
sanitizedData, _ = json.Marshal(coords[0:4])
} else {
return nil, "", "", nil, errors.New("invalid input RegionType")
}

return geom, input.Name, input.RegionType, sanitizedData, nil
}

// check the filesystem for the result JSON
// if it's not started yet, return the position in the queue
func (h *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
if r.Method == "POST" {
decoder := json.NewDecoder(r.Body)
geom, sanitized_name, sanitized_type, sanitized_region, err := parseInput(r.Body)

var input Input
err := decoder.Decode(&input)
if err != nil {
panic(err)
}

var geom orb.Geometry
var sanitizedData json.RawMessage
// validate input
if input.RegionType == "geojson" {
geojsonGeom, _ := geojson.UnmarshalGeometry(input.RegionData)
geom = geojsonGeom.Geometry()
sanitizedData, _ = geojsonGeom.MarshalJSON()
} else if input.RegionType == "bbox" {
var coords []float64
json.Unmarshal(input.RegionData, &coords)
if len(coords) < 4 {
w.WriteHeader(400)
return
}
geom = orb.MultiPoint{orb.Point{coords[1], coords[0]}, orb.Point{coords[3], coords[2]}}.Bound()
sanitizedData, _ = json.Marshal(coords[0:4])
} else {
w.WriteHeader(400)
return
}
Expand All @@ -291,10 +329,7 @@ func (h *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}

// todo: sanitize name
// end validate input

task := Task{Uuid: uuid.New().String(), SanitizedName: input.Name, SanitizedRegionType: input.RegionType, SanitizedRegionData: sanitizedData}
task := Task{Uuid: uuid.New().String(), SanitizedName: sanitized_name, SanitizedRegionType: sanitized_type, SanitizedRegionData: sanitized_region}

select {
case h.queue <- task:
Expand Down
45 changes: 45 additions & 0 deletions main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"github.com/stretchr/testify/assert"
"image/png"
"os"
"strings"
"testing"
)

Expand All @@ -13,3 +14,47 @@ func TestGetPixel(t *testing.T) {
img, _ := png.Decode(file)
assert.Equal(t, 249.125, GetPixel(img, 14, 2620, 6331))
}

func TestGeoJSON(t *testing.T) {
_, name, regiontype, _, err := parseInput(strings.NewReader(`{"Name":"a_name", "RegionType":"geojson", "RegionData":{"type":"Polygon","coordinates":[[[0,0],[1,1],[1,0],[0,0]]]}}`))
assert.Nil(t, err)
assert.Equal(t, "a_name", name)
assert.Equal(t, "geojson", regiontype)
}

func TestBbox(t *testing.T) {
_, name, regiontype, _, err := parseInput(strings.NewReader(`{"Name":"a_name", "RegionType":"bbox", "RegionData":[0,0,1,1]}`))
assert.Nil(t, err)
assert.Equal(t, "a_name", name)
assert.Equal(t, "bbox", regiontype)
}

func TestInvalidGeoJSON(t *testing.T) {
_, _, _, _, err := parseInput(strings.NewReader(`{"Name":"a_name", "RegionType":"geojson", "RegionData":null}`))
assert.NotNil(t, err)
}

func TestMalformedGeoJSON(t *testing.T) {
_, _, _, _, err := parseInput(strings.NewReader(`{"Name":"a_name", "RegionType":"geojson", "RegionData":[}`))
assert.NotNil(t, err)
}

func TestEmptyGeoJSONPolygon(t *testing.T) {
_, _, _, _, err := parseInput(strings.NewReader(`{"Name":"a_name", "RegionType":"geojson", "RegionData":{"type":"Polygon","coordinates":[]}}`))
assert.NotNil(t, err)
}
func TestEmptyGeoJSONMultiPolygon(t *testing.T) {
_, _, _, _, err := parseInput(strings.NewReader(`{"Name":"a_name", "RegionType":"geojson", "RegionData":{"type":"MultiPolygon","coordinates":[]}}`))
assert.NotNil(t, err)
}

func TestGeoJSONPolygonTooFewCoords(t *testing.T) {
_, _, _, _, err := parseInput(strings.NewReader(`{"Name":"a_name", "RegionType":"geojson", "RegionData":{"type":"Polygon","coordinates":[[[0,0],[1,1],[0,0]]]}}`))
assert.NotNil(t, err)
}
func TestGeoJSONMultiPolygonTooFewCoords(t *testing.T) {
_, _, _, _, err := parseInput(strings.NewReader(`{"Name":"a_name", "RegionType":"geojson", "RegionData":{"type":"MultiPolygon","coordinates":[[]]}}`))
assert.NotNil(t, err)
_, _, _, _, err = parseInput(strings.NewReader(`{"Name":"a_name", "RegionType":"geojson", "RegionData":{"type":"MultiPolygon","coordinates":[[[],[]]]}}`))
assert.NotNil(t, err)
}
Loading