initial commits
parent
31110d58c2
commit
33ffaa1ad7
|
@ -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()
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue