1  
//
1  
//
2  
// Copyright (c) 2021 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2021 Vinnie Falco (vinnie.falco@gmail.com)
3  
// Copyright (c) 2024 Christian Mazakas
3  
// Copyright (c) 2024 Christian Mazakas
4  
//
4  
//
5  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
5  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
6  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7  
//
7  
//
8  
// Official repository: https://github.com/cppalliance/http
8  
// Official repository: https://github.com/cppalliance/http
9  
//
9  
//
10  

10  

11  
#include <boost/http/message_base.hpp>
11  
#include <boost/http/message_base.hpp>
12  
#include <boost/http/rfc/list_rule.hpp>
12  
#include <boost/http/rfc/list_rule.hpp>
13  
#include <boost/http/rfc/token_rule.hpp>
13  
#include <boost/http/rfc/token_rule.hpp>
14  
#include <boost/http/detail/except.hpp>
14  
#include <boost/http/detail/except.hpp>
15  
#include "detail/number_string.hpp"
15  
#include "detail/number_string.hpp"
16  
#include <boost/url/grammar/parse.hpp>
16  
#include <boost/url/grammar/parse.hpp>
17  
#include <boost/url/grammar/ci_string.hpp>
17  
#include <boost/url/grammar/ci_string.hpp>
18  

18  

19  
namespace boost {
19  
namespace boost {
20  
namespace http {
20  
namespace http {
21  

21  

22  
void
22  
void
23  
message_base::
23  
message_base::
24  
set_payload_size(
24  
set_payload_size(
25  
    std::uint64_t n)
25  
    std::uint64_t n)
26  
{
26  
{
27  
    //if(! is_head_response())
27  
    //if(! is_head_response())
28  
    if(true)
28  
    if(true)
29  
    {
29  
    {
30  
        // comes first for exception safety
30  
        // comes first for exception safety
31  
        set_content_length(n);
31  
        set_content_length(n);
32  

32  

33  
        set_chunked(false);
33  
        set_chunked(false);
34  
    }
34  
    }
35  
    else
35  
    else
36  
    {
36  
    {
37  
        // VFALCO ?
37  
        // VFALCO ?
38  
    }
38  
    }
39  
}
39  
}
40  

40  

41  
void
41  
void
42  
message_base::
42  
message_base::
43  
set_content_length(
43  
set_content_length(
44  
    std::uint64_t n)
44  
    std::uint64_t n)
45  
{
45  
{
46  
    set(field::content_length,
46  
    set(field::content_length,
47  
        detail::number_string(n));
47  
        detail::number_string(n));
48  
}
48  
}
49  

49  

50  
void
50  
void
51  
message_base::
51  
message_base::
52  
set_chunked(bool value)
52  
set_chunked(bool value)
53  
{
53  
{
54  
    if(value)
54  
    if(value)
55  
    {
55  
    {
56  
        // set chunked
56  
        // set chunked
57  
        if(! h_.md.transfer_encoding.is_chunked )
57  
        if(! h_.md.transfer_encoding.is_chunked )
58  
        {
58  
        {
59  
            append(
59  
            append(
60  
                field::transfer_encoding,
60  
                field::transfer_encoding,
61  
                "chunked");
61  
                "chunked");
62  
            return;
62  
            return;
63  
        }
63  
        }
64  
    }
64  
    }
65  
    else
65  
    else
66  
    {
66  
    {
67  
        // clear chunked
67  
        // clear chunked
68  
        // VFALCO ?
68  
        // VFALCO ?
69  
    }
69  
    }
70  
}
70  
}
71  

71  

72  
void
72  
void
73  
message_base::
73  
message_base::
74  
set_keep_alive(bool value)
74  
set_keep_alive(bool value)
75  
{
75  
{
76  
    if(h_.md.connection.ec)
76  
    if(h_.md.connection.ec)
77  
    {
77  
    {
78  
        // throw? return false?
78  
        // throw? return false?
79  
        return;
79  
        return;
80  
    }
80  
    }
81  

81  

82  
    if(h_.md.connection.count == 0)
82  
    if(h_.md.connection.count == 0)
83  
    {
83  
    {
84  
        // no Connection field
84  
        // no Connection field
85  
        switch(h_.version)
85  
        switch(h_.version)
86  
        {
86  
        {
87  
        default:
87  
        default:
88  
        case http::version::http_1_1:
88  
        case http::version::http_1_1:
89  
            if(! value)
89  
            if(! value)
90  
                set(field::connection, "close");
90  
                set(field::connection, "close");
91  
            break;
91  
            break;
92  

92  

93  
        case http::version::http_1_0:
93  
        case http::version::http_1_0:
94  
            if(value)
94  
            if(value)
95  
                set(field::connection, "keep-alive");
95  
                set(field::connection, "keep-alive");
96  
            break;
96  
            break;
97  
        }
97  
        }
98  
        return;
98  
        return;
99  
    }
99  
    }
100  

100  

101  
    // VFALCO TODO iterate in reverse order,
101  
    // VFALCO TODO iterate in reverse order,
102  
    // and cache the last iterator to use
102  
    // and cache the last iterator to use
103  
    // for appending
103  
    // for appending
104  

104  

105  
    // one or more Connection fields
105  
    // one or more Connection fields
106  
    auto it = begin();
106  
    auto it = begin();
107  
    auto const erase_token =
107  
    auto const erase_token =
108  
        [&](core::string_view token)
108  
        [&](core::string_view token)
109  
        {
109  
        {
110  
            while(it != end())
110  
            while(it != end())
111  
            {
111  
            {
112  
                if(it->id != field::connection)
112  
                if(it->id != field::connection)
113  
                {
113  
                {
114  
                    ++it;
114  
                    ++it;
115  
                    continue;
115  
                    continue;
116  
                }
116  
                }
117  
                auto rv = grammar::parse(
117  
                auto rv = grammar::parse(
118  
                    it->value,
118  
                    it->value,
119  
                    list_rule(token_rule, 1));
119  
                    list_rule(token_rule, 1));
120  
                BOOST_ASSERT(! rv.has_error());
120  
                BOOST_ASSERT(! rv.has_error());
121  
                BOOST_ASSERT(! rv->empty());
121  
                BOOST_ASSERT(! rv->empty());
122  
                auto itv = rv->begin();
122  
                auto itv = rv->begin();
123  
                if(urls::grammar::ci_is_equal(
123  
                if(urls::grammar::ci_is_equal(
124  
                    *itv, token))
124  
                    *itv, token))
125  
                {
125  
                {
126  
                    if(rv->size() == 1)
126  
                    if(rv->size() == 1)
127  
                    {
127  
                    {
128  
                        // only one token
128  
                        // only one token
129  
                        it = erase(it);
129  
                        it = erase(it);
130  
                    }
130  
                    }
131  
                    else
131  
                    else
132  
                    {
132  
                    {
133  
                        // first token matches
133  
                        // first token matches
134  
                        ++itv;
134  
                        ++itv;
135  
                        set(it,
135  
                        set(it,
136  
                            it->value.substr(
136  
                            it->value.substr(
137  
                                (*itv).data() -
137  
                                (*itv).data() -
138  
                                it->value.data()));
138  
                                it->value.data()));
139  
                        ++it;
139  
                        ++it;
140  
                    }
140  
                    }
141  
                    continue;
141  
                    continue;
142  
                }
142  
                }
143  
                // search remaining tokens
143  
                // search remaining tokens
144  
                std::string s = *itv++;
144  
                std::string s = *itv++;
145  
                while(itv != rv->end())
145  
                while(itv != rv->end())
146  
                {
146  
                {
147  
                    if(! urls::grammar::ci_is_equal(
147  
                    if(! urls::grammar::ci_is_equal(
148  
                        *itv, token))
148  
                        *itv, token))
149  
                        s += ", " + std::string(*itv);
149  
                        s += ", " + std::string(*itv);
150  
                    ++itv;
150  
                    ++itv;
151  
                }
151  
                }
152  
                set(it, s);
152  
                set(it, s);
153  
                ++it;
153  
                ++it;
154  
            }
154  
            }
155  
        };
155  
        };
156  
    if(value)
156  
    if(value)
157  
    {
157  
    {
158  
        if(h_.md.connection.close)
158  
        if(h_.md.connection.close)
159  
            erase_token("close");
159  
            erase_token("close");
160  
    }
160  
    }
161  
    else
161  
    else
162  
    {
162  
    {
163  
        if(h_.md.connection.keep_alive)
163  
        if(h_.md.connection.keep_alive)
164  
            erase_token("keep-alive");
164  
            erase_token("keep-alive");
165  
    }
165  
    }
166  
    switch(h_.version)
166  
    switch(h_.version)
167  
    {
167  
    {
168  
    default:
168  
    default:
169  
    case http::version::http_1_1:
169  
    case http::version::http_1_1:
170  
        if(! value)
170  
        if(! value)
171  
        {
171  
        {
172  
            // add one "close" token if needed
172  
            // add one "close" token if needed
173  
            if(! h_.md.connection.close)
173  
            if(! h_.md.connection.close)
174  
                append(field::connection, "close");
174  
                append(field::connection, "close");
175  
        }
175  
        }
176  
        break;
176  
        break;
177  

177  

178  
    case http::version::http_1_0:
178  
    case http::version::http_1_0:
179  
        if(value)
179  
        if(value)
180  
        {
180  
        {
181  
            // add one "keep-alive" token if needed
181  
            // add one "keep-alive" token if needed
182  
            if(! h_.md.connection.keep_alive)
182  
            if(! h_.md.connection.keep_alive)
183  
                append(field::connection, "keep-alive");
183  
                append(field::connection, "keep-alive");
184  
        }
184  
        }
185  
        break;
185  
        break;
186  
    }
186  
    }
187  
}
187  
}
188  

188  

189  
} // http
189  
} // http
190  
} // boost
190  
} // boost