123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101 |
- package httphead
- import "io"
- var (
- comma = []byte{','}
- equality = []byte{'='}
- semicolon = []byte{';'}
- quote = []byte{'"'}
- escape = []byte{'\\'}
- )
- // WriteOptions write options list to the dest.
- // It uses the same form as {Scan,Parse}Options functions:
- // values = 1#value
- // value = token *( ";" param )
- // param = token [ "=" (token | quoted-string) ]
- //
- // It wraps valuse into the quoted-string sequence if it contains any
- // non-token characters.
- func WriteOptions(dest io.Writer, options []Option) (n int, err error) {
- w := writer{w: dest}
- for i, opt := range options {
- if i > 0 {
- w.write(comma)
- }
- writeTokenSanitized(&w, opt.Name)
- for _, p := range opt.Parameters.data() {
- w.write(semicolon)
- writeTokenSanitized(&w, p.key)
- if len(p.value) != 0 {
- w.write(equality)
- writeTokenSanitized(&w, p.value)
- }
- }
- }
- return w.result()
- }
- // writeTokenSanitized writes token as is or as quouted string if it contains
- // non-token characters.
- //
- // Note that is is not expects LWS sequnces be in s, cause LWS is used only as
- // header field continuation:
- // "A CRLF is allowed in the definition of TEXT only as part of a header field
- // continuation. It is expected that the folding LWS will be replaced with a
- // single SP before interpretation of the TEXT value."
- // See https://tools.ietf.org/html/rfc2616#section-2
- //
- // That is we sanitizing s for writing, so there could not be any header field
- // continuation.
- // That is any CRLF will be escaped as any other control characters not allowd in TEXT.
- func writeTokenSanitized(bw *writer, bts []byte) {
- var qt bool
- var pos int
- for i := 0; i < len(bts); i++ {
- c := bts[i]
- if !OctetTypes[c].IsToken() && !qt {
- qt = true
- bw.write(quote)
- }
- if OctetTypes[c].IsControl() || c == '"' {
- if !qt {
- qt = true
- bw.write(quote)
- }
- bw.write(bts[pos:i])
- bw.write(escape)
- bw.write(bts[i : i+1])
- pos = i + 1
- }
- }
- if !qt {
- bw.write(bts)
- } else {
- bw.write(bts[pos:])
- bw.write(quote)
- }
- }
- type writer struct {
- w io.Writer
- n int
- err error
- }
- func (w *writer) write(p []byte) {
- if w.err != nil {
- return
- }
- var n int
- n, w.err = w.w.Write(p)
- w.n += n
- return
- }
- func (w *writer) result() (int, error) {
- return w.n, w.err
- }
|