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

View File

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