// foreachHeaderElement splits v according to the "#rule" construction // in RFC 2616 section 2.1 and calls fn for each non-empty element. func foreachHeaderElement(v string, fn func(string)) { v = textproto.TrimString(v) if v == "" { return } if !strings.Contains(v, ",") { fn(v) return } for _, f := range strings.Split(v, ",") { if f = textproto.TrimString(f); f != "" { fn(f) } } }
// writeHeader writes the specified MIMEHeader to the io.Writer. // Header values will be trimmed but otherwise left alone. // Headers with multiple values are not supported and will return an error. func writeHeader(w io.Writer, header textproto.MIMEHeader) error { for k, vs := range header { _, err := fmt.Fprintf(w, "%s: ", k) if err != nil { return err } for i, v := range vs { v = textproto.TrimString(v) _, err := fmt.Fprintf(w, "%s", v) if err != nil { return err } if i < len(vs)-1 { return errors.New("Multiple header values are not supported.") } } _, err = fmt.Fprint(w, crlf) if err != nil { return err } } // Write a blank line as a spacer _, err := fmt.Fprint(w, crlf) if err != nil { return err } return nil }
func checkIfMatch(w ResponseWriter, r *Request) condResult { im := r.Header.Get("If-Match") if im == "" { return condNone } for { im = textproto.TrimString(im) if len(im) == 0 { break } if im[0] == ',' { im = im[1:] continue } if im[0] == '*' { return condTrue } etag, remain := scanETag(im) if etag == "" { break } if etagStrongMatch(etag, w.Header().get("Etag")) { return condTrue } im = remain } return condFalse }
func checkIfNoneMatch(w ResponseWriter, r *Request) condResult { inm := r.Header.get("If-None-Match") if inm == "" { return condNone } buf := inm for { buf = textproto.TrimString(buf) if len(buf) == 0 { break } if buf[0] == ',' { buf = buf[1:] } if buf[0] == '*' { return condFalse } etag, remain := scanETag(buf) if etag == "" { break } if etagWeakMatch(etag, w.Header().get("Etag")) { return condFalse } buf = remain } return condTrue }
// Write writes a header in wire format. func (h Header) Write(w io.Writer) error { var err error // Mid is required if h.get(HEADER_MID) == "" { return errors.New("Missing MID in header") } // Write mid, this is defined to be the first value _, err = fmt.Fprintf(w, "Mid: %s\r\n", h.get(HEADER_MID)) if err != nil { return err } for k, slice := range h { if strings.EqualFold(k, HEADER_MID) { continue } for _, v := range slice { v = textproto.TrimString(v) _, err = fmt.Fprintf(w, "%s: %s\r\n", k, v) if err != nil { return err } } } return nil }
// only allows single content func SendMulti(auth Auth, email MultipartEmail) error { if len(email.Content) != 1 { panic("only 1 content supported") } a := smtp.PlainAuth("", auth.User, auth.Password, auth.Host) buf := new(bytes.Buffer) boundary := randomBoundary() header := make(textproto.MIMEHeader) header.Set("Subject", email.Subject) header.Set("From", email.From) header.Set("To", strings.Join(email.To, ", ")) if len(email.Cc) > 0 { header.Set("Cc", strings.Join(email.Cc, ", ")) } header.Set("MIME-Version", "1.0") header.Set("Content-Type", "multipart/mixed; boundary="+boundary) for k, v := range header { for _, s := range v { fmt.Fprintf(buf, "%s: %s%s", k, textproto.TrimString(s), crlf) } } fmt.Fprint(buf, crlf) mm := multipart.NewWriter(buf) mm.SetBoundary(boundary) { content := email.Content[0] header := make(textproto.MIMEHeader) header.Set("Content-Type", content.Type) header.Set("Content-Transfer-Encoding", "base64") part, err := mm.CreatePart(header) if err != nil { return err } lw := &lineWriter{Writer: part, Length: 75} e := base64.NewEncoder(base64.StdEncoding, lw) e.Write(content.Data) e.Close() } for _, a := range email.Attachments { header := make(textproto.MIMEHeader) header.Set("Content-Type", fmt.Sprintf(`%s; name="%s"`, a.Type, a.Filename)) if len(a.ContentID) > 0 { header.Set("Content-ID", fmt.Sprintf(`<%s>`, a.ContentID)) } header.Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, a.Filename)) header.Set("Content-Transfer-Encoding", "base64") part, err := mm.CreatePart(header) if err != nil { return err } lw := &lineWriter{Writer: part, Length: 75} e := base64.NewEncoder(base64.StdEncoding, lw) e.Write(a.Data) e.Close() } mm.Close() addr := fmt.Sprintf("%s:%d", auth.Host, auth.Port) return smtp.SendMail(addr, a, email.From, email.To, buf.Bytes()) }
func (cd *ResponseCacheDirectives) addPair(token string, v string) error { var err error = nil switch token { case "must-revalidate": err = ErrMustRevalidateNoArgs case "no-cache": cd.NoCachePresent = true tokens := strings.Split(v, ",") if cd.NoCache == nil { cd.NoCache = make(FieldNames) } for _, t := range tokens { k := http.CanonicalHeaderKey(textproto.TrimString(t)) cd.NoCache[k] = true } case "no-store": err = ErrNoStoreNoArgs case "no-transform": err = ErrNoTransformNoArgs case "public": err = ErrPublicNoArgs case "private": cd.PrivatePresent = true tokens := strings.Split(v, ",") if cd.Private == nil { cd.Private = make(FieldNames) } for _, t := range tokens { k := http.CanonicalHeaderKey(textproto.TrimString(t)) cd.Private[k] = true } case "proxy-revalidate": err = ErrProxyRevalidateNoArgs case "max-age": cd.MaxAge, err = parseDeltaSeconds(v) case "s-maxage": cd.SMaxAge, err = parseDeltaSeconds(v) default: // TODO(pquerna): this sucks, making user re-parse, and its technically not 'quoted' like the original, // but this is still easier, just a SplitN on "=" cd.Extensions = append(cd.Extensions, token+"="+v) } return err }
// WriteSubset writes a header in wire format. // If exclude is not nil, keys where exclude[key] == true are not written. func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) error { ws, ok := w.(writeStringer) if !ok { ws = stringWriter{w} } for _, kv := range h.sortedKeyValues(exclude) { for _, v := range kv.values { v = headerNewlineToSpace.Replace(v) v = textproto.TrimString(v) for _, s := range []string{kv.key, ": ", v, "\r\n"} { if _, err := ws.WriteString(s); err != nil { return err } } } } return nil }
// WriteSubset writes a header in wire format. // If exclude is not nil, keys where exclude[key] == true are not written. func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) error { ws, ok := w.(writeStringer) // 将w变为writeStringer if !ok { ws = stringWriter{w} // 转换为WriteStringer接口 } kvs, sorter := h.sortedKeyValues(exclude) // 将头部信息进行排序 for _, kv := range kvs { for _, v := range kv.values { v = headerNewlineToSpace.Replace(v) v = textproto.TrimString(v) for _, s := range []string{kv.key, ": ", v, "\r\n"} { if _, err := ws.WriteString(s); err != nil { return err } } } } headerSorterPool.Put(sorter) return nil }
// WriteTo writes this header out, including every field except for Bcc. func (h Header) WriteTo(w io.Writer) (int64, error) { // TODO: Change how headerWriter decides where to wrap, then switch to MaxHeaderLineLength writer := &headerWriter{w: w, maxLineLen: MaxHeaderTotalLength} var total int64 for _, field := range sortedHeaderFields(h) { if field == "Bcc" { continue // skip writing out Bcc } for _, val := range h[field] { val = textproto.TrimString(val) writer.curLineLen = 0 // Reset for next header for _, s := range []string{field, ": ", mime.QEncoding.Encode("UTF-8", val), "\r\n"} { written, err := io.WriteString(writer, s) if err != nil { return total, err } total += int64(written) } } } return total, nil }
// scanETag determines if a syntactically valid ETag is present at s. If so, // the ETag and remaining text after consuming ETag is returned. Otherwise, // it returns "", "". func scanETag(s string) (etag string, remain string) { s = textproto.TrimString(s) start := 0 if strings.HasPrefix(s, "W/") { start = 2 } if len(s[start:]) < 2 || s[start] != '"' { return "", "" } // ETag is either W/"text" or "text". // See RFC 7232 2.3. for i := start + 1; i < len(s); i++ { c := s[i] switch { // Character values allowed in ETags. case c == 0x21 || c >= 0x23 && c <= 0x7E || c >= 0x80: case c == '"': return string(s[:i+1]), s[i+1:] default: break } } return "", "" }
Expect(reflect.TypeOf(result).String()).To(Equal(expectedType)) }) }) Describe("#injectIconsIntoSvgTemplate ", func() { It("injects icons into a template", func() { const svgTemplateContainer = ` <svg> <defs> {{.Icons}} <defs> </svg>` stringToBeInjected := `<symbol id="hello"></symbol>` tmpl, _ := template.New("svgSpriteTemplate").Parse(textproto.TrimString(svgTemplateContainer)) resultByte := injectIconsIntoSvgTemplate(stringToBeInjected, tmpl) result := string(resultByte) expectedResult := `<svg> <defs> <symbol id="hello"></symbol> <defs> </svg>` Expect(result).To(Equal(expectedResult)) }) }) Describe("#exists", func() {