1// Copyright (C) MongoDB, Inc. 2017-present. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); you may 4// not use this file except in compliance with the License. You may obtain 5// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 7package wiremessage 8 9import ( 10 "fmt" 11) 12 13// ErrInvalidHeader is returned when methods are called on a malformed Header. 14var ErrInvalidHeader error = Error{Type: ErrHeader, Message: "invalid header"} 15 16// ErrHeaderTooSmall is returned when the size of the header is too small to be valid. 17var ErrHeaderTooSmall error = Error{Type: ErrHeader, Message: "the header is too small to be valid"} 18 19// ErrHeaderTooFewBytes is returned when a call to ReadHeader does not contain enough 20// bytes to be a valid header. 21var ErrHeaderTooFewBytes error = Error{Type: ErrHeader, Message: "invalid header because []byte too small"} 22 23// ErrHeaderInvalidLength is returned when the MessageLength of a header is 24// set but is not set to the correct size. 25var ErrHeaderInvalidLength error = Error{Type: ErrHeader, Message: "invalid header because MessageLength is imporperly set"} 26 27// ErrHeaderIncorrectOpCode is returned when the OpCode on a header is set but 28// is not set to the correct OpCode. 29var ErrHeaderIncorrectOpCode error = Error{Type: ErrHeader, Message: "invalid header because OpCode is improperly set"} 30 31// Header represents the header of a MongoDB wire protocol message. 32type Header struct { 33 MessageLength int32 34 RequestID int32 35 ResponseTo int32 36 OpCode OpCode 37} 38 39// ReadHeader reads a header from the given slice of bytes starting at offset 40// pos. 41func ReadHeader(b []byte, pos int32) (Header, error) { 42 if len(b) < 16 { 43 return Header{}, ErrHeaderTooFewBytes 44 } 45 return Header{ 46 MessageLength: readInt32(b, 0), 47 RequestID: readInt32(b, 4), 48 ResponseTo: readInt32(b, 8), 49 OpCode: OpCode(readInt32(b, 12)), 50 }, nil 51} 52 53func (h Header) String() string { 54 return fmt.Sprintf( 55 `Header{MessageLength: %d, RequestID: %d, ResponseTo: %d, OpCode: %v}`, 56 h.MessageLength, h.RequestID, h.ResponseTo, h.OpCode, 57 ) 58} 59 60// AppendHeader will append this header to the given slice of bytes. 61func (h Header) AppendHeader(b []byte) []byte { 62 b = appendInt32(b, h.MessageLength) 63 b = appendInt32(b, h.RequestID) 64 b = appendInt32(b, h.ResponseTo) 65 b = appendInt32(b, int32(h.OpCode)) 66 67 return b 68} 69 70// SetDefaults sets the length and opcode of this header. 71func (h *Header) SetDefaults(length int, opcode OpCode) error { 72 switch h.MessageLength { 73 case int32(length): 74 case 0: 75 h.MessageLength = int32(length) 76 default: 77 return ErrHeaderInvalidLength 78 } 79 switch h.OpCode { 80 case opcode: 81 case OpCode(0): 82 h.OpCode = opcode 83 default: 84 return ErrHeaderIncorrectOpCode 85 } 86 return nil 87} 88