Skip to content

Commit

Permalink
Merge pull request #15 from placeholder-app/amattu2/issue14
Browse files Browse the repository at this point in the history
#14 Add E-Tag Header Support
  • Loading branch information
amattu2 authored Feb 18, 2023
2 parents 1a9c673 + e3905e8 commit 529875d
Show file tree
Hide file tree
Showing 13 changed files with 315 additions and 46 deletions.
32 changes: 28 additions & 4 deletions .vscode/thunder-tests/thunderclient.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@
"method": "GET",
"sortNum": 10000,
"created": "2023-01-26T17:53:36.396Z",
"modified": "2023-02-08T23:23:18.634Z",
"modified": "2023-02-09T13:39:50.673Z",
"headers": [],
"params": [
{
Expand Down Expand Up @@ -183,6 +183,12 @@
"custom": "x-rate-limit-remaining",
"action": ">=",
"value": "0"
},
{
"type": "custom-header",
"custom": "ETag",
"action": "istype",
"value": "string"
}
]
},
Expand All @@ -195,7 +201,7 @@
"method": "GET",
"sortNum": 10000,
"created": "2023-01-27T01:03:22.554Z",
"modified": "2023-02-08T23:23:25.725Z",
"modified": "2023-02-15T13:44:42.205Z",
"headers": [],
"params": [
{
Expand Down Expand Up @@ -265,6 +271,12 @@
"custom": "x-rate-limit-remaining",
"action": ">=",
"value": "0"
},
{
"type": "custom-header",
"custom": "etag",
"action": "equal",
"value": "54ee307fe133c0a4dd4ad03e080c7023fdd68d31"
}
]
},
Expand All @@ -277,7 +289,7 @@
"method": "GET",
"sortNum": 12500,
"created": "2023-01-27T01:04:03.315Z",
"modified": "2023-01-27T13:05:02.710Z",
"modified": "2023-02-15T13:45:02.548Z",
"headers": [],
"params": [
{
Expand Down Expand Up @@ -309,6 +321,12 @@
"custom": "x-rate-limit-remaining",
"action": ">=",
"value": "0"
},
{
"type": "custom-header",
"custom": "etag",
"action": "equal",
"value": "d7f1a7ceea5f35bc7eb41bb527ecbc9675c69244"
}
]
},
Expand All @@ -321,7 +339,7 @@
"method": "GET",
"sortNum": 15000,
"created": "2023-01-27T13:04:57.941Z",
"modified": "2023-02-08T23:23:32.797Z",
"modified": "2023-02-15T13:45:38.556Z",
"headers": [],
"params": [
{
Expand Down Expand Up @@ -376,6 +394,12 @@
"custom": "x-rate-limit-remaining",
"action": ">=",
"value": "0"
},
{
"type": "custom-header",
"custom": "etag",
"action": "equal",
"value": "95493d77df654e19f4a57c4c056ddaebbf87c25d"
}
]
},
Expand Down
23 changes: 12 additions & 11 deletions controllers/imageController_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package controllers
package controllers_test

import (
"encoding/json"
"net/http"
"net/http/httptest"
"placeholder-app/backend/controllers"
"strings"
"testing"

Expand All @@ -38,7 +39,7 @@ func TestImageGenerateNoOptions(t *testing.T) {
recorder := httptest.NewRecorder()
context, _ := gin.CreateTestContext(recorder)

GetImage(context)
controllers.GetImage(context)

assert.Equal(t, http.StatusBadRequest, recorder.Code)
}
Expand All @@ -53,7 +54,7 @@ func TestAcceptWithOversizedBorder(t *testing.T) {
}
context.Request = httptest.NewRequest("GET", "/?borderWidth=26&format=gif", nil)

GetImage(context)
controllers.GetImage(context)

assert.Equal(t, http.StatusOK, recorder.Code)
assert.Equal(t, "image/gif", recorder.Header().Get("Content-Type"))
Expand All @@ -69,7 +70,7 @@ func TestAcceptWithUndersizedBorder(t *testing.T) {
}
context.Request = httptest.NewRequest("GET", "/?borderWidth=-1", nil)

GetImage(context)
controllers.GetImage(context)

assert.Equal(t, http.StatusOK, recorder.Code)
assert.Equal(t, "image/png", recorder.Header().Get("Content-Type"))
Expand All @@ -82,7 +83,7 @@ func TestIncorrectImageSizeFormat(t *testing.T) {
context, _ := gin.CreateTestContext(recorder)
context.Params = gin.Params{{Key: "size", Value: "fakesize"}}

GetImage(context)
controllers.GetImage(context)

assert.Equal(t, http.StatusBadRequest, recorder.Code)
}
Expand All @@ -94,7 +95,7 @@ func TestInvalidImageSize1(t *testing.T) {
context, _ := gin.CreateTestContext(recorder)
context.Params = gin.Params{{Key: "size", Value: "0x0"}}

GetImage(context)
controllers.GetImage(context)

assert.Equal(t, http.StatusBadRequest, recorder.Code)
}
Expand All @@ -106,7 +107,7 @@ func TestInvalidImageSize2(t *testing.T) {
context, _ := gin.CreateTestContext(recorder)
context.Params = gin.Params{{Key: "size", Value: "-450x500"}}

GetImage(context)
controllers.GetImage(context)

assert.Equal(t, http.StatusBadRequest, recorder.Code)
}
Expand All @@ -118,7 +119,7 @@ func TestInvalidImageSize3(t *testing.T) {
context, _ := gin.CreateTestContext(recorder)
context.Params = gin.Params{{Key: "size", Value: "5555x240"}}

GetImage(context)
controllers.GetImage(context)

assert.Equal(t, http.StatusBadRequest, recorder.Code)
}
Expand All @@ -133,7 +134,7 @@ func TestValidImageCreateFormat(t *testing.T) {
}
context.Request = httptest.NewRequest("GET", "/?format=bmp", nil)

GetImage(context)
controllers.GetImage(context)

assert.Equal(t, http.StatusOK, recorder.Code)
assert.Equal(t, "image/bmp", recorder.Header().Get("Content-Type"))
Expand All @@ -145,7 +146,7 @@ func TestGetImageFonts(t *testing.T) {
recorder := httptest.NewRecorder()
context, _ := gin.CreateTestContext(recorder)

GetFonts(context)
controllers.GetFonts(context)

assert.Equal(t, http.StatusOK, recorder.Code)
assert.Equal(t, "application/json; charset=utf-8", recorder.Header().Get("Content-Type"))
Expand All @@ -160,7 +161,7 @@ func TestGetImageFormats(t *testing.T) {
recorder := httptest.NewRecorder()
context, _ := gin.CreateTestContext(recorder)

GetFormats(context)
controllers.GetFormats(context)

assert.Equal(t, http.StatusOK, recorder.Code)
assert.Equal(t, "application/json; charset=utf-8", recorder.Header().Get("Content-Type"))
Expand Down
5 changes: 3 additions & 2 deletions controllers/utilityController_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package controllers
package controllers_test

import (
"encoding/json"
"net/http"
"net/http/httptest"
"placeholder-app/backend/controllers"
"strings"
"testing"

Expand All @@ -38,7 +39,7 @@ func TestUtilityController(t *testing.T) {
recorder := httptest.NewRecorder()
context, _ := gin.CreateTestContext(recorder)

GetStatus(context)
controllers.GetStatus(context)

assert.Equal(t, http.StatusOK, recorder.Code)
assert.Equal(t, "application/json; charset=utf-8", recorder.Header().Get("Content-Type"))
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ require (
github.com/placeholder-app/go-fonts v0.1.1
)

require github.com/google/go-cmp v0.5.8 // indirect

require (
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MG
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/james-elicx/go-utils v0.2.0 h1:MUEUEL4q6OQfWYYm1NzkDQYIlsCltaXjCyqigLmpArw=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
Expand Down Expand Up @@ -101,7 +102,6 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
Expand Down
2 changes: 1 addition & 1 deletion middlewares/cors.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import (
func Cors() gin.HandlerFunc {
return func(c *gin.Context) {
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
c.Writer.Header().Set("Access-Control-Allow-Headers", "Accept-Encoding, accept, Content-Type, Content-Length, Cache-Control, origin, X-Requested-With")
c.Writer.Header().Set("Access-Control-Allow-Headers", "Accept-Encoding, accept, Content-Type, Content-Length, Cache-Control, Etag, origin, X-Requested-With")
c.Writer.Header().Set("Access-Control-Allow-Methods", "HEAD, OPTIONS, GET")

if c.Request.Method == "OPTIONS" {
Expand Down
17 changes: 9 additions & 8 deletions middlewares/cors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package middlewares
package middlewares_test

import (
"net/http"
"net/http/httptest"
"placeholder-app/backend/middlewares"
"testing"

"github.com/gin-gonic/gin"
Expand All @@ -38,7 +39,7 @@ func TestCorsHeadMethod(t *testing.T) {

c.Request = httptest.NewRequest("HEAD", "/", nil)

Cors()(c)
middlewares.Cors()(c)

assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "*", w.Header().Get("Access-Control-Allow-Origin"))
Expand All @@ -53,7 +54,7 @@ func TestCorsOptionsMethod(t *testing.T) {

c.Request = httptest.NewRequest("OPTIONS", "/", nil)

Cors()(c)
middlewares.Cors()(c)

assert.Equal(t, http.StatusNoContent, w.Code)
assert.Equal(t, "*", w.Header().Get("Access-Control-Allow-Origin"))
Expand All @@ -68,7 +69,7 @@ func TestCorsGetMethod(t *testing.T) {

c.Request = httptest.NewRequest("GET", "/", nil)

Cors()(c)
middlewares.Cors()(c)

assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "*", w.Header().Get("Access-Control-Allow-Origin"))
Expand All @@ -83,7 +84,7 @@ func TestCorsPostMethod(t *testing.T) {

c.Request = httptest.NewRequest("POST", "/", nil)

Cors()(c)
middlewares.Cors()(c)

assert.Equal(t, http.StatusMethodNotAllowed, w.Code)
}
Expand All @@ -96,7 +97,7 @@ func TestCorsDeleteMethod(t *testing.T) {

c.Request = httptest.NewRequest("DELETE", "/", nil)

Cors()(c)
middlewares.Cors()(c)

assert.Equal(t, http.StatusMethodNotAllowed, w.Code)
}
Expand All @@ -109,7 +110,7 @@ func TestCorsPutMethod(t *testing.T) {

c.Request = httptest.NewRequest("PUT", "/", nil)

Cors()(c)
middlewares.Cors()(c)

assert.Equal(t, http.StatusMethodNotAllowed, w.Code)
}
Expand All @@ -122,7 +123,7 @@ func TestCorsPatchMethod(t *testing.T) {

c.Request = httptest.NewRequest("PATCH", "/", nil)

Cors()(c)
middlewares.Cors()(c)

assert.Equal(t, http.StatusMethodNotAllowed, w.Code)
}
66 changes: 66 additions & 0 deletions middlewares/etag.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Produced: Wed Feb 08 2023
* Author: Alec M.
* GitHub: https://amattu.com/links/github
* Copyright: (C) 2023 Alec M.
* License: License GNU Affero General Public License v3.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package middlewares

import (
"net/http"
"placeholder-app/backend/shared"

"github.com/gin-gonic/gin"
)

// GenerateEtag generates an ETag based on the query string
//
// c: gin context to generate ETag from
func generateEtag(c *gin.Context) string {
from := []string{
c.Param("size"),
c.Param("bgColor"),
c.Param("txtColor"),
c.Query("text"),
c.Query("borderWidth"),
c.Query("borderColor"),
c.Query("font"),
c.Query("format"),
}
str := ""

for _, v := range from {
str += v
}

return shared.GenerateHash(str)
}

func ETag() gin.HandlerFunc {
return func(c *gin.Context) {
var sum = generateEtag(c)

if c.Request.Header.Get("If-None-Match") == sum {
c.AbortWithStatus(http.StatusNotModified)
}

c.Writer.Header().Set("ETag", sum)

c.Next()
}
}
Loading

0 comments on commit 529875d

Please sign in to comment.