The bits are finaggled
This commit is contained in:
parent
ce0f9fcfc4
commit
10d8e5bf42
@ -4,6 +4,7 @@ import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
@ -53,41 +54,83 @@ func (client *FCGIClient) writeEndRequest(appStatus int, protocolStatus uint8) e
|
||||
// Value size
|
||||
// Name
|
||||
// Value
|
||||
// The high bit of name size and value size is used for signaling
|
||||
// how many bytes are used to store the length/size.
|
||||
// If the size is > 127, we can just use one byte,
|
||||
// and the high bit will be 0, otherwise, we use
|
||||
// four bytes and the high bit will be 1
|
||||
type NameValuePair struct {
|
||||
// Making the length values 32 bit for ease.
|
||||
// However, when encoding, the rules for
|
||||
// how many bytes are used will apply.
|
||||
NameLength uint32
|
||||
ValueLength uint32
|
||||
// Data
|
||||
NameData string
|
||||
ValueData string
|
||||
}
|
||||
|
||||
func (client *FCGIClient) writePairs(recType FCGIRequestType, pairs map[string]string) error {
|
||||
w := newWriter(client, recType)
|
||||
b := make([]byte, 8)
|
||||
nn := 0
|
||||
// Get ourselves a nice slice to work with
|
||||
nvpairs := []NameValuePair{}
|
||||
for k, v := range pairs {
|
||||
m := 8 + len(k) + len(v)
|
||||
if m > maxWrite {
|
||||
// param data size exceed 65535 bytes"
|
||||
vl := maxWrite - 8 - len(k)
|
||||
v = v[:vl]
|
||||
}
|
||||
n := encodeSize(b, uint32(len(k)))
|
||||
n += encodeSize(b[n:], uint32(len(v)))
|
||||
m = n + len(k) + len(v)
|
||||
if (nn + m) > maxWrite {
|
||||
w.Flush()
|
||||
nn = 0
|
||||
}
|
||||
nn += m
|
||||
if _, err := w.Write(b[:n]); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := w.WriteString(k); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := w.WriteString(v); err != nil {
|
||||
return err
|
||||
}
|
||||
nvpairs = append(nvpairs, NameValuePair{
|
||||
NameLength: uint32(len(k)),
|
||||
ValueLength: uint32(len(v)),
|
||||
NameData: k,
|
||||
ValueData: v,
|
||||
})
|
||||
}
|
||||
w.Close()
|
||||
|
||||
// We'll use this to put together
|
||||
// the packet
|
||||
var buf bytes.Buffer
|
||||
|
||||
for _, p := range nvpairs {
|
||||
// Let's see how many bytes we have in total.
|
||||
// Since we have to leave 8 bytes for encoding
|
||||
// the sizes, we'll add it to the calculation.
|
||||
// If the value is larger than what we can
|
||||
// handle, we'll truncate it
|
||||
if (8 + p.NameLength + p.ValueLength) > maxWrite {
|
||||
fmt.Println("We should not have hit this")
|
||||
p.ValueLength = maxWrite - 8 - p.NameLength
|
||||
p.ValueData = p.ValueData[:p.ValueLength]
|
||||
}
|
||||
|
||||
// The high bit of name size and value size is used for signaling
|
||||
// how many bytes are used to store the length/size.
|
||||
// If the size is > 127, we can just use one byte,
|
||||
// and the high bit will be 0, otherwise, we use
|
||||
// four bytes and the high bit will be 1
|
||||
// So if length is encoded in 4 bytes it would look
|
||||
// something like:
|
||||
// 10000000000000000000010000100000
|
||||
if p.NameLength > 127 {
|
||||
p.NameLength |= 1 << 31
|
||||
b := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(b, p.NameLength)
|
||||
buf.Write(b)
|
||||
} else {
|
||||
buf.Write([]byte{byte(p.NameLength)})
|
||||
}
|
||||
|
||||
if p.ValueLength > 127 {
|
||||
p.ValueLength |= 1 << 31
|
||||
b := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(b, p.ValueLength)
|
||||
buf.Write(b)
|
||||
} else {
|
||||
buf.Write([]byte{byte(p.ValueLength)})
|
||||
}
|
||||
|
||||
// Now we just write our values to the buffer
|
||||
buf.WriteString(p.NameData)
|
||||
buf.WriteString(p.ValueData)
|
||||
}
|
||||
|
||||
w := newWriter(client, recType)
|
||||
defer w.Close()
|
||||
|
||||
// Send the data
|
||||
w.Write(buf.Bytes())
|
||||
w.Flush()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -98,16 +98,6 @@ func readString(s []byte, size uint32) string {
|
||||
return string(s[:size])
|
||||
}
|
||||
|
||||
func encodeSize(b []byte, size uint32) int {
|
||||
if size > 127 {
|
||||
size |= 1 << 31
|
||||
binary.BigEndian.PutUint32(b, size)
|
||||
return 4
|
||||
}
|
||||
b[0] = byte(size)
|
||||
return 1
|
||||
}
|
||||
|
||||
// bufWriter encapsulates bufio.Writer but also closes the underlying stream when
|
||||
// Closed.
|
||||
type bufWriter struct {
|
||||
|
Loading…
x
Reference in New Issue
Block a user