|
@@ -0,0 +1,168 @@
|
|
|
+package ajp13
|
|
|
+
|
|
|
+import (
|
|
|
+ "encoding/binary"
|
|
|
+ "fmt"
|
|
|
+ "net"
|
|
|
+ "reflect"
|
|
|
+)
|
|
|
+
|
|
|
+// ForwardRequest marks that this request is an actual request
|
|
|
+const ForwardRequest = 2
|
|
|
+
|
|
|
+// Shutdown marks that this is a shutdown request
|
|
|
+const Shutdown = 7
|
|
|
+
|
|
|
+// Ping marks that this is a ping request
|
|
|
+const Ping = 8
|
|
|
+
|
|
|
+// CPing marks that this is a cping request
|
|
|
+const CPing = 10
|
|
|
+
|
|
|
+// AJP13 represents the apache java protocol
|
|
|
+type AJP13 struct {
|
|
|
+ len uint16
|
|
|
+ Type uint8
|
|
|
+ method HTTPMethod
|
|
|
+ Version string // e.g. HTTP/1.1
|
|
|
+ URI string
|
|
|
+ RemoteAddr net.IP
|
|
|
+ RemoteHost string
|
|
|
+ Server string
|
|
|
+ Port uint16
|
|
|
+ SSL bool
|
|
|
+ headers map[string]string
|
|
|
+}
|
|
|
+
|
|
|
+// Parse takes a []byte payload and builds
|
|
|
+func Parse(payload []byte) (*AJP13, error) {
|
|
|
+ if !reflect.DeepEqual(payload[0:2], []byte{0x12, 0x34}) {
|
|
|
+ return nil, fmt.Errorf("The magic signature is not 0x12 0x34 but %v", payload[0:2])
|
|
|
+ }
|
|
|
+
|
|
|
+ a := &AJP13{}
|
|
|
+
|
|
|
+ // the data length
|
|
|
+ a.len = binary.BigEndian.Uint16(payload[2:4])
|
|
|
+
|
|
|
+ data := payload[4 : a.len+4]
|
|
|
+
|
|
|
+ // the request type
|
|
|
+ a.Type = uint8(data[0])
|
|
|
+
|
|
|
+ switch a.Type {
|
|
|
+ case ForwardRequest:
|
|
|
+ a.parseForwardRequest(data)
|
|
|
+ }
|
|
|
+
|
|
|
+ return a, nil
|
|
|
+}
|
|
|
+
|
|
|
+func (a *AJP13) parseForwardRequest(data []byte) {
|
|
|
+
|
|
|
+ // Method
|
|
|
+ a.method = HTTPMethod(uint8(data[1]))
|
|
|
+
|
|
|
+ offset := uint16(2)
|
|
|
+
|
|
|
+ // Version
|
|
|
+ if !reflect.DeepEqual(data[offset:offset+2], []byte{0xff, 0xff}) {
|
|
|
+ versionLen := binary.BigEndian.Uint16(data[offset : offset+2])
|
|
|
+ a.Version = string(data[offset+2 : offset+2+versionLen])
|
|
|
+ offset += versionLen + 1
|
|
|
+ }
|
|
|
+ offset += 2
|
|
|
+
|
|
|
+ // URI
|
|
|
+ if !reflect.DeepEqual(data[offset:offset+2], []byte{0xff, 0xff}) {
|
|
|
+ uriLen := binary.BigEndian.Uint16(data[offset : offset+2])
|
|
|
+ a.URI = string(data[offset+2 : offset+2+uriLen])
|
|
|
+ offset += uriLen + 1
|
|
|
+ }
|
|
|
+ offset += 2
|
|
|
+
|
|
|
+ // RemoteAddr
|
|
|
+ if !reflect.DeepEqual(data[offset:offset+2], []byte{0xff, 0xff}) {
|
|
|
+ raddrLen := binary.BigEndian.Uint16(data[offset : offset+2])
|
|
|
+ a.RemoteAddr = net.ParseIP(string(data[offset+2 : offset+2+raddrLen]))
|
|
|
+ offset += raddrLen + 1
|
|
|
+ }
|
|
|
+ offset += 2
|
|
|
+
|
|
|
+ // RemoteHost
|
|
|
+ if !reflect.DeepEqual(data[offset:offset+2], []byte{0xff, 0xff}) {
|
|
|
+ rhostLen := binary.BigEndian.Uint16(data[offset : offset+2])
|
|
|
+ a.RemoteHost = string(data[offset+2 : offset+2+rhostLen])
|
|
|
+ offset += rhostLen + 1
|
|
|
+ }
|
|
|
+ offset += 2
|
|
|
+
|
|
|
+ // Server
|
|
|
+ if !reflect.DeepEqual(data[offset:offset+2], []byte{0xff, 0xff}) {
|
|
|
+ len := binary.BigEndian.Uint16(data[offset : offset+2])
|
|
|
+ a.Server = string(data[offset+2 : offset+2+len])
|
|
|
+ offset += len + 1
|
|
|
+ }
|
|
|
+ offset += 2
|
|
|
+
|
|
|
+ // Port
|
|
|
+ a.Port = binary.BigEndian.Uint16(data[offset : offset+2])
|
|
|
+
|
|
|
+ offset += 2
|
|
|
+
|
|
|
+ // SSL
|
|
|
+ if data[offset] == 0x1 {
|
|
|
+ a.SSL = true
|
|
|
+ }
|
|
|
+
|
|
|
+ offset++
|
|
|
+
|
|
|
+ // Headers
|
|
|
+ numHeaders := binary.BigEndian.Uint16(data[offset : offset+2])
|
|
|
+ offset += 2
|
|
|
+
|
|
|
+ headers := make(map[string]string)
|
|
|
+
|
|
|
+ for idx := uint16(0); idx < numHeaders; idx++ {
|
|
|
+ if data[offset] == 0xa0 { // encoded header name
|
|
|
+ len := binary.BigEndian.Uint16(data[offset+2 : offset+4])
|
|
|
+ hdrName := HTTPHeader(binary.BigEndian.Uint16(data[offset : offset+2])).String()
|
|
|
+ if hdrName != "UNKNOWN" {
|
|
|
+ headers[hdrName] = string(data[offset+4 : offset+4+len])
|
|
|
+ }
|
|
|
+ offset = offset + 5 + len
|
|
|
+ } else { // plain text header name
|
|
|
+ length := binary.BigEndian.Uint16(data[offset : offset+2])
|
|
|
+ key := string(data[offset+2 : offset+2+length])
|
|
|
+
|
|
|
+ offset = offset + 3 + length
|
|
|
+
|
|
|
+ length = binary.BigEndian.Uint16(data[offset : offset+2])
|
|
|
+ val := string(data[offset+2 : offset+2+length])
|
|
|
+ headers[key] = val
|
|
|
+
|
|
|
+ offset = offset + 3 + length
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ a.headers = headers
|
|
|
+
|
|
|
+ // don't need Attributes for the time being
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+// Length returns the length of the data this AJP13 request consists of
|
|
|
+func (a *AJP13) Length() uint16 {
|
|
|
+ return a.len
|
|
|
+}
|
|
|
+
|
|
|
+// Method returns the name of the method used
|
|
|
+func (a *AJP13) Method() string {
|
|
|
+ return a.method.String()
|
|
|
+}
|
|
|
+
|
|
|
+// Header returns the header value refered to by key
|
|
|
+func (a *AJP13) Header(key string) (string, bool) {
|
|
|
+ val, ok := a.headers[key]
|
|
|
+ return val, ok
|
|
|
+}
|