1/* 2 * Copyright (c) 2014 IBM Corp. 3 * 4 * All rights reserved. This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License v1.0 6 * which accompanies this distribution, and is available at 7 * http://www.eclipse.org/legal/epl-v10.html 8 * 9 * Contributors: 10 * Seth Hoenig 11 * Allan Stockdill-Mander 12 * Mike Robertson 13 */ 14 15package mqtt 16 17import ( 18 "errors" 19 "strings" 20) 21 22//ErrInvalidQos is the error returned when an packet is to be sent 23//with an invalid Qos value 24var ErrInvalidQos = errors.New("Invalid QoS") 25 26//ErrInvalidTopicEmptyString is the error returned when a topic string 27//is passed in that is 0 length 28var ErrInvalidTopicEmptyString = errors.New("Invalid Topic; empty string") 29 30//ErrInvalidTopicMultilevel is the error returned when a topic string 31//is passed in that has the multi level wildcard in any position but 32//the last 33var ErrInvalidTopicMultilevel = errors.New("Invalid Topic; multi-level wildcard must be last level") 34 35// Topic Names and Topic Filters 36// The MQTT v3.1.1 spec clarifies a number of ambiguities with regard 37// to the validity of Topic strings. 38// - A Topic must be between 1 and 65535 bytes. 39// - A Topic is case sensitive. 40// - A Topic may contain whitespace. 41// - A Topic containing a leading forward slash is different than a Topic without. 42// - A Topic may be "/" (two levels, both empty string). 43// - A Topic must be UTF-8 encoded. 44// - A Topic may contain any number of levels. 45// - A Topic may contain an empty level (two forward slashes in a row). 46// - A TopicName may not contain a wildcard. 47// - A TopicFilter may only have a # (multi-level) wildcard as the last level. 48// - A TopicFilter may contain any number of + (single-level) wildcards. 49// - A TopicFilter with a # will match the absense of a level 50// Example: a subscription to "foo/#" will match messages published to "foo". 51 52func validateSubscribeMap(subs map[string]byte) ([]string, []byte, error) { 53 var topics []string 54 var qoss []byte 55 for topic, qos := range subs { 56 if err := validateTopicAndQos(topic, qos); err != nil { 57 return nil, nil, err 58 } 59 topics = append(topics, topic) 60 qoss = append(qoss, qos) 61 } 62 63 return topics, qoss, nil 64} 65 66func validateTopicAndQos(topic string, qos byte) error { 67 if len(topic) == 0 { 68 return ErrInvalidTopicEmptyString 69 } 70 71 levels := strings.Split(topic, "/") 72 for i, level := range levels { 73 if level == "#" && i != len(levels)-1 { 74 return ErrInvalidTopicMultilevel 75 } 76 } 77 78 if qos < 0 || qos > 2 { 79 return ErrInvalidQos 80 } 81 return nil 82} 83