initial commits

master
Charles Iliya Krempeaux 2023-08-11 14:11:12 -07:00
parent 31110d58c2
commit 33ffaa1ad7
2 changed files with 165 additions and 0 deletions

104
httpaccept.go 100644
View File

@ -0,0 +1,104 @@
package httpaccept
import (
"sourcecode.social/reiver/go-httpaccept/mediarange"
"strings"
)
// HTTPAccept represents the values of the Accept headers of an HTTP request.
//
// Note that an HTTP request can have multople Accept headers.
type HTTPAccept struct {
mediaranges []mediarange.MediaRange
}
// Create creates an HTTPAccept.
//
// For example:
//
// // Accept: application/activity+json
// accept := httpaccept.Create(
// mediarange.Create("application", "activity+json"), // application/activity+json
// )
//
// // Accept: image/png,image/gif
// accept := httpaccept.Create(
// mediarange.Create("image", "png"), // image/png
// mediarange.Create("image", "gif"), // image/gif
// )
func Create(mediaranges ...mediarange.MediaRange) HTTPAccept {
return HTTPAccept{
mediaranges:mediaranges,
}
}
// Negotiate figures out if there is an acceptable media-type, and if there is returns the "best" one.
//
// For example:
//
// var accept httpaccept.HTTPAccept
//
// // ...
//
// contentType, err := accept.Negotiate("text/gemini", "text/html", "application/activity+json")
func (receiver HTTPAccept) Negotiate(mediatypes ...string) (string, error) {
var temp []string
{
temp, mediatypes = mediatypes, nil
for _, mediatype := range temp {
a := strings.SplitN(mediatype, ";", 2)
if len(a) < 1 {
continue
}
mediatypes = append(mediatypes, a[0])
}
}
for _, mediarange := range receiver.mediaranges {
for _, mediatype := range mediatypes {
if mediarange.Match(mediatype) {
return mediatype, nil
}
}
}
return "", internalNotAcceptable{temp}
}
// String returns the serialized HTTP Accept header.
//
// For example:
//
// // "Accept: text/html,application/xhtml+xml\r\n"
// s := httpaccept.Create(mediarange.Create("text", "html"), mediarange.Create("application","xhtml+xml")).String()
func (receiver HTTPAccept) String() string {
var mediaranges []mediarange.MediaRange = receiver.mediaranges
if len(mediaranges) < 1 {
return ""
}
var buffer strings.Builder
{
buffer.WriteString("Accept: ")
for i, mediarange := range receiver.mediaranges {
if 0 != i {
buffer.WriteRune(',')
}
buffer.WriteString(mediarange.String())
}
buffer.WriteString("\r\n")
}
return buffer.String()
}

View File

@ -0,0 +1,61 @@
package httpaccept_test
import (
"sourcecode.social/reiver/go-httpaccept"
"sourcecode.social/reiver/go-httpaccept/mediarange"
"testing"
)
func TestHTTPAccept_String(t *testing.T) {
tests := []struct{
HTTPAccept httpaccept.HTTPAccept
Expected string
}{
{
HTTPAccept: httpaccept.Create(),
Expected: "",
},
{
HTTPAccept: httpaccept.Create(mediarange.Create("*", "*")),
Expected: "Accept: */*"+"\r\n",
},
{
HTTPAccept: httpaccept.Create(mediarange.Create("text", "html"), mediarange.Create("*", "*")),
Expected: "Accept: text/html,*/*"+"\r\n",
},
{
HTTPAccept: httpaccept.Create(mediarange.Create("text", "html"), mediarange.Create("application", "xhtml+xml"), mediarange.Create("*", "*")),
Expected: "Accept: text/html,application/xhtml+xml,*/*"+"\r\n",
},
{
HTTPAccept: httpaccept.Create(mediarange.Create("application", "activity+json")),
Expected: "Accept: application/activity+json"+"\r\n",
},
{
HTTPAccept: httpaccept.Create(mediarange.Create("application", "activity+json"), mediarange.Create("application", "json")),
Expected: "Accept: application/activity+json,application/json"+"\r\n",
},
}
for testNumber, test := range tests {
actual := test.HTTPAccept.String()
expected := test.Expected
if expected != actual {
t.Errorf("For test #%d, the actual (serialized) stringer value is not what was expected.", testNumber)
t.Logf("HTTP-ACCEPT: %#v", test.HTTPAccept)
t.Logf("EXPECTED: %q", expected)
t.Logf("ACTUAL: %q", actual)
continue
}
}
}