123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- // Package linkheader provides functions for parsing HTTP Link headers
- package linkheader
- import (
- "fmt"
- "strings"
- )
- // A Link is a single URL and related parameters
- type Link struct {
- URL string
- Rel string
- Params map[string]string
- }
- // HasParam returns if a Link has a particular parameter or not
- func (l Link) HasParam(key string) bool {
- for p := range l.Params {
- if p == key {
- return true
- }
- }
- return false
- }
- // Param returns the value of a parameter if it exists
- func (l Link) Param(key string) string {
- for k, v := range l.Params {
- if key == k {
- return v
- }
- }
- return ""
- }
- // String returns the string representation of a link
- func (l Link) String() string {
- p := make([]string, 0, len(l.Params))
- for k, v := range l.Params {
- p = append(p, fmt.Sprintf("%s=\"%s\"", k, v))
- }
- if l.Rel != "" {
- p = append(p, fmt.Sprintf("%s=\"%s\"", "rel", l.Rel))
- }
- return fmt.Sprintf("<%s>; %s", l.URL, strings.Join(p, "; "))
- }
- // Links is a slice of Link structs
- type Links []Link
- // FilterByRel filters a group of Links by the provided Rel attribute
- func (l Links) FilterByRel(r string) Links {
- links := make(Links, 0)
- for _, link := range l {
- if link.Rel == r {
- links = append(links, link)
- }
- }
- return links
- }
- // String returns the string representation of multiple Links
- // for use in HTTP responses etc
- func (l Links) String() string {
- if l == nil {
- return fmt.Sprint(nil)
- }
- var strs []string
- for _, link := range l {
- strs = append(strs, link.String())
- }
- return strings.Join(strs, ", ")
- }
- // Parse parses a raw Link header in the form:
- // <url>; rel="foo", <url>; rel="bar"; wat="dis"
- // returning a slice of Link structs
- func Parse(raw string) Links {
- var links Links
- // One chunk: <url>; rel="foo"
- for _, chunk := range strings.Split(raw, ",") {
- link := Link{URL: "", Rel: "", Params: make(map[string]string)}
- // Figure out what each piece of the chunk is
- for _, piece := range strings.Split(chunk, ";") {
- piece = strings.Trim(piece, " ")
- if piece == "" {
- continue
- }
- // URL
- if piece[0] == '<' && piece[len(piece)-1] == '>' {
- link.URL = strings.Trim(piece, "<>")
- continue
- }
- // Params
- key, val := parseParam(piece)
- if key == "" {
- continue
- }
- // Special case for rel
- if strings.ToLower(key) == "rel" {
- link.Rel = val
- } else {
- link.Params[key] = val
- }
- }
- if link.URL != "" {
- links = append(links, link)
- }
- }
- return links
- }
- // ParseMultiple is like Parse, but accepts a slice of headers
- // rather than just one header string
- func ParseMultiple(headers []string) Links {
- links := make(Links, 0)
- for _, header := range headers {
- links = append(links, Parse(header)...)
- }
- return links
- }
- // parseParam takes a raw param in the form key="val" and
- // returns the key and value as seperate strings
- func parseParam(raw string) (key, val string) {
- parts := strings.SplitN(raw, "=", 2)
- if len(parts) == 1 {
- return parts[0], ""
- }
- if len(parts) != 2 {
- return "", ""
- }
- key = parts[0]
- val = strings.Trim(parts[1], "\"")
- return key, val
- }
|