Avi Drissman | 6459548 | 2022-09-14 20:52:29 | [diff] [blame] | 1 | // Copyright 2016 The Chromium Authors |
eroman | 94e42f5 | 2016-03-23 22:07:08 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #ifndef NET_BASE_PARSE_NUMBER_H_ |
| 6 | #define NET_BASE_PARSE_NUMBER_H_ |
| 7 | |
Bruno Pitrus | 6bbf6b0 | 2023-04-11 19:32:13 | [diff] [blame] | 8 | #include <cstdint> |
David Benjamin | 506122dc | 2023-11-07 01:32:18 | [diff] [blame] | 9 | #include <string_view> |
Bruno Pitrus | 6bbf6b0 | 2023-04-11 19:32:13 | [diff] [blame] | 10 | |
eroman | 94e42f5 | 2016-03-23 22:07:08 | [diff] [blame] | 11 | #include "net/base/net_export.h" |
| 12 | |
| 13 | // This file contains utility functions for parsing numbers, in the context of |
| 14 | // network protocols. |
| 15 | // |
| 16 | // Q: Doesn't //base already provide these in string_number_conversions.h, with |
| 17 | // functions like base::StringToInt()? |
| 18 | // |
eroman | ae40d9ba | 2016-04-11 18:40:26 | [diff] [blame] | 19 | // A: Yes, and those functions are used under the hood by these implementations. |
eroman | 94e42f5 | 2016-03-23 22:07:08 | [diff] [blame] | 20 | // |
eroman | ae40d9ba | 2016-04-11 18:40:26 | [diff] [blame] | 21 | // However using the base::StringTo*() has historically led to subtle bugs |
| 22 | // in the context of parsing network protocols: |
eroman | 94e42f5 | 2016-03-23 22:07:08 | [diff] [blame] | 23 | // |
eroman | ae40d9ba | 2016-04-11 18:40:26 | [diff] [blame] | 24 | // * Permitting a leading '+' |
| 25 | // * Incorrectly classifying overflow/underflow from a parsing failure |
| 26 | // * Allowing negative numbers for non-negative fields |
eroman | 94e42f5 | 2016-03-23 22:07:08 | [diff] [blame] | 27 | // |
eroman | ae40d9ba | 2016-04-11 18:40:26 | [diff] [blame] | 28 | // This API tries to avoid these problems by picking sensible defaults for |
| 29 | // //net code. For more details see crbug.com/596523. |
eroman | 94e42f5 | 2016-03-23 22:07:08 | [diff] [blame] | 30 | |
eroman | 94e42f5 | 2016-03-23 22:07:08 | [diff] [blame] | 31 | namespace net { |
| 32 | |
eroman | ae40d9ba | 2016-04-11 18:40:26 | [diff] [blame] | 33 | // Format to use when parsing integers. |
| 34 | enum class ParseIntFormat { |
| 35 | // Accepts non-negative base 10 integers of the form: |
| 36 | // |
| 37 | // 1*DIGIT |
| 38 | // |
| 39 | // This construction is used in a variety of IETF standards, such as RFC 7230 |
| 40 | // (HTTP). |
| 41 | // |
| 42 | // When attempting to parse a negative number using this format, the failure |
| 43 | // will be FAILED_PARSE since it violated the expected format (and not |
| 44 | // FAILED_UNDERFLOW). |
| 45 | // |
| 46 | // Also note that inputs need not be in minimal encoding: "0003" is valid and |
| 47 | // equivalent to "3". |
| 48 | NON_NEGATIVE, |
| 49 | |
| 50 | // Accept optionally negative base 10 integers of the form: |
| 51 | // |
| 52 | // ["-"] 1*DIGIT |
| 53 | // |
| 54 | // In other words, this accepts the same things as NON_NEGATIVE, and |
| 55 | // additionally recognizes those numbers prefixed with a '-'. |
| 56 | // |
Matt Menke | d80a12e | 2023-03-22 16:57:26 | [diff] [blame] | 57 | // Note that by this definition "-0" IS a valid input. |
| 58 | OPTIONALLY_NEGATIVE, |
| 59 | |
| 60 | // Like NON_NEGATIVE, but rejects anything not in minimal encoding - that is, |
| 61 | // it rejects anything with leading 0's, except "0". |
| 62 | STRICT_NON_NEGATIVE, |
| 63 | |
| 64 | // Like OPTIONALLY_NEGATIVE, but rejects anything not in minimal encoding - |
| 65 | // that is, it rejects "-0" and anything with leading 0's, except "0". |
| 66 | STRICT_OPTIONALLY_NEGATIVE, |
eroman | ae40d9ba | 2016-04-11 18:40:26 | [diff] [blame] | 67 | }; |
| 68 | |
| 69 | // The specific reason why a ParseInt*() function failed. |
| 70 | enum class ParseIntError { |
| 71 | // The parsed number couldn't fit into the provided output type because it was |
| 72 | // too high. |
| 73 | FAILED_OVERFLOW, |
| 74 | |
| 75 | // The parsed number couldn't fit into the provided output type because it was |
| 76 | // too low. |
| 77 | FAILED_UNDERFLOW, |
| 78 | |
| 79 | // The number failed to be parsed because it wasn't a valid decimal number (as |
| 80 | // determined by the policy). |
| 81 | FAILED_PARSE, |
| 82 | }; |
| 83 | |
| 84 | // The ParseInt*() functions parse a string representing a number. |
eroman | 94e42f5 | 2016-03-23 22:07:08 | [diff] [blame] | 85 | // |
eroman | ae40d9ba | 2016-04-11 18:40:26 | [diff] [blame] | 86 | // The format of the strings that are accepted is controlled by the |format| |
| 87 | // parameter. This allows rejecting negative numbers. |
eroman | 94e42f5 | 2016-03-23 22:07:08 | [diff] [blame] | 88 | // |
eroman | ae40d9ba | 2016-04-11 18:40:26 | [diff] [blame] | 89 | // These functions return true on success, and fill |*output| with the result. |
eroman | 94e42f5 | 2016-03-23 22:07:08 | [diff] [blame] | 90 | // |
eroman | ae40d9ba | 2016-04-11 18:40:26 | [diff] [blame] | 91 | // On failure, it is guaranteed that |*output| was not modified. If |
| 92 | // |optional_error| was non-null, then it is filled with the reason for the |
| 93 | // failure. |
Daniel Cheng | 76bb1e00 | 2022-01-14 01:34:42 | [diff] [blame] | 94 | [[nodiscard]] NET_EXPORT bool ParseInt32( |
David Benjamin | 506122dc | 2023-11-07 01:32:18 | [diff] [blame] | 95 | std::string_view input, |
Daniel Cheng | 76bb1e00 | 2022-01-14 01:34:42 | [diff] [blame] | 96 | ParseIntFormat format, |
| 97 | int32_t* output, |
| 98 | ParseIntError* optional_error = nullptr); |
eroman | ae40d9ba | 2016-04-11 18:40:26 | [diff] [blame] | 99 | |
Daniel Cheng | 76bb1e00 | 2022-01-14 01:34:42 | [diff] [blame] | 100 | [[nodiscard]] NET_EXPORT bool ParseInt64( |
David Benjamin | 506122dc | 2023-11-07 01:32:18 | [diff] [blame] | 101 | std::string_view input, |
Daniel Cheng | 76bb1e00 | 2022-01-14 01:34:42 | [diff] [blame] | 102 | ParseIntFormat format, |
| 103 | int64_t* output, |
| 104 | ParseIntError* optional_error = nullptr); |
eroman | ae40d9ba | 2016-04-11 18:40:26 | [diff] [blame] | 105 | |
| 106 | // The ParseUint*() functions parse a string representing a number. |
eroman | 94e42f5 | 2016-03-23 22:07:08 | [diff] [blame] | 107 | // |
Matt Menke | d80a12e | 2023-03-22 16:57:26 | [diff] [blame] | 108 | // These are equivalent to calling ParseInt*(), except with unsigned output |
Qingxin Wu | 430b87e0 | 2023-04-10 18:04:59 | [diff] [blame] | 109 | // types. ParseIntFormat may only be one of {NON_NEGATIVE, STRICT_NON_NEGATIVE}. |
Daniel Cheng | 76bb1e00 | 2022-01-14 01:34:42 | [diff] [blame] | 110 | [[nodiscard]] NET_EXPORT bool ParseUint32( |
David Benjamin | 506122dc | 2023-11-07 01:32:18 | [diff] [blame] | 111 | std::string_view input, |
Matt Menke | d80a12e | 2023-03-22 16:57:26 | [diff] [blame] | 112 | ParseIntFormat format, |
Daniel Cheng | 76bb1e00 | 2022-01-14 01:34:42 | [diff] [blame] | 113 | uint32_t* output, |
| 114 | ParseIntError* optional_error = nullptr); |
eroman | ae40d9ba | 2016-04-11 18:40:26 | [diff] [blame] | 115 | |
Daniel Cheng | 76bb1e00 | 2022-01-14 01:34:42 | [diff] [blame] | 116 | [[nodiscard]] NET_EXPORT bool ParseUint64( |
David Benjamin | 506122dc | 2023-11-07 01:32:18 | [diff] [blame] | 117 | std::string_view input, |
Matt Menke | d80a12e | 2023-03-22 16:57:26 | [diff] [blame] | 118 | ParseIntFormat format, |
Daniel Cheng | 76bb1e00 | 2022-01-14 01:34:42 | [diff] [blame] | 119 | uint64_t* output, |
| 120 | ParseIntError* optional_error = nullptr); |
eroman | 94e42f5 | 2016-03-23 22:07:08 | [diff] [blame] | 121 | |
| 122 | } // namespace net |
| 123 | |
| 124 | #endif // NET_BASE_PARSE_NUMBER_H_ |