mirror of https://github.com/periph/devices
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
75 lines
1.7 KiB
Go
75 lines
1.7 KiB
Go
// Copyright 2021 The Periph Authors. All rights reserved.
|
|
// Use of this source code is governed under the Apache License, Version 2.0
|
|
// that can be found in the LICENSE file.
|
|
|
|
package videosink
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/rand"
|
|
"fmt"
|
|
"io"
|
|
"net/textproto"
|
|
"strconv"
|
|
)
|
|
|
|
// randomBoundary generates a MIME multipart boundary compatible with RFC 2046
|
|
// (section 5.1.1).
|
|
func randomBoundary() string {
|
|
var buf [34]byte
|
|
if _, err := io.ReadFull(rand.Reader, buf[:]); err != nil {
|
|
panic(err)
|
|
}
|
|
return fmt.Sprintf("%x", buf[:])
|
|
}
|
|
|
|
type partWriter struct {
|
|
u io.Writer
|
|
boundary string
|
|
started bool
|
|
}
|
|
|
|
func makePartWriter(u io.Writer) partWriter {
|
|
return partWriter{
|
|
u: u,
|
|
boundary: randomBoundary(),
|
|
}
|
|
}
|
|
|
|
// writeFrame sends a single part of a MIME multipart entity, ensuring it's
|
|
// fully written by the time the function returns.
|
|
//
|
|
// The caller-owned headers are modified to set a Content-Length header.
|
|
//
|
|
// Go has a writer for MIME multipart messages in "mime/multipart".Writer. As
|
|
// of Go 1.17 it's not suitable for writing a neverending stream of parts where
|
|
// each must be flushed to the client with the part-ending boundary line.
|
|
func (w *partWriter) writeFrame(header textproto.MIMEHeader, body []byte) error {
|
|
header.Set("Content-Length", strconv.FormatInt(int64(len(body)), 10))
|
|
|
|
var buf bytes.Buffer
|
|
|
|
if !w.started {
|
|
fmt.Fprintf(&buf, "--%s\r\n", w.boundary)
|
|
w.started = true
|
|
}
|
|
|
|
for name := range header {
|
|
for _, value := range header[name] {
|
|
fmt.Fprintf(&buf, "%s: %s\r\n", name, value)
|
|
}
|
|
}
|
|
|
|
buf.WriteString("\r\n")
|
|
|
|
_, err := buf.WriteTo(w.u)
|
|
if err == nil {
|
|
_, err = io.Copy(w.u, bytes.NewReader(body))
|
|
if err == nil {
|
|
_, err = fmt.Fprintf(w.u, "\r\n--%s\r\n", w.boundary)
|
|
}
|
|
}
|
|
|
|
return err
|
|
}
|