github.com/jackc/pgx/v5@v5.5.5/pgproto3/pgproto3.go (about) 1 package pgproto3 2 3 import ( 4 "encoding/hex" 5 "errors" 6 "fmt" 7 8 "github.com/jackc/pgx/v5/internal/pgio" 9 ) 10 11 // maxMessageBodyLen is the maximum length of a message body in bytes. See PG_LARGE_MESSAGE_LIMIT in the PostgreSQL 12 // source. It is defined as (MaxAllocSize - 1). MaxAllocSize is defined as 0x3fffffff. 13 const maxMessageBodyLen = (0x3fffffff - 1) 14 15 // Message is the interface implemented by an object that can decode and encode 16 // a particular PostgreSQL message. 17 type Message interface { 18 // Decode is allowed and expected to retain a reference to data after 19 // returning (unlike encoding.BinaryUnmarshaler). 20 Decode(data []byte) error 21 22 // Encode appends itself to dst and returns the new buffer. 23 Encode(dst []byte) ([]byte, error) 24 } 25 26 // FrontendMessage is a message sent by the frontend (i.e. the client). 27 type FrontendMessage interface { 28 Message 29 Frontend() // no-op method to distinguish frontend from backend methods 30 } 31 32 // BackendMessage is a message sent by the backend (i.e. the server). 33 type BackendMessage interface { 34 Message 35 Backend() // no-op method to distinguish frontend from backend methods 36 } 37 38 type AuthenticationResponseMessage interface { 39 BackendMessage 40 AuthenticationResponse() // no-op method to distinguish authentication responses 41 } 42 43 type invalidMessageLenErr struct { 44 messageType string 45 expectedLen int 46 actualLen int 47 } 48 49 func (e *invalidMessageLenErr) Error() string { 50 return fmt.Sprintf("%s body must have length of %d, but it is %d", e.messageType, e.expectedLen, e.actualLen) 51 } 52 53 type invalidMessageFormatErr struct { 54 messageType string 55 details string 56 } 57 58 func (e *invalidMessageFormatErr) Error() string { 59 return fmt.Sprintf("%s body is invalid %s", e.messageType, e.details) 60 } 61 62 type writeError struct { 63 err error 64 safeToRetry bool 65 } 66 67 func (e *writeError) Error() string { 68 return fmt.Sprintf("write failed: %s", e.err.Error()) 69 } 70 71 func (e *writeError) SafeToRetry() bool { 72 return e.safeToRetry 73 } 74 75 func (e *writeError) Unwrap() error { 76 return e.err 77 } 78 79 type ExceededMaxBodyLenErr struct { 80 MaxExpectedBodyLen int 81 ActualBodyLen int 82 } 83 84 func (e *ExceededMaxBodyLenErr) Error() string { 85 return fmt.Sprintf("invalid body length: expected at most %d, but got %d", e.MaxExpectedBodyLen, e.ActualBodyLen) 86 } 87 88 // getValueFromJSON gets the value from a protocol message representation in JSON. 89 func getValueFromJSON(v map[string]string) ([]byte, error) { 90 if v == nil { 91 return nil, nil 92 } 93 if text, ok := v["text"]; ok { 94 return []byte(text), nil 95 } 96 if binary, ok := v["binary"]; ok { 97 return hex.DecodeString(binary) 98 } 99 return nil, errors.New("unknown protocol representation") 100 } 101 102 // beginMessage begines a new message of type t. It appends the message type and a placeholder for the message length to 103 // dst. It returns the new buffer and the position of the message length placeholder. 104 func beginMessage(dst []byte, t byte) ([]byte, int) { 105 dst = append(dst, t) 106 sp := len(dst) 107 dst = pgio.AppendInt32(dst, -1) 108 return dst, sp 109 } 110 111 // finishMessage finishes a message that was started with beginMessage. It computes the message length and writes it to 112 // dst[sp]. If the message length is too large it returns an error. Otherwise it returns the final message buffer. 113 func finishMessage(dst []byte, sp int) ([]byte, error) { 114 messageBodyLen := len(dst[sp:]) 115 if messageBodyLen > maxMessageBodyLen { 116 return nil, errors.New("message body too large") 117 } 118 pgio.SetInt32(dst[sp:], int32(messageBodyLen)) 119 return dst, nil 120 }