-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat!: add ContentType, expanded Accept parsing
BREAKING CHANGES * ContentType{} to describe a full content type descriptor * ParseAccept() returns a slice of acceptable ContentTypes found, ordered by quality factor * ParseContentType() returns (ContentType, bool) * CheckFormat() returns a single, preferred ContentType * Remove spaces from default ContentType formatting * Deprecate ResponseContentTypeHeader * Deprecate RequestAcceptHeader
- Loading branch information
Showing
4 changed files
with
262 additions
and
122 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,34 +1,105 @@ | ||
package trustlesshttp | ||
|
||
import "fmt" | ||
import ( | ||
"strconv" | ||
"strings" | ||
) | ||
|
||
type ContentTypeOrder string | ||
|
||
const ( | ||
MimeTypeCar = "application/vnd.ipld.car" // The only accepted MIME type | ||
MimeTypeCarVersion = "1" // We only accept version 1 of the MIME type | ||
FormatParameterCar = "car" // The only valid format parameter value | ||
FilenameExtCar = ".car" // The only valid filename extension | ||
DefaultIncludeDupes = true // The default value for an unspecified "dups" parameter. See https://github.com/ipfs/specs/pull/412. | ||
ResponseCacheControlHeader = "public, max-age=29030400, immutable" // Magic cache control values | ||
DefaultIncludeDupes = true // The default value for an unspecified "dups" parameter. | ||
DefaultOrder = ContentTypeOrderDfs // The default value for an unspecified "order" parameter. | ||
|
||
ContentTypeOrderDfs ContentTypeOrder = "dfs" | ||
ContentTypeOrderUnk ContentTypeOrder = "unk" | ||
) | ||
|
||
var ( | ||
ResponseChunkDelimeter = []byte("0\r\n") // An http/1.1 chunk delimeter, used for specifying an early end to the response | ||
baseContentType = fmt.Sprintf("%s; version=%s; order=dfs", MimeTypeCar, MimeTypeCarVersion) | ||
) | ||
|
||
type ContentType struct { | ||
Mime string | ||
Order ContentTypeOrder | ||
Duplicates bool | ||
Quality float32 | ||
} | ||
|
||
func (ct ContentType) String() string { | ||
sb := strings.Builder{} | ||
sb.WriteString(ct.Mime) | ||
sb.WriteString(";version=") | ||
sb.WriteString(MimeTypeCarVersion) | ||
sb.WriteString(";order=") | ||
sb.WriteString(string(ct.Order)) | ||
if ct.Duplicates { | ||
sb.WriteString(";dups=y") | ||
} else { | ||
sb.WriteString(";dups=n") | ||
} | ||
if ct.Quality < 1 && ct.Quality >= 0.00 { | ||
sb.WriteString(";q=") | ||
// write quality with max 3 decimal places | ||
sb.WriteString(strconv.FormatFloat(float64(ct.Quality), 'g', 3, 32)) | ||
} | ||
return sb.String() | ||
} | ||
|
||
type ContentTypeOption func(ct *ContentType) | ||
|
||
func WithContentTypeOrder(order ContentTypeOrder) ContentTypeOption { | ||
return func(ct *ContentType) { | ||
ct.Order = order | ||
} | ||
} | ||
|
||
func WithContentTypeDuplicates(duplicates bool) ContentTypeOption { | ||
return func(ct *ContentType) { | ||
ct.Duplicates = duplicates | ||
} | ||
} | ||
|
||
func WithContentTypeQuality(quality float32) ContentTypeOption { | ||
return func(ct *ContentType) { | ||
ct.Quality = quality | ||
} | ||
} | ||
|
||
func NewContentType(opt ...ContentTypeOption) ContentType { | ||
ct := ContentType{ | ||
Mime: MimeTypeCar, | ||
Order: DefaultOrder, | ||
Duplicates: DefaultIncludeDupes, | ||
Quality: 1, | ||
} | ||
for _, o := range opt { | ||
o(&ct) | ||
} | ||
return ct | ||
} | ||
|
||
// ResponseContentTypeHeader returns the value for the Content-Type header for a | ||
// Trustless Gateway response which will vary depending on whether duplicates | ||
// are included or not. Otherwise, the header is the same for all responses. | ||
// | ||
// Deprecated: Use NewContentType().String() instead. | ||
func ResponseContentTypeHeader(duplicates bool) string { | ||
if duplicates { | ||
return baseContentType + "; dups=y" | ||
} | ||
return baseContentType + "; dups=n" | ||
ct := NewContentType() | ||
ct.Duplicates = duplicates | ||
return ct.String() | ||
} | ||
|
||
// RequestAcceptHeader returns the value for the Accept header for a Trustless | ||
// Gateway request which will vary depending on whether duplicates are included | ||
// or not. Otherwise, the header is the same for all requests. | ||
// | ||
// Deprecated: Use NewContentType().String() instead. | ||
func RequestAcceptHeader(duplicates bool) string { | ||
return ResponseContentTypeHeader(duplicates) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.