topic.go 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  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. package mqtt
  15. import (
  16. "errors"
  17. "strings"
  18. )
  19. //ErrInvalidQos is the error returned when an packet is to be sent
  20. //with an invalid Qos value
  21. var ErrInvalidQos = errors.New("Invalid QoS")
  22. //ErrInvalidTopicEmptyString is the error returned when a topic string
  23. //is passed in that is 0 length
  24. var ErrInvalidTopicEmptyString = errors.New("Invalid Topic; empty string")
  25. //ErrInvalidTopicMultilevel is the error returned when a topic string
  26. //is passed in that has the multi level wildcard in any position but
  27. //the last
  28. var ErrInvalidTopicMultilevel = errors.New("Invalid Topic; multi-level wildcard must be last level")
  29. // Topic Names and Topic Filters
  30. // The MQTT v3.1.1 spec clarifies a number of ambiguities with regard
  31. // to the validity of Topic strings.
  32. // - A Topic must be between 1 and 65535 bytes.
  33. // - A Topic is case sensitive.
  34. // - A Topic may contain whitespace.
  35. // - A Topic containing a leading forward slash is different than a Topic without.
  36. // - A Topic may be "/" (two levels, both empty string).
  37. // - A Topic must be UTF-8 encoded.
  38. // - A Topic may contain any number of levels.
  39. // - A Topic may contain an empty level (two forward slashes in a row).
  40. // - A TopicName may not contain a wildcard.
  41. // - A TopicFilter may only have a # (multi-level) wildcard as the last level.
  42. // - A TopicFilter may contain any number of + (single-level) wildcards.
  43. // - A TopicFilter with a # will match the absense of a level
  44. // Example: a subscription to "foo/#" will match messages published to "foo".
  45. func validateSubscribeMap(subs map[string]byte) ([]string, []byte, error) {
  46. var topics []string
  47. var qoss []byte
  48. for topic, qos := range subs {
  49. if err := validateTopicAndQos(topic, qos); err != nil {
  50. return nil, nil, err
  51. }
  52. topics = append(topics, topic)
  53. qoss = append(qoss, qos)
  54. }
  55. return topics, qoss, nil
  56. }
  57. func validateTopicAndQos(topic string, qos byte) error {
  58. if len(topic) == 0 {
  59. return ErrInvalidTopicEmptyString
  60. }
  61. levels := strings.Split(topic, "/")
  62. for i, level := range levels {
  63. if level == "#" && i != len(levels)-1 {
  64. return ErrInvalidTopicMultilevel
  65. }
  66. }
  67. if qos < 0 || qos > 2 {
  68. return ErrInvalidQos
  69. }
  70. return nil
  71. }