blob: ad1c2912e48b422ece90582a56522b2e56a00db6 [file] [log] [blame]
Don Newton379ae252019-04-01 12:17:06 -04001// 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}