Coverage Report

Created: 2025-03-11 06:06

/src/brpc/src/brpc/uri.h
Line
Count
Source (jump to first uncovered line)
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
19
#ifndef  BRPC_URI_H
20
#define  BRPC_URI_H
21
22
#include <string>                   // std::string
23
#include "butil/containers/flat_map.h"
24
#include "butil/status.h"
25
#include "butil/string_splitter.h"
26
27
// To brpc developers: This is a class exposed to end-user. DON'T put impl.
28
// details in this header, use opaque pointers instead.
29
30
31
namespace brpc {
32
33
// The class for URI scheme : http://en.wikipedia.org/wiki/URI_scheme
34
//
35
//  foo://username:password@example.com:8042/over/there/index.dtb?type=animal&name=narwhal#nose
36
//  \_/   \_______________/ \_________/ \__/            \___/ \_/ \______________________/ \__/
37
//   |           |               |       |                |    |            |                |
38
//   |       userinfo           host    port              |    |          query          fragment
39
//   |    \________________________________/\_____________|____|/ \__/        \__/
40
// scheme                 |                          |    |    |    |          |
41
//                    authority                      |    |    |    |          |
42
//                                                 path   |    |    interpretable as keys
43
//                                                        |    |
44
//        \_______________________________________________|____|/       \____/     \_____/
45
//                             |                          |    |          |           |
46
//                     hierarchical part                  |    |    interpretable as values
47
//                                                        |    |
48
//                                   interpretable as filename |
49
//                                                             |
50
//                                                             |
51
//                                               interpretable as extension
52
class URI {
53
public:
54
    typedef butil::FlatMap<std::string, std::string> QueryMap;
55
    typedef QueryMap::const_iterator QueryIterator;
56
57
    // You can copy a URI.
58
    URI();
59
    ~URI();
60
61
    // Exchange internal fields with another URI.
62
    void Swap(URI &rhs);
63
64
    // Reset internal fields as if they're just default-constructed.
65
    void Clear(); 
66
67
    // Decompose `url' and set into corresponding fields.
68
    // heading and trailing spaces are allowed and skipped.
69
    // Returns 0 on success, -1 otherwise and status() is set.
70
    int SetHttpURL(const char* url);
71
11.1k
    int SetHttpURL(const std::string& url) { return SetHttpURL(url.c_str()); }
72
    // syntactic sugar of SetHttpURL
73
0
    void operator=(const char* url) { SetHttpURL(url); }
74
0
    void operator=(const std::string& url) { SetHttpURL(url); }
75
76
    // Status of previous SetHttpURL or opreator=.
77
0
    const butil::Status& status() const { return _st; }
78
79
    // Sub fields. Empty string if the field is not set.
80
0
  const std::string& scheme() const { return _scheme; }
81
0
    BAIDU_DEPRECATED const std::string& schema() const { return scheme(); }
82
15.3k
    const std::string& host() const { return _host; }
83
0
    int port() const { return _port; } // -1 on unset.
84
0
    const std::string& path() const { return _path; }
85
0
    const std::string& user_info() const { return _user_info; }
86
0
    const std::string& fragment() const { return _fragment; }
87
    // NOTE: This method is not thread-safe because it may re-generate the
88
    // query-string if SetQuery()/RemoveQuery() were successfully called.
89
    const std::string& query() const;
90
    // Put path?query#fragment into `h2_path'
91
    void GenerateH2Path(std::string* h2_path) const;
92
93
    // Overwrite parts of the URL.
94
    // NOTE: The input MUST be guaranteed to be valid.
95
0
    void set_scheme(const std::string& scheme) { _scheme = scheme; }
96
0
    BAIDU_DEPRECATED void set_schema(const std::string& s) { set_scheme(s); }
97
0
    void set_path(const std::string& path) { _path = path; }
98
0
    void set_host(const std::string& host) { _host = host; }
99
0
    void set_port(int port) { _port = port; }
100
    void SetHostAndPort(const std::string& host_and_optional_port);
101
    // Set path/query/fragment with the input in form of "path?query#fragment"
102
    void SetH2Path(const char* h2_path);
103
0
    void SetH2Path(const std::string& path) { SetH2Path(path.c_str()); }
104
    
105
    // Get the value of a CASE-SENSITIVE key.
106
    // Returns pointer to the value, NULL when the key does not exist.
107
    const std::string* GetQuery(const char* key) const
108
0
    { return get_query_map().seek(key); }
109
    const std::string* GetQuery(const std::string& key) const
110
0
    { return get_query_map().seek(key); }
111
112
    // Add key/value pair. Override existing value.
113
    void SetQuery(const std::string& key, const std::string& value);
114
115
    // Remove value associated with `key'.
116
    // Returns 1 on removed, 0 otherwise.
117
    size_t RemoveQuery(const char* key);
118
    size_t RemoveQuery(const std::string& key);
119
120
    // Get query iterators which are invalidated after calling SetQuery()
121
    // or SetHttpURL().
122
0
    QueryIterator QueryBegin() const { return get_query_map().begin(); }
123
0
    QueryIterator QueryEnd() const { return get_query_map().end(); }
124
    // #queries
125
0
    size_t QueryCount() const { return get_query_map().size(); }
126
127
    // Print this URI to the ostream.
128
    // PrintWithoutHost only prints components including and after path.
129
    void PrintWithoutHost(std::ostream& os) const;
130
    void Print(std::ostream& os) const;
131
132
private:
133
friend class HttpMessage;
134
135
    void InitializeQueryMap() const;
136
137
0
    QueryMap& get_query_map() const {
138
0
        if (!_initialized_query_map) {
139
0
            InitializeQueryMap();
140
0
        }
141
0
        return _query_map;
142
0
    }
143
144
    // Iterate _query_map and append all queries to `query'
145
    void AppendQueryString(std::string* query, bool append_question_mark) const;
146
147
    butil::Status                            _st;
148
    int                                     _port;
149
    mutable bool                            _query_was_modified;
150
    mutable bool                            _initialized_query_map;
151
    std::string                             _host;
152
    std::string                             _path;
153
    std::string                             _user_info;
154
    std::string                             _fragment;
155
    std::string                             _scheme;
156
    mutable std::string                     _query;
157
    mutable QueryMap _query_map;
158
};
159
160
// Parse host/port/scheme from `url' if the corresponding parameter is not NULL.
161
// Returns 0 on success, -1 otherwise.
162
int ParseURL(const char* url, std::string* scheme, std::string* host, int* port);
163
164
0
inline void URI::SetQuery(const std::string& key, const std::string& value) {
165
0
    get_query_map()[key] = value;
166
0
    _query_was_modified = true;
167
0
}
168
169
0
inline size_t URI::RemoveQuery(const char* key) {
170
0
    if (get_query_map().erase(key)) {
171
0
        _query_was_modified = true;
172
0
        return 1;
173
0
    }
174
0
    return 0;
175
0
}
176
177
0
inline size_t URI::RemoveQuery(const std::string& key) {
178
0
    if (get_query_map().erase(key)) {
179
0
        _query_was_modified = true;
180
0
        return 1;
181
0
    }
182
0
    return 0;
183
0
}
184
185
0
inline const std::string& URI::query() const {
186
0
    if (_initialized_query_map && _query_was_modified) {
187
0
        _query_was_modified = false;
188
0
        _query.clear();
189
0
        AppendQueryString(&_query, false);
190
0
    }
191
0
    return _query;
192
0
}
193
194
0
inline std::ostream& operator<<(std::ostream& os, const URI& uri) {
195
0
    uri.Print(os);
196
0
    return os;
197
0
}
198
199
// Split query in the format of "key1=value1&key2&key3=value3"
200
class QuerySplitter : public butil::KeyValuePairsSplitter {
201
public:
202
    inline QuerySplitter(const char* str_begin, const char* str_end)
203
0
        : KeyValuePairsSplitter(str_begin, str_end, '&', '=')
204
0
    {}
205
206
    inline QuerySplitter(const char* str_begin)
207
0
        : KeyValuePairsSplitter(str_begin, '&', '=')
208
0
    {}
209
210
    inline QuerySplitter(const butil::StringPiece &sp)
211
        : KeyValuePairsSplitter(sp, '&', '=')
212
0
    {}
213
};
214
215
// A class to remove some specific keys in a query string, 
216
// when removal is over, call modified_query() to get modified
217
// query.
218
class QueryRemover {
219
public:
220
    QueryRemover(const std::string* str);
221
222
0
    butil::StringPiece key() { return _qs.key();}
223
0
    butil::StringPiece value() { return _qs.value(); }
224
0
    butil::StringPiece key_and_value() { return _qs.key_and_value(); }
225
226
    // Move splitter forward.
227
    QueryRemover& operator++();
228
    QueryRemover operator++(int);
229
230
0
    operator const void*() const { return _qs; }
231
232
    // After this function is called, current query will be removed from
233
    // modified_query(), calling this function more than once has no effect.
234
    void remove_current_key_and_value();
235
 
236
    // Return the modified query string
237
    std::string modified_query();
238
239
private:
240
    const std::string* _query;
241
    QuerySplitter _qs;
242
    std::string _modified_query;
243
    size_t _iterated_len;
244
    bool _removed_current_key_value;
245
    bool _ever_removed;
246
};
247
248
// This function can append key and value to *query_string
249
// in consideration of all possible format of *query_string
250
// for example:
251
// "" -> "key=value"
252
// "key1=value1" -> "key1=value1&key=value"
253
// "/some/path?" -> "/some/path?key=value"
254
// "/some/path?key1=value1" -> "/some/path?key1=value1&key=value"
255
void append_query(std::string *query_string,
256
                  const butil::StringPiece& key,
257
                  const butil::StringPiece& value);
258
259
} // namespace brpc
260
261
262
#if __cplusplus < 201103L  // < C++11
263
#include <algorithm>  // std::swap until C++11
264
#else
265
#include <utility>  // std::swap since C++11
266
#endif  // __cplusplus < 201103L
267
268
namespace std {
269
template<>
270
0
inline void swap(brpc::URI &lhs, brpc::URI &rhs) {
271
0
    lhs.Swap(rhs);
272
0
}
273
}  // namespace std
274
275
#endif  //BRPC_URI_H