// instanceSelector retrieves the data instance given its complete string name and // forwards the request to that instance's HTTP handler. func instanceSelector(c *web.C, h http.Handler) http.Handler { fn := func(w http.ResponseWriter, r *http.Request) { var err error dataname := dvid.InstanceName(c.URLParams["dataname"]) uuid, ok := c.Env["uuid"].(dvid.UUID) if !ok { msg := fmt.Sprintf("Bad format for UUID %q\n", c.Env["uuid"]) BadRequest(w, r, msg) return } data, err := datastore.GetDataByUUID(uuid, dataname) if err != nil { BadRequest(w, r, err) return } v, err := datastore.VersionFromUUID(uuid) if err != nil { BadRequest(w, r, err) } ctx := datastore.NewVersionedCtx(data, v) // Handle DVID-wide query string commands like non-interactive call designations queryValues := r.URL.Query() // All HTTP requests are interactive so let server tally request. interactive := queryValues.Get("interactive") if interactive == "" || (interactive != "false" && interactive != "0") { GotInteractiveRequest() } // TODO: setup routing for data instances as well. data.ServeHTTP(uuid, ctx, w, r) } return http.HandlerFunc(fn) }
// NewRepo returns a new datastore.Repo suitable for testing. func NewRepo() (dvid.UUID, dvid.VersionID) { uuid, err := datastore.NewRepo("testRepo", "A test repository", nil) if err != nil { log.Fatalf("Unable to create new testing repo: %v\n", err) } versionID, err := datastore.VersionFromUUID(uuid) if err != nil { log.Fatalf("Unable to get version ID from repo root UUID %s\n", uuid) } return uuid, versionID }
// NewData returns a pointer to labelvol data. func NewData(uuid dvid.UUID, id dvid.InstanceID, name dvid.InstanceName, c dvid.Config) (*Data, error) { // Initialize the Data for this data type basedata, err := datastore.NewDataService(dtype, uuid, id, name, c) if err != nil { return nil, err } props := new(Properties) props.setDefault() if err := props.setByConfig(c); err != nil { return nil, err } data := &Data{ Data: basedata, Properties: *props, } data.Properties.MaxLabel = make(map[dvid.VersionID]uint64) v, err := datastore.VersionFromUUID(uuid) if err != nil { return nil, err } data.Properties.MaxLabel[v] = 0 return data, nil }
func TestCommitBranchMergeDelete(t *testing.T) { datastore.OpenTest() defer datastore.CloseTest() uuid := createRepo(t) // Shouldn't be able to create branch on open node. branchReq := fmt.Sprintf("%snode/%s/branch", WebAPIPath, uuid) TestBadHTTP(t, "POST", branchReq, nil) // Commit it. payload := bytes.NewBufferString(`{"note": "This is my test commit", "log": ["line1", "line2", "some more stuff in a line"]}`) apiStr := fmt.Sprintf("%snode/%s/commit", WebAPIPath, uuid) TestHTTP(t, "POST", apiStr, payload) // Make sure committed nodes can only be read. // We shouldn't be able to write to log. payload = bytes.NewBufferString(`{"log": ["line1", "line2", "some more stuff in a line"]}`) apiStr = fmt.Sprintf("%snode/%s/log", WebAPIPath, uuid) TestBadHTTP(t, "POST", apiStr, payload) // Should be able to create branch now that we've committed parent. respData := TestHTTP(t, "POST", branchReq, nil) resp := struct { Child string `json:"child"` }{} if err := json.Unmarshal(respData, &resp); err != nil { t.Errorf("Expected 'child' JSON response. Got %s\n", string(respData)) } parent1 := dvid.UUID(resp.Child) // Create a sibling. respData = TestHTTP(t, "POST", branchReq, nil) if err := json.Unmarshal(respData, &resp); err != nil { t.Errorf("Expected 'child' JSON response. Got %s\n", string(respData)) } parent2 := dvid.UUID(resp.Child) // Commit both parents payload = bytes.NewBufferString(`{"note": "This is first parent"}`) apiStr = fmt.Sprintf("%snode/%s/commit", WebAPIPath, parent1) TestHTTP(t, "POST", apiStr, payload) payload = bytes.NewBufferString(`{"note": "This is second parent"}`) apiStr = fmt.Sprintf("%snode/%s/commit", WebAPIPath, parent2) TestHTTP(t, "POST", apiStr, payload) // Merge the two disjoint branches. mergeJSON := fmt.Sprintf(`{"mergeType": "conflict-free", "note": "This is my merged node", "parents": [%q, %q]}`, parent1[:7], parent2) payload = bytes.NewBufferString(mergeJSON) apiStr = fmt.Sprintf("%srepo/%s/merge", WebAPIPath, parent1) TestHTTP(t, "POST", apiStr, payload) // Get root version to check after delete repo. rootV, err := datastore.VersionFromUUID(uuid) if err != nil { t.Errorf("Got unexpected error on getting version from root UUID: %v\n", err) } // Delete the entire repo including all branches. apiStr = fmt.Sprintf("%srepo/%s", WebAPIPath, parent2) TestBadHTTP(t, "DELETE", apiStr, nil) // Requires query string apiStr = fmt.Sprintf("%srepo/%s?imsure=true", WebAPIPath, parent2) TestHTTP(t, "DELETE", apiStr, nil) // Requires query string // Make sure none of the repo is still accessible. jsonResp, err := datastore.GetRepoJSON(uuid) if err == nil { t.Errorf("Expected invalid UUID after repo delete but got json back: %s\n", jsonResp) } if err != datastore.ErrInvalidUUID { t.Errorf("Expected invalid UUID after repo delete but got unexpected error: %v\n", err) } _, err = datastore.VersionFromUUID(uuid) if err != datastore.ErrInvalidUUID { t.Errorf("Expected invalid rot UUID after repo delete but got unexpected error: %v\n", err) } _, err = datastore.VersionFromUUID(parent1) if err != datastore.ErrInvalidUUID { t.Errorf("Expected invalid UUID for 1st parent after repo delete but got unexpected error: %v\n", err) } _, err = datastore.VersionFromUUID(parent2) if err != datastore.ErrInvalidUUID { t.Errorf("Expected invalid UUID for 2nd parent after repo delete but got unexpected error: %v\n", err) } _, err = datastore.UUIDFromVersion(rootV) if err != datastore.ErrInvalidVersion { t.Errorf("Expected invalid version id for root after repo delete but got unexpected error: %v\n", err) } }
func TestKeyvalueVersioning(t *testing.T) { datastore.OpenTest() defer datastore.CloseTest() uuid, _ := initTestRepo() config := dvid.NewConfig() dataservice, err := datastore.NewData(uuid, kvtype, "versiontest", config) if err != nil { t.Fatalf("Error creating new keyvalue instance: %v\n", err) } data, ok := dataservice.(*Data) if !ok { t.Fatalf("Returned new data instance is not roi.Data\n") } // PUT a value key1 := "mykey" value1 := "some stuff" key1req := fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, uuid, data.DataName(), key1) server.TestHTTP(t, "POST", key1req, strings.NewReader(value1)) // Add 2nd k/v key2 := "my2ndkey" value2 := "more good stuff" key2req := fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, uuid, data.DataName(), key2) server.TestHTTP(t, "POST", key2req, strings.NewReader(value2)) // Create a new version in repo if err = datastore.Commit(uuid, "my commit msg", []string{"stuff one", "stuff two"}); err != nil { t.Errorf("Unable to lock root node %s: %v\n", uuid, err) } uuid2, err := datastore.NewVersion(uuid, "some child", nil) if err != nil { t.Fatalf("Unable to create new version off node %s: %v\n", uuid, err) } _, err = datastore.VersionFromUUID(uuid2) if err != nil { t.Fatalf("Unable to get version ID from new uuid %s: %v\n", uuid2, err) } // Change the 2nd k/v uuid2val := "this is completely different" uuid2req := fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, uuid2, data.DataName(), key2) server.TestHTTP(t, "POST", uuid2req, strings.NewReader(uuid2val)) // Get the first version value returnValue := server.TestHTTP(t, "GET", key2req, nil) if string(returnValue) != value2 { t.Errorf("Error on first version, key %q: expected %s, got %s\n", key2, value2, string(returnValue)) } // Get the second version value returnValue = server.TestHTTP(t, "GET", uuid2req, nil) if string(returnValue) != uuid2val { t.Errorf("Error on second version, key %q: expected %s, got %s\n", key2, uuid2val, string(returnValue)) } // Check return of first two keys in range. rangereq := fmt.Sprintf("%snode/%s/%s/keyrange/%s/%s", server.WebAPIPath, uuid, data.DataName(), "my", "zebra") returnValue = server.TestHTTP(t, "GET", rangereq, nil) var retrievedKeys []string if err = json.Unmarshal(returnValue, &retrievedKeys); err != nil { t.Errorf("Bad key range request unmarshal: %v\n", err) } if len(retrievedKeys) != 2 || retrievedKeys[1] != "mykey" && retrievedKeys[0] != "my2ndKey" { t.Errorf("Bad key range request return. Expected: [%q,%q]. Got: %s\n", key1, key2, string(returnValue)) } // Commit the repo if err = datastore.Commit(uuid2, "my 2nd commit msg", []string{"changed 2nd k/v"}); err != nil { t.Errorf("Unable to commit node %s: %v\n", uuid2, err) } // Make grandchild of root uuid3, err := datastore.NewVersion(uuid2, "some child", nil) if err != nil { t.Fatalf("Unable to create new version off node %s: %v\n", uuid2, err) } // Delete the 2nd k/v uuid3req := fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, uuid3, data.DataName(), key2) server.TestHTTP(t, "DELETE", uuid3req, nil) server.TestBadHTTP(t, "GET", uuid3req, nil) // Make sure the 2nd k/v is correct for each of previous versions. returnValue = server.TestHTTP(t, "GET", key2req, nil) if string(returnValue) != value2 { t.Errorf("Error on first version, key %q: expected %s, got %s\n", key2, value2, string(returnValue)) } returnValue = server.TestHTTP(t, "GET", uuid2req, nil) if string(returnValue) != uuid2val { t.Errorf("Error on second version, key %q: expected %s, got %s\n", key2, uuid2val, string(returnValue)) } // Make a child if err = datastore.Commit(uuid3, "my 3rd commit msg", []string{"deleted 2nd k/v"}); err != nil { t.Errorf("Unable to commit node %s: %v\n", uuid2, err) } uuid4, err := datastore.NewVersion(uuid3, "some child", nil) if err != nil { t.Fatalf("Unable to create new version off node %s: %v\n", uuid3, err) } // Change the 2nd k/v uuid4val := "we are reintroducing this k/v" uuid4req := fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, uuid4, data.DataName(), key2) server.TestHTTP(t, "POST", uuid4req, strings.NewReader(uuid4val)) if err = datastore.Commit(uuid4, "commit node 4", []string{"we modified stuff"}); err != nil { t.Errorf("Unable to commit node %s: %v\n", uuid4, err) } // Make sure the 2nd k/v is correct for each of previous versions. returnValue = server.TestHTTP(t, "GET", key2req, nil) if string(returnValue) != value2 { t.Errorf("Error on first version, key %q: expected %s, got %s\n", key2, value2, string(returnValue)) } returnValue = server.TestHTTP(t, "GET", uuid2req, nil) if string(returnValue) != uuid2val { t.Errorf("Error on second version, key %q: expected %s, got %s\n", key2, uuid2val, string(returnValue)) } server.TestBadHTTP(t, "GET", uuid3req, nil) returnValue = server.TestHTTP(t, "GET", uuid4req, nil) if string(returnValue) != uuid4val { t.Errorf("Error on fourth version, key %q: expected %s, got %s\n", key2, uuid4val, string(returnValue)) } // Let's try a merge! // Make a child off the 2nd version from root. uuid5, err := datastore.NewVersion(uuid2, "some child", nil) if err != nil { t.Fatalf("Unable to create new version off node %s: %v\n", uuid2, err) } // Store new stuff in 2nd k/v uuid5val := "this is forked value" uuid5req := fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, uuid5, data.DataName(), key2) server.TestHTTP(t, "POST", uuid5req, strings.NewReader(uuid5val)) returnValue = server.TestHTTP(t, "GET", uuid5req, nil) if string(returnValue) != uuid5val { t.Errorf("Error on merged child, key %q: expected %q, got %q\n", key2, uuid5val, string(returnValue)) } // Commit node if err = datastore.Commit(uuid5, "forked node", []string{"we modified stuff"}); err != nil { t.Errorf("Unable to commit node %s: %v\n", uuid5, err) } // Should be able to merge using conflict-free (disjoint at key level) merge even though // its conflicted. Will get lazy error on request. badChild, err := datastore.Merge([]dvid.UUID{uuid4, uuid5}, "some child", datastore.MergeConflictFree) if err != nil { t.Errorf("Error doing merge: %v\n", err) } childreq := fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, badChild, data.DataName(), key2) server.TestBadHTTP(t, "GET", childreq, nil) // Manually fix conflict: Branch, and then delete 2nd k/v and commit. uuid6, err := datastore.NewVersion(uuid5, "some child", nil) if err != nil { t.Fatalf("Unable to create new version off node %s: %v\n", uuid5, err) } uuid6req := fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, uuid6, data.DataName(), key2) server.TestHTTP(t, "DELETE", uuid6req, nil) server.TestBadHTTP(t, "GET", uuid6req, nil) if err = datastore.Commit(uuid6, "deleted forked node 2nd k/v", []string{"we modified stuff"}); err != nil { t.Errorf("Unable to commit node %s: %s\n", uuid6, err) } // Should now be able to correctly merge the two branches. goodChild, err := datastore.Merge([]dvid.UUID{uuid4, uuid6}, "merging stuff", datastore.MergeConflictFree) if err != nil { t.Errorf("Error doing merge: %v\n", err) } // We should be able to see just the original uuid4 value of the 2nd k/v childreq = fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, goodChild, data.DataName(), key2) returnValue = server.TestHTTP(t, "GET", childreq, nil) if string(returnValue) != uuid4val { t.Errorf("Error on merged child, key %q: expected %q, got %q\n", key2, uuid4val, string(returnValue)) } // Apply the automatic conflict resolution using ordering. payload := fmt.Sprintf(`{"data":["versiontest"],"parents":[%q,%q],"note":"automatic resolved merge"}`, uuid5, uuid4) resolveReq := fmt.Sprintf("%srepo/%s/resolve", server.WebAPIPath, uuid4) returnValue = server.TestHTTP(t, "POST", resolveReq, bytes.NewBufferString(payload)) resolveResp := struct { Child dvid.UUID `json:"child"` }{} if err := json.Unmarshal(returnValue, &resolveResp); err != nil { t.Fatalf("Can't parse return of resolve request: %s\n", string(returnValue)) } // We should now see the uuid5 version of the 2nd k/v in the returned merged node. childreq = fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, resolveResp.Child, data.DataName(), key2) returnValue = server.TestHTTP(t, "GET", childreq, nil) if string(returnValue) != uuid5val { t.Errorf("Error on auto merged child, key %q: expected %q, got %q\n", key2, uuid5val, string(returnValue)) } // Introduce a child off root but don't add 2nd k/v to it. uuid7, err := datastore.NewVersion(uuid, "2nd child off root", nil) if err != nil { t.Fatalf("Unable to create new version off node %s: %v\n", uuid, err) } if err = datastore.Commit(uuid7, "useless node", []string{"we modified nothing!"}); err != nil { t.Errorf("Unable to commit node %s: %v\n", uuid7, err) } // Now merge the previously merged node with the newly created "blank" child off root. if err = datastore.Commit(goodChild, "this was a good merge", []string{}); err != nil { t.Errorf("Unable to commit node %s: %v\n", goodChild, err) } merge2, err := datastore.Merge([]dvid.UUID{goodChild, uuid7}, "merging a useless path", datastore.MergeConflictFree) if err != nil { t.Errorf("Error doing merge: %v\n", err) } merge3, err := datastore.Merge([]dvid.UUID{uuid7, goodChild}, "merging a useless path in reverse order", datastore.MergeConflictFree) if err != nil { t.Errorf("Error doing merge: %v\n", err) } // We should still be conflict free since 2nd key in left parent path will take precedent over shared 2nd key // in root. This tests our invalidation of ancestors. toughreq := fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, merge2, data.DataName(), key2) returnValue = server.TestHTTP(t, "GET", toughreq, nil) if string(returnValue) != uuid4val { t.Errorf("Error on merged child, key %q: expected %q, got %q\n", key2, uuid4val, string(returnValue)) } toughreq = fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, merge3, data.DataName(), key2) returnValue = server.TestHTTP(t, "GET", toughreq, nil) if string(returnValue) != uuid4val { t.Errorf("Error on merged child, key %q: expected %q, got %q\n", key2, uuid4val, string(returnValue)) } }
func TestKeyvalueUnversioned(t *testing.T) { datastore.OpenTest() defer datastore.CloseTest() uuid, _ := initTestRepo() config := dvid.NewConfig() config.Set("versioned", "false") dataservice, err := datastore.NewData(uuid, kvtype, "unversiontest", config) if err != nil { t.Fatalf("Error creating new keyvalue instance: %v\n", err) } data, ok := dataservice.(*Data) if !ok { t.Fatalf("Returned new data instance is not roi.Data\n") } // PUT a value key1 := "mykey" value1 := "some stuff" key1req := fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, uuid, data.DataName(), key1) server.TestHTTP(t, "POST", key1req, strings.NewReader(value1)) // Add 2nd k/v key2 := "my2ndkey" value2 := "more good stuff" key2req := fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, uuid, data.DataName(), key2) server.TestHTTP(t, "POST", key2req, strings.NewReader(value2)) // Create a new version in repo if err = datastore.Commit(uuid, "my commit msg", []string{"stuff one", "stuff two"}); err != nil { t.Errorf("Unable to lock root node %s: %v\n", uuid, err) } uuid2, err := datastore.NewVersion(uuid, "some child", nil) if err != nil { t.Fatalf("Unable to create new version off node %s: %v\n", uuid, err) } _, err = datastore.VersionFromUUID(uuid2) if err != nil { t.Fatalf("Unable to get version ID from new uuid %s: %v\n", uuid2, err) } // Change the 2nd k/v uuid2val := "this is completely different" uuid2req := fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, uuid2, data.DataName(), key2) server.TestHTTP(t, "POST", uuid2req, strings.NewReader(uuid2val)) // Now the first version value should equal the new value returnValue := server.TestHTTP(t, "GET", key2req, nil) if string(returnValue) != uuid2val { t.Errorf("Error on unversioned key %q: expected %s, got %s\n", key2, uuid2val, string(returnValue)) } // Get the second version value returnValue = server.TestHTTP(t, "GET", uuid2req, nil) if string(returnValue) != uuid2val { t.Errorf("Error on unversioned key %q: expected %s, got %s\n", key2, uuid2val, string(returnValue)) } // Check return of first two keys in range. rangereq := fmt.Sprintf("%snode/%s/%s/keyrange/%s/%s", server.WebAPIPath, uuid, data.DataName(), "my", "zebra") returnValue = server.TestHTTP(t, "GET", rangereq, nil) var retrievedKeys []string if err = json.Unmarshal(returnValue, &retrievedKeys); err != nil { t.Errorf("Bad key range request unmarshal: %v\n", err) } if len(retrievedKeys) != 2 || retrievedKeys[1] != "mykey" && retrievedKeys[0] != "my2ndKey" { t.Errorf("Bad key range request return. Expected: [%q,%q]. Got: %s\n", key1, key2, string(returnValue)) } // Commit the repo if err = datastore.Commit(uuid2, "my 2nd commit msg", []string{"changed 2nd k/v"}); err != nil { t.Errorf("Unable to commit node %s: %v\n", uuid2, err) } // Make grandchild of root uuid3, err := datastore.NewVersion(uuid2, "some child", nil) if err != nil { t.Fatalf("Unable to create new version off node %s: %v\n", uuid2, err) } // Delete the 2nd k/v uuid3req := fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, uuid3, data.DataName(), key2) server.TestHTTP(t, "DELETE", uuid3req, nil) server.TestBadHTTP(t, "GET", uuid3req, nil) // Make sure the 2nd k/v is now missing for previous versions. server.TestBadHTTP(t, "GET", key2req, nil) server.TestBadHTTP(t, "GET", uuid2req, nil) // Make a child if err = datastore.Commit(uuid3, "my 3rd commit msg", []string{"deleted 2nd k/v"}); err != nil { t.Errorf("Unable to commit node %s: %v\n", uuid2, err) } uuid4, err := datastore.NewVersion(uuid3, "some child", nil) if err != nil { t.Fatalf("Unable to create new version off node %s: %v\n", uuid3, err) } // Change the 2nd k/v uuid4val := "we are reintroducing this k/v" uuid4req := fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, uuid4, data.DataName(), key2) server.TestHTTP(t, "POST", uuid4req, strings.NewReader(uuid4val)) if err = datastore.Commit(uuid4, "commit node 4", []string{"we modified stuff"}); err != nil { t.Errorf("Unable to commit node %s: %v\n", uuid4, err) } // Make sure the 2nd k/v is correct for each of previous versions. returnValue = server.TestHTTP(t, "GET", key2req, nil) if string(returnValue) != uuid4val { t.Errorf("Error on first version, key %q: expected %s, got %s\n", key2, uuid4val, string(returnValue)) } returnValue = server.TestHTTP(t, "GET", uuid2req, nil) if string(returnValue) != uuid4val { t.Errorf("Error on second version, key %q: expected %s, got %s\n", key2, uuid4val, string(returnValue)) } returnValue = server.TestHTTP(t, "GET", uuid3req, nil) if string(returnValue) != uuid4val { t.Errorf("Error on third version, key %q: expected %s, got %s\n", key2, uuid4val, string(returnValue)) } returnValue = server.TestHTTP(t, "GET", uuid4req, nil) if string(returnValue) != uuid4val { t.Errorf("Error on fourth version, key %q: expected %s, got %s\n", key2, uuid4val, string(returnValue)) } }
// instanceSelector retrieves the data instance given its complete string name and // forwards the request to that instance's HTTP handler. func instanceSelector(c *web.C, h http.Handler) http.Handler { fn := func(w http.ResponseWriter, r *http.Request) { if httpUnavailable(w) { return } var err error dataname := dvid.InstanceName(c.URLParams["dataname"]) uuid, ok := c.Env["uuid"].(dvid.UUID) if !ok { msg := fmt.Sprintf("Bad format for UUID %q\n", c.Env["uuid"]) BadRequest(w, r, msg) return } data, err := datastore.GetDataByUUIDName(uuid, dataname) if err != nil { BadRequest(w, r, err) return } v, err := datastore.VersionFromUUID(uuid) if err != nil { BadRequest(w, r, err) return } if data.Versioned() { // Make sure we aren't trying mutable methods on committed nodes. locked, err := datastore.LockedUUID(uuid) if err != nil { BadRequest(w, r, err) return } if locked && data.IsMutationRequest(r.Method, c.URLParams["keyword"]) { BadRequest(w, r, "Cannot do %s on endpoint %q of locked node %s", r.Method, c.URLParams["keyword"], uuid) return } } else { // Map everything to root version. v, err = datastore.GetRepoRootVersion(v) if err != nil { BadRequest(w, r, err) return } } ctx := datastore.NewVersionedCtx(data, v) // Also set the web request information in case logging needs it downstream. ctx.SetRequestID(middleware.GetReqID(*c)) // Handle DVID-wide query string commands like non-interactive call designations queryStrings := r.URL.Query() // All HTTP requests are interactive so let server tally request. interactive := queryStrings.Get("interactive") if interactive == "" || (interactive != "false" && interactive != "0") { GotInteractiveRequest() } // TODO: setup routing for data instances as well. if config != nil && config.AllowTiming() { w.Header().Set("Timing-Allow-Origin", "*") } data.ServeHTTP(uuid, ctx, w, r) } return http.HandlerFunc(fn) }