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