• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PowerDNS / pdns / 17468346531

04 Sep 2025 03:08PM UTC coverage: 65.858% (-0.1%) from 65.97%
17468346531

Pull #16040

github

web-flow
Merge d7e69d5eb into 858e581ad
Pull Request #16040: rest api: better report ill-formed zone data

42107 of 92548 branches covered (45.5%)

Branch coverage included in aggregate %.

25 of 29 new or added lines in 1 file covered. (86.21%)

1653 existing lines in 28 files now uncovered.

128067 of 165849 relevant lines covered (77.22%)

5792596.38 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

61.6
/ext/yahttp/yahttp/router.cpp
1
/* @file
2
 * @brief Concrete implementation of Router 
3
 */
4
#include "yahttp.hpp"
5
#include "router.hpp"
6

7
namespace YaHTTP {
8
  // router is defined here.
9
  YaHTTP::Router Router::router;
10

11
  void Router::map(const std::string& method, const std::string& url, THandlerFunction handler, const std::string& name) {
519✔
12
    std::string method2 = method;
519✔
13
    bool isopen=false;
519✔
14
    // add into vector
15
    for(std::string::const_iterator i = url.begin(); i != url.end(); i++) {
20,021✔
16
       if (*i == '<' && isopen) throw Error("Invalid URL mask, cannot have < after <");
19,502!
17
       if (*i == '<') isopen = true;
19,502✔
18
       if (*i == '>' && !isopen) throw Error("Invalid URL mask, cannot have > without < first");
19,502!
19
       if (*i == '>') isopen = false;
19,502✔
20
    }
19,502✔
21
    std::transform(method2.begin(), method2.end(), method2.begin(), ::toupper); 
519✔
22
    routes.push_back(funcptr::make_tuple(method2, url, handler, name));
519✔
23
  };
519✔
24

25
  bool Router::match(const std::string& route, const URL& requrl, std::map<std::string, TDelim> &params) {
39,840✔
26
     size_t rpos = 0;
39,840✔
27
     size_t upos = 0;
39,840✔
28
     size_t npos = 0;
39,840✔
29
     size_t nstart = 0;
39,840✔
30
     size_t nend = 0;
39,840✔
31
     std::string pname;
39,840✔
32
     for(; rpos < route.size() && upos < requrl.path.size(); ) {
1,134,706✔
33
        if (route[rpos] == '<') {
1,116,652✔
34
          nstart = upos;
8,776✔
35
          npos = rpos+1;
8,776✔
36
          // start of parameter
37
          while(rpos < route.size() && route[rpos] != '>') {
38,052!
38
            rpos++;
29,276✔
39
          }
29,276✔
40
          pname = std::string(route.begin()+static_cast<long>(npos), route.begin()+static_cast<long>(rpos));
8,776✔
41
          // then we also look it on the url
42
          if (pname[0] == '*') {
8,776✔
43
            pname = pname.substr(1);
1,153✔
44
            // this matches whatever comes after it, basically end of string
45
            nend = requrl.path.size();
1,153✔
46
            if (!pname.empty()) {
1,153!
47
              params[pname] = funcptr::tie(nstart,nend);
1,153✔
48
            }
1,153✔
49
            rpos = route.size();
1,153✔
50
            upos = requrl.path.size();
1,153✔
51
            break;
1,153✔
52
          }
1,153✔
53
          // match until url[upos] or next / if pattern is at end
54
          while (upos < requrl.path.size()) {
169,101✔
55
            if (route[rpos+1] == '\0' && requrl.path[upos] == '/') {
162,711!
UNCOV
56
              break;
×
UNCOV
57
            }
×
58
            if (requrl.path[upos] == route[rpos+1]) {
162,711✔
59
              break;
1,233✔
60
            }
1,233✔
61
            upos++;
161,478✔
62
          }
161,478✔
63
          nend = upos;
7,623✔
64
          params[pname] = funcptr::tie(nstart, nend);
7,623✔
65
          if (upos > 0) {
7,623!
66
            upos--;
7,623✔
67
          }
7,623✔
68
          else {
×
69
            // If upos is zero, do not decrement it and then increment at bottom of loop, this disturbs Coverity.
70
            // Only increment rpos and continue loop
71
            rpos++;
×
72
            continue;
×
73
          }
×
74
        }
7,623✔
75
        else if (route[rpos] != requrl.path[upos]) {
1,107,876✔
76
          break;
20,633✔
77
        }
20,633✔
78

79
        rpos++; upos++;
1,094,866✔
80
      }
1,094,866✔
81
      return route[rpos] == requrl.path[upos];
39,840✔
82
  }
39,840✔
83

84
  RoutingResult Router::route(Request *req, THandlerFunction& handler) {
1,162✔
85
    std::map<std::string, TDelim> params;
1,162✔
86
    bool matched = false;
1,162✔
87
    bool seen = false;
1,162✔
88
    std::string rname;
1,162✔
89

90
    // iterate routes
91
    for (auto& route: routes) {
39,264✔
92
      std::string method;
39,264✔
93
      std::string url;
39,264✔
94
      funcptr::tie(method, url, handler, rname) = route;
39,264✔
95

96
      // see if we can't match the url
97
      params.clear();
39,264✔
98
      // simple matcher func
99
      matched = match(url, req->url, params);
39,264✔
100

101
      if (matched && !method.empty() && req->method != method) {
39,264✔
102
         // method did not match, record it though so we can return correct result
103
         matched = false;
2,131✔
104
         // The OPTIONS handler registered in pdns/webserver.cc matches every
105
         // url, and would cause "not found" errors to always be superseded
106
         // with "found, but wrong method" errors, so don't pretend there has
107
         // been a match in this case.
108
         if (method != "OPTIONS") {
2,131✔
109
           seen = true;
990✔
110
         }
990✔
111
         continue;
2,131✔
112
      }
2,131✔
113
      if (matched) {
37,133✔
114
        break;
1,159✔
115
      }
1,159✔
116
    }
37,133✔
117

118
    if (!matched) {
1,162✔
119
      if (seen) {
3!
UNCOV
120
        return RouteNoMethod;
×
UNCOV
121
      }
×
122
      // no route
123
      return RouteNotFound;
3✔
124
    }
3✔
125

126
    req->parameters.clear();
1,159✔
127

128
    for (const auto& param: params) {
1,159✔
129
      int nstart = 0;
636✔
130
      int nend = 0;
636✔
131
      funcptr::tie(nstart, nend) = param.second;
636✔
132
      std::string value(req->url.path.begin() + nstart, req->url.path.begin() + nend);
636✔
133
      value = Utility::decodeURL(value);
636✔
134
      req->parameters[param.first] = std::move(value);
636✔
135
    }
636✔
136

137
    req->routeName = std::move(rname);
1,159✔
138

139
    return RouteFound;
1,159✔
140
  };
1,162✔
141

142
  void Router::printRoutes(std::ostream &os) {
×
143
    for(TRouteList::iterator i = routes.begin(); i != routes.end(); i++) {
×
144
#if __cplusplus >= 201103L
×
145
      std::streamsize ss = os.width();
×
146
      std::ios::fmtflags ff = os.setf(std::ios::left);
×
147
      os.width(10);
×
148
      os << std::get<0>(*i);
×
UNCOV
149
      os.width(50);
×
UNCOV
150
      os << std::get<1>(*i);
×
UNCOV
151
      os.width(ss);
×
152
      os.setf(ff);
×
153
      os << "    " << std::get<3>(*i);
×
UNCOV
154
      os << std::endl;
×
155
#else
156
      os << i->get<0>() << "    " << i->get<1>() << "    " << i->get<3>() << std::endl;
157
#endif
158
    } 
×
UNCOV
159
  };
×
160

161
  std::pair<std::string,std::string> Router::urlFor(const std::string &name, const strstr_map_t& arguments) {
×
162
    std::ostringstream path;
×
163
    std::string mask,method,result;
×
UNCOV
164
    int k1,k2,k3;
×
165

UNCOV
166
    bool found = false;
×
167
    for(TRouteList::iterator i = routes.begin(); !found && i != routes.end(); i++) {
×
UNCOV
168
#if __cplusplus >= 201103L
×
169
      if (std::get<3>(*i) == name) { mask = std::get<1>(*i); method = std::get<0>(*i); found = true; }
×
170
#else
171
      if (i->get<3>() == name) { mask = i->get<1>(); method = i->get<0>(); found = true; }
172
#endif
173
    }
×
174

175
    if (!found)
×
176
      throw Error("Route not found");
×
177

178
    for(k1=0,k3=0;k1<static_cast<int>(mask.size());k1++) {
×
179
      if (mask[k1] == '<') {
×
180
        std::string pname;
×
181
        strstr_map_t::const_iterator pptr;
×
182
        k2=k1;
×
183
        while(k1<static_cast<int>(mask.size()) && mask[k1]!='>') k1++;
×
184
        path << mask.substr(k3,k2-k3);
×
185
        if (mask[k2+1] == '*')
×
186
          pname = std::string(mask.begin() + k2 + 2, mask.begin() + k1);
×
187
        else 
×
UNCOV
188
          pname = std::string(mask.begin() + k2 + 1, mask.begin() + k1);
×
189
        if ((pptr = arguments.find(pname)) != arguments.end()) 
×
190
          path << Utility::encodeURL(pptr->second);
×
191
        k3 = k1+1;
×
192
      }
×
193
      else if (mask[k1] == '*') {
×
194
        // ready 
195
        k3++;
×
196
        continue;
×
UNCOV
197
      }
×
UNCOV
198
    }
×
UNCOV
199
    path << mask.substr(k3);
×
UNCOV
200
    result = path.str();
×
UNCOV
201
    return std::make_pair(method, result);
×
UNCOV
202
  }
×
203
};
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc