The bits are finaggled

This commit is contained in:
Javier Feliz 2024-12-27 00:49:40 -05:00
parent ce0f9fcfc4
commit 10d8e5bf42
2 changed files with 75 additions and 42 deletions

View File

@ -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
}

View File

@ -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 {