mirror of
https://github.com/dutchcoders/transfer.sh.git
synced 2025-01-15 21:20:19 +01:00
145 lines
3.6 KiB
Go
145 lines
3.6 KiB
Go
// Copyright 2015 Google Inc. All rights reserved.
|
|
//
|
|
// 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 marbl
|
|
|
|
import (
|
|
"bufio"
|
|
"encoding/binary"
|
|
"fmt"
|
|
"io"
|
|
)
|
|
|
|
// Header is either an HTTP header or meta-data pertaining to the request or response.
|
|
type Header struct {
|
|
ID string
|
|
MessageType MessageType
|
|
Name string
|
|
Value string
|
|
}
|
|
|
|
// String returns the contents of a Header frame in a format appropriate for debugging and runtime logging.
|
|
func (hf Header) String() string {
|
|
return fmt.Sprintf("ID=%s; Type=%d; Name=%s; Value=%s", hf.ID, hf.MessageType, hf.Name, hf.Value)
|
|
}
|
|
|
|
// FrameType returns HeaderFrame
|
|
func (hf Header) FrameType() FrameType {
|
|
return HeaderFrame
|
|
}
|
|
|
|
// Data is the payload (body) of the request or response.
|
|
type Data struct {
|
|
ID string
|
|
MessageType MessageType
|
|
Index uint32
|
|
Terminal bool
|
|
Data []byte
|
|
}
|
|
|
|
// String returns the contents of a Data frame in a format appropriate for debugging and runtime logging. The
|
|
// contents of the data content slice (df.Data) is not printed, instead the length of Data is printed.
|
|
func (df Data) String() string {
|
|
return fmt.Sprintf("ID=%s; Type=%d; Index=%d; Terminal=%t; Data length=%d",
|
|
df.ID, df.MessageType, df.Index, df.Terminal, len(df.Data))
|
|
}
|
|
|
|
// FrameType returns DataFrame
|
|
func (df Data) FrameType() FrameType {
|
|
return DataFrame
|
|
}
|
|
|
|
// Frame describes the interface for a frame (either Data or Header).
|
|
type Frame interface {
|
|
String() string
|
|
FrameType() FrameType
|
|
}
|
|
|
|
// Reader wraps a buffered Reader that reads from the io.Reader and emits Frames.
|
|
type Reader struct {
|
|
r io.Reader
|
|
}
|
|
|
|
// NewReader returns a Reader initialized with a buffered reader.
|
|
func NewReader(r io.Reader) *Reader {
|
|
return &Reader{
|
|
r: bufio.NewReader(r),
|
|
}
|
|
}
|
|
|
|
// ReadFrame reads from r, determines the FrameType, and returns either a Header or Data and an error.
|
|
func (r *Reader) ReadFrame() (Frame, error) {
|
|
fh := make([]byte, 10)
|
|
|
|
if _, err := io.ReadFull(r.r, fh); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
switch FrameType(fh[0]) {
|
|
case HeaderFrame:
|
|
hf := Header{
|
|
ID: string(fh[2:]),
|
|
MessageType: MessageType(fh[1]),
|
|
}
|
|
|
|
lens := make([]byte, 8)
|
|
if _, err := io.ReadFull(r.r, lens); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
nl := binary.BigEndian.Uint32(lens[:4])
|
|
vl := binary.BigEndian.Uint32(lens[4:])
|
|
|
|
nv := make([]byte, int(nl+vl))
|
|
if _, err := io.ReadFull(r.r, nv); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
hf.Name = string(nv[:nl])
|
|
hf.Value = string(nv[nl:])
|
|
|
|
return hf, nil
|
|
case DataFrame:
|
|
df := Data{
|
|
ID: string(fh[2:]),
|
|
MessageType: MessageType(fh[1]),
|
|
}
|
|
|
|
// Reading 9 bytes:
|
|
// 4 bytes index
|
|
// 1 byte terminal
|
|
// 4 bytes data length
|
|
desc := make([]byte, 9)
|
|
if _, err := io.ReadFull(r.r, desc); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
df.Index = binary.BigEndian.Uint32(desc[:4])
|
|
df.Terminal = desc[4] == 1
|
|
|
|
dl := binary.BigEndian.Uint32(desc[5:])
|
|
|
|
|
|
data := make([]byte, int(dl))
|
|
if _, err := io.ReadFull(r.r, data); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
df.Data = data
|
|
|
|
return df, nil
|
|
default:
|
|
return nil, fmt.Errorf("marbl: unknown type of frame")
|
|
}
|
|
}
|