The bits are finaggled
This commit is contained in:
parent
ce0f9fcfc4
commit
10d8e5bf42
@ -4,6 +4,7 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httputil"
|
"net/http/httputil"
|
||||||
@ -53,41 +54,83 @@ func (client *FCGIClient) writeEndRequest(appStatus int, protocolStatus uint8) e
|
|||||||
// Value size
|
// Value size
|
||||||
// Name
|
// Name
|
||||||
// Value
|
// Value
|
||||||
// The high bit of name size and value size is used for signaling
|
type NameValuePair struct {
|
||||||
// how many bytes are used to store the length/size.
|
// Making the length values 32 bit for ease.
|
||||||
// If the size is > 127, we can just use one byte,
|
// However, when encoding, the rules for
|
||||||
// and the high bit will be 0, otherwise, we use
|
// how many bytes are used will apply.
|
||||||
// four bytes and the high bit will be 1
|
NameLength uint32
|
||||||
|
ValueLength uint32
|
||||||
|
// Data
|
||||||
|
NameData string
|
||||||
|
ValueData string
|
||||||
|
}
|
||||||
|
|
||||||
func (client *FCGIClient) writePairs(recType FCGIRequestType, pairs map[string]string) error {
|
func (client *FCGIClient) writePairs(recType FCGIRequestType, pairs map[string]string) error {
|
||||||
w := newWriter(client, recType)
|
// Get ourselves a nice slice to work with
|
||||||
b := make([]byte, 8)
|
nvpairs := []NameValuePair{}
|
||||||
nn := 0
|
|
||||||
for k, v := range pairs {
|
for k, v := range pairs {
|
||||||
m := 8 + len(k) + len(v)
|
nvpairs = append(nvpairs, NameValuePair{
|
||||||
if m > maxWrite {
|
NameLength: uint32(len(k)),
|
||||||
// param data size exceed 65535 bytes"
|
ValueLength: uint32(len(v)),
|
||||||
vl := maxWrite - 8 - len(k)
|
NameData: k,
|
||||||
v = v[:vl]
|
ValueData: v,
|
||||||
}
|
})
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,16 +98,6 @@ func readString(s []byte, size uint32) string {
|
|||||||
return string(s[:size])
|
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
|
// bufWriter encapsulates bufio.Writer but also closes the underlying stream when
|
||||||
// Closed.
|
// Closed.
|
||||||
type bufWriter struct {
|
type bufWriter struct {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user