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

CrowCpp / Crow / 846

16 Nov 2025 05:22PM UTC coverage: 87.239% (-0.3%) from 87.521%
846

Pull #1116

gh-actions

web-flow
Merge 6fbd19f5d into ae2172b82
Pull Request #1116: bugfix for errors on asio::write on do_sync_write()

10 of 23 new or added lines in 1 file covered. (43.48%)

7 existing lines in 2 files now uncovered.

4129 of 4733 relevant lines covered (87.24%)

136.1 hits per line

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

93.68
/include/crow/parser.h
1
#pragma once
2

3
#include <string>
4
#include <unordered_map>
5
#include <algorithm>
6

7
#include "crow/http_request.h"
8
#include "crow/http_parser_merged.h"
9

10
namespace crow
11
{
12
    /// A wrapper for `nodejs/http-parser`.
13

14
    ///
15
    /// Used to generate a \ref crow.request from the TCP socket buffer.
16
    template<typename Handler>
17
    struct HTTPParser : public http_parser
18
    {
19
        static int on_message_begin(http_parser*)
86✔
20
        {
21
            return 0;
86✔
22
        }
23
        static int on_method(http_parser* self_)
272✔
24
        {
25
            HTTPParser* self = static_cast<HTTPParser*>(self_);
272✔
26
            self->req.method = static_cast<HTTPMethod>(self->method);
272✔
27

28
            return 0;
272✔
29
        }
30
        static int on_url(http_parser* self_, const char* at, size_t length)
84✔
31
        {
32
            HTTPParser* self = static_cast<HTTPParser*>(self_);
84✔
33
            self->req.raw_url.insert(self->req.raw_url.end(), at, at + length);
84✔
34
            self->req.url_params = query_string(self->req.raw_url);
84✔
35
            self->req.url = self->req.raw_url.substr(0, self->qs_point != 0 ? self->qs_point : std::string::npos);
84✔
36

37
            self->process_url();
84✔
38

39
            return 0;
84✔
40
        }
41
        static int on_header_field(http_parser* self_, const char* at, size_t length)
104✔
42
        {
43
            HTTPParser* self = static_cast<HTTPParser*>(self_);
104✔
44
            switch (self->header_building_state)
104✔
45
            {
46
                case 0:
104✔
47
                    if (!self->header_value.empty())
104✔
48
                    {
49
                        self->req.headers.emplace(std::move(self->header_field), std::move(self->header_value));
51✔
50
                    }
51
                    self->header_field.assign(at, at + length);
104✔
52
                    self->header_building_state = 1;
104✔
53
                    break;
104✔
UNCOV
54
                case 1:
×
UNCOV
55
                    self->header_field.insert(self->header_field.end(), at, at + length);
×
UNCOV
56
                    break;
×
57
            }
58
            return 0;
104✔
59
        }
60
        static int on_header_value(http_parser* self_, const char* at, size_t length)
104✔
61
        {
62
            HTTPParser* self = static_cast<HTTPParser*>(self_);
104✔
63
            switch (self->header_building_state)
104✔
64
            {
UNCOV
65
                case 0:
×
UNCOV
66
                    self->header_value.insert(self->header_value.end(), at, at + length);
×
UNCOV
67
                    break;
×
68
                case 1:
104✔
69
                    self->header_building_state = 0;
104✔
70
                    self->header_value.assign(at, at + length);
104✔
71
                    break;
104✔
72
            }
73
            return 0;
104✔
74
        }
75
        static int on_headers_complete(http_parser* self_)
81✔
76
        {
77
            HTTPParser* self = static_cast<HTTPParser*>(self_);
81✔
78
            if (!self->header_field.empty())
81✔
79
            {
80
                self->req.headers.emplace(std::move(self->header_field), std::move(self->header_value));
53✔
81
            }
82

83
            self->set_connection_parameters();
81✔
84

85
            self->process_header();
81✔
86
            return 0;
81✔
87
        }
88
        static int on_body(http_parser* self_, const char* at, size_t length)
3✔
89
        {
90
            HTTPParser* self = static_cast<HTTPParser*>(self_);
3✔
91
            self->req.body.insert(self->req.body.end(), at, at + length);
3✔
92
            return 0;
3✔
93
        }
94
        static int on_message_complete(http_parser* self_)
81✔
95
        {
96
            HTTPParser* self = static_cast<HTTPParser*>(self_);
81✔
97

98
            self->message_complete = true;
81✔
99
            self->process_message();
81✔
100
            return 0;
81✔
101
        }
102
        HTTPParser(Handler* handler):
103✔
103
          http_parser(),
104
          handler_(handler)
103✔
105
        {
106
            http_parser_init(this);
103✔
107
        }
103✔
108

109
        // return false on error
110
        /// Parse a buffer into the different sections of an HTTP request.
111
        bool feed(const char* buffer, int length)
156✔
112
        {
113
            if (message_complete)
156✔
114
                return true;
9✔
115

116
            const static http_parser_settings settings_{
117
              on_message_begin,
118
              on_method,
119
              on_url,
120
              on_header_field,
121
              on_header_value,
122
              on_headers_complete,
123
              on_body,
124
              on_message_complete,
125
            };
126

127
            int nparsed = http_parser_execute(this, &settings_, buffer, length);
147✔
128
            if (http_errno != CHPE_OK)
147✔
129
            {
130
                return false;
13✔
131
            }
132
            return nparsed == length;
134✔
133
        }
134

135
        bool done()
68✔
136
        {
137
            return feed(nullptr, 0);
68✔
138
        }
139

140
        void clear()
221✔
141
        {
142
            req = crow::request();
221✔
143
            header_field.clear();
221✔
144
            header_value.clear();
221✔
145
            header_building_state = 0;
221✔
146
            qs_point = 0;
221✔
147
            message_complete = false;
221✔
148
            state = CROW_NEW_MESSAGE();
221✔
149
        }
221✔
150

151
        inline void process_url()
84✔
152
        {
153
            handler_->handle_url();
84✔
154
        }
84✔
155

156
        inline void process_header()
81✔
157
        {
158
            handler_->handle_header();
81✔
159
        }
81✔
160

161
        inline void process_message()
81✔
162
        {
163
            handler_->handle();
81✔
164
        }
81✔
165

166
        inline void set_connection_parameters()
81✔
167
        {
168
            req.http_ver_major = http_major;
81✔
169
            req.http_ver_minor = http_minor;
81✔
170

171
            //NOTE(EDev): it seems that the problem is with crow's policy on closing the connection for HTTP_VERSION < 1.0, the behaviour for that in crow is "don't close the connection, but don't send a keep-alive either"
172

173
            // HTTP1.1 = always send keep_alive, HTTP1.0 = only send if header exists, HTTP?.? = never send
174
            req.keep_alive = (http_major == 1 && http_minor == 0) ?
155✔
175
                               ((flags & F_CONNECTION_KEEP_ALIVE) ? true : false) :
7✔
176
                               ((http_major == 1 && http_minor == 1) ? true : false);
74✔
177

178
            // HTTP1.1 = only close if close header exists, HTTP1.0 = always close unless keep_alive header exists, HTTP?.?= never close
179
            req.close_connection = (http_major == 1 && http_minor == 0) ?
155✔
180
                                     ((flags & F_CONNECTION_KEEP_ALIVE) ? false : true) :
7✔
181
                                     ((http_major == 1 && http_minor == 1) ? ((flags & F_CONNECTION_CLOSE) ? true : false) : false);
74✔
182
            req.upgrade = static_cast<bool>(upgrade);
81✔
183
        }
81✔
184

185
        /// The final request that this parser outputs.
186
        ///
187
        /// Data parsed is put directly into this object as soon as the related callback returns. (e.g. the request will have the cooorect method as soon as on_method() returns)
188
        request req;
189

190
    private:
191
        int header_building_state = 0;
192
        bool message_complete = false;
193
        std::string header_field;
194
        std::string header_value;
195

196
        Handler* handler_; ///< This is currently an HTTP connection object (\ref crow.Connection).
197
    };
198
} // namespace crow
199

200
#undef CROW_NEW_MESSAGE
201
#undef CROW_start_state
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