mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-12-30 20:30:31 +00:00
117 lines
2.6 KiB
Go
117 lines
2.6 KiB
Go
// Copyright 2023 Woodpecker Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package multipart
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"io"
|
|
"mime/multipart"
|
|
"net/textproto"
|
|
)
|
|
|
|
type (
|
|
// Reader is an iterator over parts in a multipart log stream.
|
|
Reader interface {
|
|
// NextPart returns the next part in the multipart or
|
|
// an error. When there are no more parts, the error
|
|
// io.EOF is returned.
|
|
NextPart() (Part, error)
|
|
}
|
|
|
|
// A Part represents a single part in a multipart body.
|
|
Part interface {
|
|
io.Reader
|
|
|
|
// Header returns the headers of the body with the
|
|
// keys canonicalized.
|
|
Header() textproto.MIMEHeader
|
|
|
|
// FileName returns the filename parameter of the
|
|
// Content-Disposition header.
|
|
FileName() string
|
|
|
|
// FormName returns the name parameter if p has a
|
|
// Content-Disposition of type form-data.
|
|
FormName() string
|
|
}
|
|
)
|
|
|
|
// New returns a new multipart Reader.
|
|
func New(r io.Reader) Reader {
|
|
buf := bufio.NewReader(r)
|
|
out, _ := buf.Peek(8)
|
|
|
|
if bytes.Equal(out, []byte("PIPELINE")) {
|
|
return &multipartReader{
|
|
reader: multipart.NewReader(buf, "boundary"),
|
|
}
|
|
}
|
|
return &textReader{
|
|
reader: buf,
|
|
}
|
|
}
|
|
|
|
//
|
|
// wraps the stdlib multi-part reader
|
|
//
|
|
|
|
type multipartReader struct {
|
|
reader *multipart.Reader
|
|
}
|
|
|
|
func (r *multipartReader) NextPart() (Part, error) {
|
|
next, err := r.reader.NextPart()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
part := new(part)
|
|
part.Reader = next
|
|
part.filename = next.FileName()
|
|
part.formname = next.FormName()
|
|
part.header = next.Header
|
|
return part, nil
|
|
}
|
|
|
|
//
|
|
// wraps a simple io.Reader to satisfy the multi-part interface
|
|
//
|
|
|
|
type textReader struct {
|
|
reader io.Reader
|
|
done bool
|
|
}
|
|
|
|
func (r *textReader) NextPart() (Part, error) {
|
|
if r.done {
|
|
return nil, io.EOF
|
|
}
|
|
r.done = true
|
|
p := new(part)
|
|
p.Reader = r.reader
|
|
return p, nil
|
|
}
|
|
|
|
type part struct {
|
|
io.Reader
|
|
|
|
filename string
|
|
formname string
|
|
header textproto.MIMEHeader
|
|
}
|
|
|
|
func (p *part) Header() textproto.MIMEHeader { return p.header }
|
|
func (p *part) FileName() string { return p.filename }
|
|
func (p *part) FormName() string { return p.filename }
|