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

PowerDNS / pdns / 12595591960

03 Jan 2025 09:27AM UTC coverage: 62.774% (+2.5%) from 60.245%
12595591960

Pull #15008

github

web-flow
Merge c2a2749d3 into 788f396a7
Pull Request #15008: Do not follow CNAME records for ANY or CNAME queries

30393 of 78644 branches covered (38.65%)

Branch coverage included in aggregate %.

105822 of 138350 relevant lines covered (76.49%)

4613078.44 hits per line

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

59.83
/ext/yahttp/yahttp/reqresp.hpp
1
#if __cplusplus >= 201103L
2
#include <functional>
3
#define HAVE_CPP_FUNC_PTR
4
namespace funcptr = std;
5
#else
6
#ifdef HAVE_BOOST
7
#include <boost/function.hpp>
8
namespace funcptr = boost;
9
#define HAVE_CPP_FUNC_PTR
10
#endif
11
#endif
12

13
#include <fstream>
14
#include <cctype>
15

16
#ifndef WIN32
17
#include <cstdio>
18
#include <unistd.h>
19
#endif
20

21
#include <algorithm>
22

23
#ifndef YAHTTP_MAX_REQUEST_SIZE
24
#define YAHTTP_MAX_REQUEST_SIZE 2097152
3,093✔
25
#endif
26

27
#ifndef YAHTTP_MAX_RESPONSE_SIZE
28
#define YAHTTP_MAX_RESPONSE_SIZE 2097152
3,093✔
29
#endif
30

31
#define YAHTTP_TYPE_REQUEST 1
4,215✔
32
#define YAHTTP_TYPE_RESPONSE 2
2,830✔
33

34
namespace YaHTTP {
35
  typedef std::map<std::string,Cookie,ASCIICINullSafeComparator> strcookie_map_t; //<! String to Cookie map
36

37
  typedef enum {
38
    urlencoded,
39
    multipart
40
  } postformat_t; //<! Enumeration of possible post encodings, url encoding or multipart
41

42
  /*! Base class for request and response */
43
  class HTTPBase {
44
  public:
45
    /*! Default renderer for request/response, simply copies body to response */
46
    class SendBodyRender {
47
    public:
48
      SendBodyRender() {};
3,093✔
49

50
      size_t operator()(const HTTPBase *doc, std::ostream& os, bool chunked) const {
608✔
51
        if (chunked) {
608✔
52
          std::string::size_type i,cl;
314✔
53
          for(i=0;i<doc->body.length();i+=1024) {
2,046✔
54
            cl = std::min(static_cast<std::string::size_type>(1024), doc->body.length()-i); // for less than 1k blocks
1,732✔
55
            os << std::hex << cl << std::dec << "\r\n";
1,732✔
56
            os << doc->body.substr(i, cl) << "\r\n";
1,732✔
57
          }
1,732✔
58
          os << 0 << "\r\n\r\n"; // last chunk
314✔
59
        } else {
608✔
60
          os << doc->body;
294✔
61
        }
294✔
62
        return doc->body.length();
608✔
63
      }; //<! writes body to ostream and returns length 
608✔
64
    };
65
    /* Simple sendfile renderer which streams file to ostream */
66
    class SendFileRender {
67
    public:
68
      SendFileRender(const std::string& path_) {
×
69
        this->path = path_;
×
70
      };
×
71
  
72
      size_t operator()(const HTTPBase *doc __attribute__((unused)), std::ostream& os, bool chunked) const {
×
73
        char buf[4096];
×
74
        size_t n,k;
×
75
#if __cplusplus >= 201103L
×
76
        std::ifstream ifs(path, std::ifstream::binary);
×
77
#else
×
78
        std::ifstream ifs(path.c_str(), std::ifstream::binary);
×
79
#endif
×
80
        n = 0;
×
81

×
82
        while(ifs.good()) {
×
83
          ifs.read(buf, sizeof buf);
×
84
          n += (k = ifs.gcount());
×
85
          if (k > 0) {
×
86
            if (chunked) os << std::hex << k << std::dec << "\r\n";
×
87
            os.write(buf, k);
×
88
            if (chunked) os << "\r\n"; 
×
89
          }
×
90
        }
×
91
        if (chunked) os << 0 << "\r\n\r\n";
×
92
        return n;
×
93
      }; //<! writes file to ostream and returns length
×
94

95
      std::string path; //<! File to send
96
    };
97

98
    HTTPBase() {
1,242✔
99
      HTTPBase::initialize();
1,242✔
100
    };
1,242✔
101
    virtual ~HTTPBase() = default;
1,266✔
102

103
    virtual void initialize() {
3,093✔
104
      kind = 0;
3,093✔
105
      status = 0;
3,093✔
106
#ifdef HAVE_CPP_FUNC_PTR
3,093✔
107
      renderer = SendBodyRender();
3,093✔
108
#endif
3,093✔
109
      max_request_size = YAHTTP_MAX_REQUEST_SIZE;
3,093✔
110
      max_response_size = YAHTTP_MAX_RESPONSE_SIZE;
3,093✔
111
      url = "";
3,093✔
112
      method = "";
3,093✔
113
      statusText = "";
3,093✔
114
      jar.clear();
3,093✔
115
      headers.clear();
3,093✔
116
      parameters.clear();
3,093✔
117
      getvars.clear();
3,093✔
118
      postvars.clear();
3,093✔
119
      body = "";
3,093✔
120
      routeName = "";
3,093✔
121
      version = 11; // default to version 1.1
3,093✔
122
      is_multipart = false;
3,093✔
123
    }
3,093✔
124
protected:
125
    HTTPBase(const HTTPBase& rhs) {
25✔
126
      this->url = rhs.url; this->kind = rhs.kind;
25✔
127
      this->status = rhs.status; this->statusText = rhs.statusText;
25✔
128
      this->method = rhs.method; this->headers = rhs.headers;
25✔
129
      this->jar = rhs.jar; this->postvars = rhs.postvars;
25✔
130
      this->parameters = rhs.parameters; this->getvars = rhs.getvars;
25✔
131
      this->body = rhs.body; this->max_request_size = rhs.max_request_size;
25✔
132
      this->max_response_size = rhs.max_response_size; this->version = rhs.version;
25✔
133
#ifdef HAVE_CPP_FUNC_PTR
25✔
134
      this->renderer = rhs.renderer;
25✔
135
#endif
25✔
136
      this->is_multipart = rhs.is_multipart;
25✔
137
    };
25✔
138
    virtual HTTPBase& operator=(const HTTPBase& rhs) {
25✔
139
      this->url = rhs.url; this->kind = rhs.kind;
25✔
140
      this->status = rhs.status; this->statusText = rhs.statusText;
25✔
141
      this->method = rhs.method; this->headers = rhs.headers;
25✔
142
      this->jar = rhs.jar; this->postvars = rhs.postvars;
25✔
143
      this->parameters = rhs.parameters; this->getvars = rhs.getvars;
25✔
144
      this->body = rhs.body; this->max_request_size = rhs.max_request_size;
25✔
145
      this->max_response_size = rhs.max_response_size; this->version = rhs.version;
25✔
146
#ifdef HAVE_CPP_FUNC_PTR
25✔
147
      this->renderer = rhs.renderer;
25✔
148
#endif
25✔
149
      this->is_multipart = rhs.is_multipart;
25✔
150
      return *this;
25✔
151
    };
25✔
152
public:
153
    URL url; //<! URL of this request/response
154
    int kind; //<! Type of object (1 = request, 2 = response)
155
    int status; //<! status code 
156
    int version; //<! http version 9 = 0.9, 10 = 1.0, 11 = 1.1
157
    std::string statusText; //<! textual representation of status code
158
    std::string method; //<! http verb
159
    strstr_map_t headers; //<! map of header(s)
160
    CookieJar jar; //<! cookies 
161
    strstr_map_t postvars; //<! map of POST variables (from POST body)
162
    strstr_map_t getvars; //<! map of GET variables (from URL)
163
// these two are for Router
164
    strstr_map_t parameters; //<! map of route parameters (only if you use YaHTTP::Router)
165
    std::string routeName; //<! name of the current route (only if you use YaHTTP::Router)
166

167
    std::string body; //<! the actual content
168

169
    ssize_t max_request_size; //<! maximum size of request
170
    ssize_t max_response_size;  //<! maximum size of response
171
    bool is_multipart; //<! if the request is multipart, prevents Content-Length header
172
#ifdef HAVE_CPP_FUNC_PTR
173
    funcptr::function<size_t(const HTTPBase*,std::ostream&,bool)> renderer; //<! rendering function
174
#endif
175
    void write(std::ostream& os) const; //<! writes request to the given output stream
176

177
    strstr_map_t& GET() { return getvars; }; //<! acccessor for getvars
178
    strstr_map_t& POST() { return postvars; }; //<! accessor for postvars
179
    strcookie_map_t& COOKIES() { return jar.cookies; }; //<! accessor for cookies
×
180

181
    std::string versionStr(int version_) const {
773✔
182
      switch(version_) {
773✔
183
      case  9: return "0.9";
×
184
      case 10: return "1.0";
1✔
185
      case 11: return "1.1";
772✔
186
      default: throw YaHTTP::Error("Unsupported version");
×
187
      }
773✔
188
    };
773✔
189

190
    std::string str() const {
×
191
       std::ostringstream oss;
×
192
       write(oss);
×
193
       return oss.str();
×
194
    }; //<! return string representation of this object
×
195
  };
196

197
  /*! Response class, represents a HTTP Response document */
198
  class Response: public HTTPBase { 
199
  public:
200
    Response() { Response::initialize(); };
633✔
201
    Response(const HTTPBase& rhs): HTTPBase(rhs) {
×
202
      this->kind = YAHTTP_TYPE_RESPONSE;
×
203
    };
×
204
    Response& operator=(const HTTPBase& rhs) override {
×
205
      HTTPBase::operator=(rhs);
×
206
      this->kind = YAHTTP_TYPE_RESPONSE;
×
207
      return *this;
×
208
    };
×
209
    void initialize() override {
762✔
210
      HTTPBase::initialize();
762✔
211
      this->kind = YAHTTP_TYPE_RESPONSE;
762✔
212
    }
762✔
213
    void initialize(const HTTPBase& rhs) {
×
214
      HTTPBase::initialize();
×
215
      this->kind = YAHTTP_TYPE_RESPONSE;
×
216
      // copy SOME attributes
×
217
      this->url = rhs.url;
×
218
      this->method = rhs.method;
×
219
      this->jar = rhs.jar;
×
220
      this->version = rhs.version;
×
221
    }
×
222
    friend std::ostream& operator<<(std::ostream& os, const Response &resp);
223
    friend std::istream& operator>>(std::istream& is, Response &resp);
224
  };
225

226
  /* Request class, represents a HTTP Request document */
227
  class Request: public HTTPBase {
228
  public:
229
    Request() { Request::initialize(); };
609✔
230
    Request(const HTTPBase& rhs): HTTPBase(rhs) {
×
231
      this->kind = YAHTTP_TYPE_REQUEST;
×
232
    };
×
233
    Request& operator=(const HTTPBase& rhs) override {
×
234
      HTTPBase::operator=(rhs);
×
235
      this->kind = YAHTTP_TYPE_REQUEST;
×
236
      return *this;
×
237
    };
×
238
    void initialize() override {
1,089✔
239
      HTTPBase::initialize();
1,089✔
240
      this->kind = YAHTTP_TYPE_REQUEST;
1,089✔
241
    }
1,089✔
242
    void initialize(const HTTPBase& rhs) {
×
243
      HTTPBase::initialize();
×
244
      this->kind = YAHTTP_TYPE_REQUEST;
×
245
      // copy SOME attributes
×
246
      this->url = rhs.url;
×
247
      this->method = rhs.method;
×
248
      this->jar = rhs.jar;
×
249
      this->version = rhs.version;
×
250
    }
×
251
    void setup(const std::string& method_, const std::string& url_) {
252
      this->url.parse(url_);
253
      this->headers["host"] = this->url.host.find(":") == std::string::npos ? this->url.host : "[" + this->url.host + "]";
254
      this->method = method_;
255
      std::transform(this->method.begin(), this->method.end(), this->method.begin(), ::toupper);
256
      this->headers["user-agent"] = "YaHTTP v1.0";
257
    }; //<! Set some initial things for a request
258

259
    void preparePost(postformat_t format = urlencoded) {
260
      std::ostringstream postbuf;
261
      if (format == urlencoded) {
262
        for(strstr_map_t::const_iterator i = POST().begin(); i != POST().end(); i++) {
263
          postbuf << Utility::encodeURL(i->first, false) << "=" << Utility::encodeURL(i->second, false) << "&";
264
        }
265
        // remove last bit
266
        if (postbuf.str().length()>0) 
267
          body = postbuf.str().substr(0, postbuf.str().length()-1);
268
        else
269
          body = "";
270
        headers["content-type"] = "application/x-www-form-urlencoded; charset=utf-8";
271
      } else if (format == multipart) {
272
        headers["content-type"] = "multipart/form-data; boundary=YaHTTP-12ca543";
273
        this->is_multipart = true;
274
        for(strstr_map_t::const_iterator i = POST().begin(); i != POST().end(); i++) {
275
          postbuf << "--YaHTTP-12ca543\r\nContent-Disposition: form-data; name=\"" << Utility::encodeURL(i->first, false) << "\"; charset=UTF-8\r\nContent-Length: " << i->second.size() << "\r\n\r\n"
276
            << Utility::encodeURL(i->second, false) << "\r\n";
277
        }
278
        postbuf << "--";
279
        body = postbuf.str();
280
      }
281

282
      postbuf.str("");
283
      postbuf << body.length();
284
      // set method and change headers
285
      method = "POST";
286
      if (!this->is_multipart)
287
        headers["content-length"] = postbuf.str();
288
    }; //<! convert all postvars into string and stuff it into body
289

290
    friend std::ostream& operator<<(std::ostream& os, const Request &resp);
291
    friend std::istream& operator>>(std::istream& is, Request &resp);
292
  };
293

294
  /*! Asynchronous HTTP document loader */
295
  template <class T>
296
  class AsyncLoader {
297
  public:
298
    T* target; //<! target to populate
299
    int state; //<! reader state
300
    size_t pos; //<! reader position
301
    
302
    std::string buffer; //<! read buffer 
303
    bool chunked; //<! whether we are parsing chunked data
304
    int chunk_size; //<! expected size of next chunk
305
    std::ostringstream bodybuf; //<! buffer for body
306
    size_t maxbody; //<! maximum size of body
307
    size_t minbody; //<! minimum size of body
308
    bool hasBody; //<! are we expecting body
309

310
    void keyValuePair(const std::string &keyvalue, std::string &key, std::string &value); //<! key value pair parser helper
311

312
    void initialize(T* target_) {
924✔
313
      chunked = false; chunk_size = 0;
924✔
314
      bodybuf.str(""); minbody = 0; maxbody = 0;
924✔
315
      pos = 0; state = 0; this->target = target_;
924✔
316
      hasBody = false;
924✔
317
      buffer = "";
924✔
318
      this->target->initialize();
924✔
319
    }; //<! Initialize the parser for target and clear state
924✔
320
    bool feed(const std::string& somedata); //<! Feed data to the parser
321
    bool ready() {
1,709✔
322
     return (chunked == true && state == 3) || // if it's chunked we get end of data indication
1,709!
323
             (chunked == false && state > 1 &&  
1,709!
324
               (!hasBody || 
1,709!
325
                 (bodybuf.str().size() <= maxbody && 
1,532!
326
                  bodybuf.str().size() >= minbody)
808!
327
               )
1,532✔
328
             ); 
1,709✔
329
    }; //<! whether we have received enough data
1,709✔
330
    void finalize() {
922✔
331
      bodybuf.flush();
922✔
332
      if (ready()) {
922!
333
        strstr_map_t::iterator cpos = target->headers.find("content-type");
874✔
334
        if (cpos != target->headers.end() && Utility::iequals(cpos->second, "application/x-www-form-urlencoded", 32)) {
874!
335
          target->postvars = Utility::parseUrlParameters(bodybuf.str());
×
336
        }
×
337
        target->body = bodybuf.str();
874✔
338
      }
874✔
339
      bodybuf.str("");
922✔
340
      this->target = NULL;
922✔
341
    }; //<! finalize and release target
922✔
342
  };
343

344
  /*! Asynchronous HTTP response loader */
345
  class AsyncResponseLoader: public AsyncLoader<Response> {
346
  };
347

348
  /*! Asynchronous HTTP request loader */
349
  class AsyncRequestLoader: public AsyncLoader<Request> {
350
  };
351

352
};
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

© 2025 Coveralls, Inc