Coverage Report

Created: 2024-09-11 06:42

/src/brpc/src/brpc/http_header.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_HTTP_HEADER_H
20
#define  BRPC_HTTP_HEADER_H
21
22
#include <vector>
23
#include "butil/strings/string_piece.h"  // StringPiece
24
#include "butil/containers/case_ignored_flat_map.h"
25
#include "brpc/uri.h"              // URI
26
#include "brpc/http_method.h"      // HttpMethod
27
#include "brpc/http_status_code.h"
28
#include "brpc/http2.h"
29
30
// To rpc developers: DON'T put impl. details here, use opaque pointers instead.
31
32
33
namespace brpc {
34
class InputMessageBase;
35
namespace policy {
36
void ProcessHttpRequest(InputMessageBase *msg);
37
class H2StreamContext;
38
}
39
40
// Non-body part of a HTTP message.
41
class HttpHeader {
42
public:
43
    typedef butil::CaseIgnoredMultiFlatMap<std::string> HeaderMap;
44
    typedef HeaderMap::const_iterator HeaderIterator;
45
    typedef HeaderMap::key_equal HeaderKeyEqual;
46
47
    HttpHeader();
48
49
    // Exchange internal fields with another HttpHeader.
50
    void Swap(HttpHeader &rhs);
51
52
    // Reset internal fields as if they're just default-constructed.
53
    void Clear();
54
55
    // Get http version, 1.1 by default.
56
5.46k
    int major_version() const { return _version.first; }
57
5.46k
    int minor_version() const { return _version.second; }
58
    // Change the http version
59
    void set_version(int http_major, int http_minor)
60
15.1k
    { _version = std::make_pair(http_major, http_minor); }
61
62
    // True if version of http is earlier than 1.1
63
    bool before_http_1_1() const
64
5.46k
    { return (major_version() * 10000 +  minor_version()) <= 10000; }
65
66
    // True if the message is from HTTP2.
67
0
    bool is_http2() const { return major_version() == 2; }
68
69
    // Get/set "Content-Type".
70
    // possible values: "text/plain", "application/json" ...
71
    // NOTE: Equal to `GetHeader("Content-Type")', ·SetHeader("Content-Type")‘ (case-insensitive).
72
0
    const std::string& content_type() const { return _content_type; }
73
0
    void set_content_type(const std::string& type) { _content_type = type; }
74
0
    void set_content_type(const char* type) { _content_type = type; }
75
0
    std::string& mutable_content_type() { return _content_type; }
76
    
77
    // Get value of a header which is case-insensitive according to:
78
    //   https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
79
    // Namely, GetHeader("log-id"), GetHeader("Log-Id"), GetHeader("LOG-ID")
80
    // point to the same value.
81
    // Return pointer to the value, NULL on not found.
82
    // NOTE: If the key is "Content-Type", `GetHeader("Content-Type")'
83
    // (case-insensitive) is equal to `content_type()'.
84
    const std::string* GetHeader(const char* key) const;
85
    const std::string* GetHeader(const std::string& key) const;
86
87
    std::vector<const std::string*> GetAllSetCookieHeader() const;
88
89
    // Set value of a header.
90
    // NOTE: If the key is "Content-Type", `SetHeader("Content-Type", ...)'
91
    // (case-insensitive) is equal to `set_content_type(...)'.
92
    void SetHeader(const std::string& key, const std::string& value);
93
94
    // Remove all headers of key.
95
    void RemoveHeader(const char* key);
96
0
    void RemoveHeader(const std::string& key) { RemoveHeader(key.c_str()); }
97
98
    // Append value to a header. If the header already exists, separate
99
    // old value and new value with comma(,), two-byte delimiter of "; "
100
    // or into a new header field, according to:
101
    //
102
    // https://datatracker.ietf.org/doc/html/rfc2616#section-4.2
103
    // Multiple message-header fields with the same field-name MAY be
104
    // present in a message if and only if the entire field-value for that
105
    // header field is defined as a comma-separated list [i.e., #(values)].
106
    //
107
    // https://datatracker.ietf.org/doc/html/rfc9114#section-4.2.1
108
    // If a decompressed field section contains multiple cookie field lines,
109
    // these MUST be concatenated into a single byte string using the two-byte
110
    // delimiter of "; " (ASCII 0x3b, 0x20) before being passed into a context
111
    // other than HTTP/2 or HTTP/3, such as an HTTP/1.1 connection, or a generic
112
    // HTTP server application.
113
    //
114
    // https://datatracker.ietf.org/doc/html/rfc6265#section-3
115
    // Origin servers SHOULD NOT fold multiple Set-Cookie header
116
    // fields into a single header field.
117
    void AppendHeader(const std::string& key, const butil::StringPiece& value);
118
    
119
    // Get header iterators which are invalidated after calling AppendHeader()
120
0
    HeaderIterator HeaderBegin() const { return _headers.begin(); }
121
0
    HeaderIterator HeaderEnd() const { return _headers.end(); }
122
    // #headers
123
0
    size_t HeaderCount() const { return _headers.size(); }
124
125
    // Get the URI object, check src/brpc/uri.h for details.
126
0
    const URI& uri() const { return _uri; }
127
25.7k
    URI& uri() { return _uri; }
128
129
    // Get/set http method.
130
0
    HttpMethod method() const { return _method; }
131
15.1k
    void set_method(const HttpMethod method) { _method = method; }
132
133
    // Get/set status-code and reason-phrase. Notice that the const char*
134
    // returned by reason_phrase() will be invalidated after next call to
135
    // set_status_code().
136
0
    int status_code() const { return _status_code; }
137
    const char* reason_phrase() const;
138
    void set_status_code(int status_code);
139
140
    // The URL path removed with matched prefix.
141
    // NOTE: always normalized and NOT started with /.
142
    //
143
    // Accessing HttpService.Echo
144
    //   [URL]                               [unresolved_path]
145
    //   "/HttpService/Echo"                 ""
146
    //   "/HttpService/Echo/Foo"             "Foo"
147
    //   "/HttpService/Echo/Foo/Bar"         "Foo/Bar"
148
    //   "/HttpService//Echo///Foo//"        "Foo"
149
    //
150
    // Accessing FileService.default_method:
151
    //   [URL]                               [unresolved_path]
152
    //   "/FileService"                      ""
153
    //   "/FileService/123.txt"              "123.txt"
154
    //   "/FileService/mydir/123.txt"        "mydir/123.txt"
155
    //   "/FileService//mydir///123.txt//"   "mydir/123.txt"
156
0
    const std::string& unresolved_path() const { return _unresolved_path; }
157
158
private:
159
friend class HttpMessage;
160
friend class HttpMessageSerializer;
161
friend class policy::H2StreamContext;
162
friend void policy::ProcessHttpRequest(InputMessageBase *msg);
163
164
    static const char* SET_COOKIE;
165
    static const char* COOKIE;
166
    static const char* CONTENT_TYPE;
167
168
    std::vector<const std::string*> GetMultiLineHeaders(const std::string& key) const;
169
170
    std::string& GetOrAddHeader(const std::string& key);
171
172
    std::string& AddHeader(const std::string& key);
173
174
73.3k
    bool IsSetCookie(const std::string& key) const {
175
73.3k
        return _header_key_equal(key, SET_COOKIE);
176
73.3k
    }
177
178
3.99k
    bool IsCookie(const std::string& key) const {
179
3.99k
        return _header_key_equal(key, COOKIE);
180
3.99k
    }
181
182
29.6k
    bool IsContentType(const std::string& key) const {
183
29.6k
        return _header_key_equal(key, CONTENT_TYPE);
184
29.6k
    }
185
186
    // Return true if the header can be folded in line,
187
    // otherwise, returns false, i.e., Set-Cookie header.
188
    // See comments of `AppendHeader'.
189
31.3k
    bool CanFoldedInLine(const std::string& key) {
190
31.3k
        return !IsSetCookie(key);
191
31.3k
    }
192
193
3.99k
    const char* HeaderValueDelimiter(const std::string& key) {
194
3.99k
        return IsCookie(key) ? "; " : ",";
195
3.99k
    }
196
197
    HeaderKeyEqual _header_key_equal;
198
    HeaderMap _headers;
199
    URI _uri;
200
    int _status_code;
201
    HttpMethod _method;
202
    std::string _content_type;
203
    std::string _unresolved_path;
204
    std::pair<int, int> _version;
205
    std::string* _first_set_cookie;
206
};
207
208
const HttpHeader& DefaultHttpHeader();
209
210
} // namespace brpc
211
212
213
#endif  //BRPC_HTTP_HEADER_H