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]) if len(payload) < int(a.len+4) { return nil, fmt.Errorf("The payload should be %d bytes long is actually only %d bytes long", a.len+4, len(payload)) } data := payload[4 : a.len+4] // the request type a.Type = uint8(data[0]) var err error switch a.Type { case ForwardRequest: err = a.parseForwardRequest(data) if err != nil { return nil, err } } return a, nil } func checkLength(data []byte, minLen int, location string) error { dataLen := len(data) if dataLen < minLen { return fmt.Errorf("%s: need %d bytes but have %d", location, minLen, dataLen) } return nil } func (a *AJP13) parseForwardRequest(data []byte) error { // 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]) if err := checkLength(data, int(offset+2+versionLen+1), "parseForwardRequest/Version"); err != nil { return err } 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]) if err := checkLength(data, int(offset+2+uriLen+1), "parseForwardRequest/URI"); err != nil { return err } 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]) if err := checkLength(data, int(offset+2+raddrLen+1), "parseForwardRequest/RemoteAddr"); err != nil { return err } 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]) if err := checkLength(data, int(offset+2+rhostLen+1), "parseForwardRequest/RemoteHost"); err != nil { return err } 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]) if err := checkLength(data, int(offset+2+len+1), "parseForwardRequest/Server"); err != nil { return err } 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 return nil } // 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 } // Headers returns all headers func (a *AJP13) Headers() map[string]string { return a.headers }