summaryrefslogtreecommitdiff
path: root/graphics/asymptote/LspCpp/third_party/uri/src/detail/uri_parse_authority.cpp
blob: 29b7de7f6897b87fcf6d39e44c5dae8dabe00ca8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// Copyright 2016 Glyn Matthews.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

#include "uri_parse_authority.hpp"
#include <cstdlib>
#include <iterator>
#include <limits>
#include "grammar.hpp"

namespace network {
namespace detail {
namespace {
enum class authority_state { user_info, host, host_ipv6, port };
}  // namespace

bool parse_authority(string_view::const_iterator &it,
                     string_view::const_iterator last,
                     optional<uri_part> &user_info, optional<uri_part> &host,
                     optional<uri_part> &port) {
  auto first = it;

  auto state = authority_state::user_info;
  while (it != last) {
    if (state == authority_state::user_info) {
      if (is_in(first, last, "@:")) {
        return false;
      }

      if (*it == '@') {
        user_info = uri_part(first, it);
        state = authority_state::host;
        ++it;
        first = it;
        continue;
      } else if (*it == '[') {
        // this is an IPv6 address
        state = authority_state::host_ipv6;
        first = it;
        continue;
      } else if (*it == ':') {
        // this is actually the host, and the next part is expected to be the
        // port
        host = uri_part(first, it);
        state = authority_state::port;
        ++it;
        first = it;
        continue;
      }
    } else if (state == authority_state::host) {
      if (*first == ':') {
        return false;
      }

      if (*it == ':') {
        host = uri_part(first, it);
        state = authority_state::port;
        ++it;
        first = it;
        continue;
      }
    } else if (state == authority_state::host_ipv6) {
      if (*first != '[') {
        return false;
      }

      if (*it == ']') {
        host = uri_part(first, it);
        ++it;
        // Then test if the next part is a host, part, or the end of the file
        if (it == last) {
          break;
        } else if (*it == ':') {
          host = uri_part(first, it);
          state = authority_state::port;
          ++it;
          first = it;
        }
      }
    } else if (state == authority_state::port) {
      if (*first == '/') {
        // the port is empty, but valid
        port = uri_part(first, it);
        if (!is_valid_port(std::begin(*port))) {
          return false;
        }

        continue;
      }

      if (!isdigit(it, last)) {
        return false;
      }
    }

    ++it;
  }

  if (state == authority_state::user_info) {
    host = uri_part(first, last);
  } else if (state == authority_state::host) {
    host = uri_part(first, last);
  } else if (state == authority_state::host_ipv6) {
    host = uri_part(first, last);
  } else if (state == authority_state::port) {
    port = uri_part(first, last);
    if (!is_valid_port(std::begin(*port))) {
      return false;
    }
  }

  return true;
}
}  // namespace detail
}  // namespace network