https://github.com/aohorodnyk/mimeheader
Library to work with MimeHeaders and other mime types. Library supports wildcards and parameters.
https://github.com/aohorodnyk/mimeheader
accept accept-header accept-header-parser accept-parser go go-accept-header go-http-header go-library go-mimetype go-mod go-module go-package golang mime-parser mime-type mimetype mimetype-parser
Last synced: 5 months ago
JSON representation
Library to work with MimeHeaders and other mime types. Library supports wildcards and parameters.
- Host: GitHub
- URL: https://github.com/aohorodnyk/mimeheader
- Owner: aohorodnyk
- License: mit
- Created: 2021-06-17T01:34:30.000Z (almost 5 years ago)
- Default Branch: main
- Last Pushed: 2024-05-31T01:37:45.000Z (about 2 years ago)
- Last Synced: 2024-06-18T21:38:15.439Z (almost 2 years ago)
- Topics: accept, accept-header, accept-header-parser, accept-parser, go, go-accept-header, go-http-header, go-library, go-mimetype, go-mod, go-module, go-package, golang, mime-parser, mime-type, mimetype, mimetype-parser
- Language: Go
- Homepage: https://aohorodnyk.com/post/2021-07-03-mime-headers/
- Size: 46.9 KB
- Stars: 24
- Watchers: 3
- Forks: 3
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
README
# Mime header
[](https://github.com/aohorodnyk/mimeheader/actions/workflows/go.yml)    
## RFC reference
Implementation of mime types and [Accept header support (RFC 2616 Sec 14.1)](https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1).
## Motivation
This library created to help people to parse media type data, like headers, and store and match it.
The main features of the library are to:
* Save a type as a structure (it can help pass mime type as an argument to a function or use as a field of a structure)
* Match mime types by a wildcard. It can be helpful for Accept header negotiation
* MUST be covered by tests to provide guarantees it works well
* Zero dependencies
## Examples
### Match a header with text
```go
package main
import (
"fmt"
"github.com/aohorodnyk/mimeheader"
)
// Content-Type - application/json;q=0.9;p=2
func parse(contentType string) {
mtype, err := mimeheader.ParseMediaType(contentType)
fmt.Println(err) // nil
fmt.Println(mtype.MatchText("application/json; param=1")) // true
fmt.Println(mtype.MatchText("application/xml; param=1")) // false
fmt.Println(mtype.MatchText("*/plain; param=1")) // false
fmt.Println(mtype.MatchText("text/plain; param=1")) // false
}
```
### Match accept header
```go
package main
import (
"fmt"
"github.com/aohorodnyk/mimeheader"
)
// Accept - application/json;q=1.0,*/*;q=1.0; param=wild,image/png;q=1.0;param=test
func parse(acceptHeader string) {
ah := mimeheader.ParseAcceptHeader(acceptHeader)
fmt.Println(ah.Negotiate([]string{"application/json;param=1", "image/png"}, "text/javascript")) // image/png, image/png, true
}
```
### Accept header HTTP middleware
[OWASP](https://cheatsheetseries.owasp.org/cheatsheets/REST_Security_Cheat_Sheet.html#send-safe-response-content-types) suggests using this middleware in all applications.
```go
package main
import (
"context"
"log"
"net/http"
"github.com/aohorodnyk/mimeheader"
)
func main() {
r := http.NewServeMux()
r.HandleFunc("/", acceptHeaderMiddleware([]string{"application/json", "text/html"})(handlerTestFunc))
err := http.ListenAndServe(":8080", r)
if err != nil {
log.Fatalln(err)
}
}
func acceptHeaderMiddleware(acceptMimeTypes []string) func(http.HandlerFunc) http.HandlerFunc {
return func(next http.HandlerFunc) http.HandlerFunc {
return func(rw http.ResponseWriter, r *http.Request) {
header := r.Header.Get("Accept")
ah := mimeheader.ParseAcceptHeader(header)
// We do not need default mime type.
_, mtype, m := ah.Negotiate(acceptMimeTypes, "")
if !m {
// If not matched accept mim type, return 406.
rw.WriteHeader(http.StatusNotAcceptable)
return
}
// Add matched mime type to context.
ctx := context.WithValue(r.Context(), "resp_content_type", mtype)
// New requet from new context.
rc := r.WithContext(ctx)
// Call next middleware or handler.
next(rw, rc)
}
}
}
func handlerTestFunc(rw http.ResponseWriter, r *http.Request) {
mtype := r.Context().Value("resp_content_type").(string)
rw.Write([]byte(mtype))
}
```
Requests example
```http request
GET http://localhost:8080/
Accept: text/*; q=0.9,application/json; q=1;
# HTTP/1.1 200 OK
# Date: Sat, 03 Jul 2021 19:14:58 GMT
# Content-Length: 16
# Content-Type: text/plain; charset=utf-8
# Connection: close
# application/json
###
GET http://localhost:8080/
Accept: text/*; q=1,application/json; q=1;
# HTTP/1.1 200 OK
# Date: Sat, 03 Jul 2021 19:15:51 GMT
# Content-Length: 16
# Content-Type: text/plain; charset=utf-8
# Connection: close
# application/json
###
GET http://localhost:8080/
Accept: text/html; q=1,application/*; q=1;
# HTTP/1.1 200 OK
# Date: Sat, 03 Jul 2021 19:16:15 GMT
# Content-Length: 9
# Content-Type: text/plain; charset=utf-8
# Connection: close
# text/html
###
GET http://localhost:8080/
Accept: text/*; q=1,application/*; q=0.9;
# HTTP/1.1 200 OK
# Date: Sat, 03 Jul 2021 19:16:48 GMT
# Content-Length: 9
# Content-Type: text/plain; charset=utf-8
# Connection: close
# text/html
###
GET http://localhost:8080/
Accept: text/plain; q=1,application/xml; q=1;
# HTTP/1.1 406 Not Acceptable
# Date: Sat, 03 Jul 2021 19:17:28 GMT
# Content-Length: 0
# Connection: close
```
## Current benchmark results
```
$ go test -bench=.
goos: darwin
goarch: arm64
pkg: github.com/aohorodnyk/mimeheader
BenchmarkParseAcceptHeaderLong-8 595474 1979 ns/op 1672 B/op 16 allocs/op
BenchmarkParseAcceptHeaderThreeWithWights-8 879034 1364 ns/op 1480 B/op 14 allocs/op
BenchmarkParseAcceptHeaderOne-8 4268950 279.7 ns/op 232 B/op 7 allocs/op
BenchmarkParseAcceptHeaderAndCompareLong-8 295642 4052 ns/op 2344 B/op 34 allocs/op
BenchmarkParseAcceptHeaderAndCompareThreeWithWights-8 408138 2943 ns/op 1992 B/op 28 allocs/op
BenchmarkParseAcceptHeaderAndCompareOne-8 1399750 856.0 ns/op 411 B/op 13 allocs/op
PASS
ok github.com/aohorodnyk/mimeheader 9.252s
```
## Contributing
All contributions have to follow the [CONTRIBUTING.md document](https://github.com/aohorodnyk/uid/blob/main/CONTRIBUTING.md)
If you have any questions/issues/feature requests do not hesitate to create a ticket.