diff --git a/geobinserver_test.go b/geobinserver_test.go index f9f36b8..e8e11dd 100644 --- a/geobinserver_test.go +++ b/geobinserver_test.go @@ -148,16 +148,15 @@ func TestCreateHandler(t *testing.T) { assertBodyContainsKey(w.Body, "expires", t) } -func TestBinHandler404(t *testing.T) { - // Test 404 for nonexistant bin - req, err := http.NewRequest("POST", "http://testing.geobin.io/nonexistant_bin", nil) +func TestCustomBinHandler(t *testing.T) { + req, err := http.NewRequest("POST", "http://testing.geobin.io/my_awesome_bin_id", nil) if err != nil { t.Error(err) } w := httptest.NewRecorder() createGeobinServer().ServeHTTP(w, req) - assertResponseNotFound(w, t) + assertResponseOK(w, t) } func TestBinHandlerEmptyBody(t *testing.T) { @@ -218,7 +217,7 @@ func TestBinHandler200(t *testing.T) { assertResponseOK(w, t) } -func TestBinHistoryReturnsErrorForInvalidBin(t *testing.T) { +func TestBinHistoryCreatesNonExistantBin(t *testing.T) { binId := "neverland" // Check history for our bin @@ -230,7 +229,7 @@ func TestBinHistoryReturnsErrorForInvalidBin(t *testing.T) { w := httptest.NewRecorder() createGeobinServer().ServeHTTP(w, req) - assertResponseCode(w, http.StatusNotFound, t) + assertResponseOK(w, t) } func TestBinHistoryWorksAsIntended(t *testing.T) { diff --git a/handlers.go b/handlers.go index 6fb24cf..d0e15d3 100644 --- a/handlers.go +++ b/handlers.go @@ -13,6 +13,28 @@ import ( "github.com/nu7hatch/gouuid" ) +func (gb *geobinServer) createBin(n string, w http.ResponseWriter) (time.Time, error) { + var err error + t := time.Now() + + // Save to redis + if _, err = gb.ZAdd(n, redis.Z{Score: 0, Member: ""}); err != nil { + log.Println("Failure to ZADD to", n, err) + http.Error(w, "Could not generate new Geobin!", http.StatusInternalServerError) + return t, err + } + + // Set expiration + d := 48 * time.Hour + if _, err = gb.Expire(n, d); err != nil { + log.Println("Failure to set EXPIRE for", n, err) + http.Error(w, "Could not generate new Geobin!", http.StatusInternalServerError) + return t, err + } + + return t.Add(d), nil +} + // createHandler handles requests to /api/1/create. It creates a randomly generated bin_id, // creates an entry in redis for it, with a 48 hour expiration time and writes a json object // to the response with the following structure: @@ -34,27 +56,16 @@ func (gb *geobinServer) createHandler(w http.ResponseWriter, r *http.Request) { return } - // Save to redis - if _, err = gb.ZAdd(n, redis.Z{Score: 0, Member: ""}); err != nil { - log.Println("Failure to ZADD to", n, err) - http.Error(w, "Could not generate new Geobin!", http.StatusInternalServerError) - return - } - - // Set expiration - d := 48 * time.Hour - if _, err = gb.Expire(n, d); err != nil { - log.Println("Failure to set EXPIRE for", n, err) - http.Error(w, "Could not generate new Geobin!", http.StatusInternalServerError) + var t time.Time + if t, err = gb.createBin(n, w); err != nil { return } - exp := time.Now().Add(d).Unix() // Create the json response and encoder encoder := json.NewEncoder(w) bin := map[string]interface{}{ "id": n, - "expires": exp, + "expires": t.Unix(), } // encode the json directly to the response writer @@ -112,8 +123,10 @@ func (gb *geobinServer) binHandler(w http.ResponseWriter, r *http.Request) { } if !exists { - http.NotFound(w, r) - return + // create it + if _, err = gb.createBin(name, w); err != nil { + return + } } var body []byte @@ -164,8 +177,10 @@ func (gb *geobinServer) historyHandler(w http.ResponseWriter, r *http.Request) { } if !exists { - http.NotFound(w, r) - return + // create it + if _, err = gb.createBin(name, w); err != nil { + return + } } set, err := gb.ZRevRange(name, "0", "-1") @@ -203,6 +218,20 @@ func (gb *geobinServer) wsHandler(w http.ResponseWriter, r *http.Request) { path := strings.Split(r.URL.Path, "/") binName := path[len(path)-1] + exists, err := gb.Exists(binName) + if err != nil { + http.Error(w, "Internal error", http.StatusInternalServerError) + return + } + + if !exists { + if _, err := gb.createBin(binName, w); err != nil { + log.Println("Failure to create bin while trying to SUBSCRIBE to", binName, err) + http.Error(w, "Internal server error", http.StatusInternalServerError) + return + } + } + // start pub subbing if err := gb.Subscribe(binName); err != nil { log.Println("Failure to SUBSCRIBE to", binName, err) diff --git a/static/app/bin/binList.html b/static/app/bin/binList.html index 2635200..4193b19 100644 --- a/static/app/bin/binList.html +++ b/static/app/bin/binList.html @@ -46,8 +46,8 @@
Try sending a request!
+This bin is empty. Try sending a request!
Either this bin has expired, or it never existed! Either way there's nothing to see here. You can either go back home or create a new geobin.
+This is an invalid bin name! You can either go back home or create a new geobin.
Inspect HTTP Requests with Geographic Data
+Visualize HTTP Requests with Geographic Data
You can create a new temporary bin by clicking the "Create a New Geobin" button above to get + a new randomly generated Bin ID, or you can use an arbitrary custom Bin ID of your choosing.
+ +To verify that your custom ID valid and is not currently being used by someone else go put the ID in after the slash: + http://{{host}}/my_custom_bin_id.
+ +After you have a URL, post some data to it! We currently only accept JSON formatted data in the body of HTTP POST requests.
+ +Anything you post to geobin will expire after 48 hours. The history list to the right shows the Geobins you've viewed recently and the amount + of time until their last piece of data will expire.
+ +It is also worth noting that Geobin is built to be a tool for quickly visualizing data in a temporary fashion. Its primary + purpose is to be a debugging tool. As such, there is no access control for the bins. Anyone with the URL can POST to or view + the data in the bin. Given that, it is a good idea to avoid using a custom bin ID that has a high probability of a clash with + others. Please keep this in mind when posting data to a bin, it is not secured or protected in any fashion.
+