Line data Source code
1 : // Copyright (c) 2011-2022 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/edhttp
4 : // contact@m2osw.com
5 : //
6 : // This program is free software: you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation, either version 3 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License
17 : // along with this program. If not, see <https://www.gnu.org/licenses/>.
18 :
19 :
20 : // self
21 : //
22 : #include "edhttp/http_link.h"
23 :
24 : #include "edhttp/exception.h"
25 : #include "edhttp/uri.h"
26 :
27 :
28 : // C
29 : //
30 : //#include <sys/time.h>
31 :
32 :
33 : // last include
34 : //
35 : #include <snapdev/poison.h>
36 :
37 :
38 :
39 : namespace edhttp
40 : {
41 :
42 :
43 :
44 : /** \brief Initializes the link.
45 : *
46 : * This function initializes the link.
47 : *
48 : * \param[in] snap The snap child creating this link.
49 : * \param[in] link The URI for this link.
50 : * \param[in] rel What the link represents (relative).
51 : *
52 : * \sa add_param()
53 : * \sa has_param()
54 : * \sa get_param()
55 : * \sa get_params()
56 : * \sa to_http_header()
57 : */
58 0 : http_link::http_link(std::string const & link, std::string const & rel)
59 : : f_link(link)
60 0 : , f_rel(rel)
61 : {
62 0 : if(f_link.empty())
63 : {
64 0 : throw link_parse_exception("the URI of a link cannot be empty.");
65 : }
66 0 : uri u;
67 0 : if(!u.set_uri(f_link))
68 : {
69 : // the snap_uri uses libtld so we arrive here if the TLD is not
70 : // considered valid
71 : //
72 0 : throw link_parse_exception("link URI is not valid.");
73 : }
74 0 : }
75 :
76 :
77 : /** \brief Retrieve the link "name".
78 : *
79 : * This function returns the relation string for this link. This is most
80 : * often viewed as the link name. In generatl, links are saved by name.
81 : * As a result, you cannot have two links with the same name.
82 : *
83 : * \return The "rel" string as passed to the constructor.
84 : */
85 0 : std::string http_link::get_name() const
86 : {
87 0 : return f_rel;
88 : }
89 :
90 :
91 : /** \brief Set whether to include this link on a redirect or not.
92 : *
93 : * Whenever Snap! generates a 301 or a 302, links do not get added to
94 : * the header (there are generally useless there in that situation.)
95 : *
96 : * By calling this function with true you indicate that it should be
97 : * added whether the process is about to redirect the client to another
98 : * page or not.
99 : *
100 : * See the shortcut implementation for an example where this is used.
101 : *
102 : * \param[in] redirect Whether to include the link on a redirect.
103 : */
104 0 : void http_link::set_redirect(bool redirect)
105 : {
106 0 : f_redirect = redirect;
107 0 : }
108 :
109 :
110 : /** \brief Check whether to add this link on a redirect.
111 : *
112 : * By default links do not get added to the header if the request
113 : * ends up in a redirect.
114 : *
115 : * If this function returns true, then it will be added to the header.
116 : *
117 : * \return true if link is expected to be added on normal or redirect calls.
118 : */
119 0 : bool http_link::get_redirect() const
120 : {
121 0 : return f_redirect;
122 : }
123 :
124 :
125 : /** \brief Add a parameter to this link.
126 : *
127 : * Each link accept any number of parameter, although usually it will be
128 : * limited to just 2 or 3. The "rel" parameter is defined on construction
129 : * and cannot be re-added or modified with this function.
130 : *
131 : * The name of the parameter cannot be the empty string.
132 : *
133 : * If that parameter already exists, its value gets replaced.
134 : *
135 : * \param[in] name The parameter name.
136 : * \param[in] value The value for the named parameter.
137 : */
138 0 : void http_link::add_param(std::string const & name, std::string const & value)
139 : {
140 0 : if(name.empty())
141 : {
142 0 : throw link_parameter_exception("the name of a link parameter cannot be empty.");
143 : }
144 0 : if(name == "rel")
145 : {
146 0 : throw link_parameter_exception("the \"rel\" link parameter cannot be modified, it is set on construction only.");
147 : }
148 0 : for(char const * s(name.c_str()); *s != '\0'; ++s)
149 : {
150 0 : if(*s < 'a'
151 0 : || *s > 'z')
152 : {
153 : // this is probably wrong, but right now that's all we need
154 : // extend as required
155 0 : throw link_parameter_exception("the name of a link parameter must be defined with lowercase letters only (a-z).");
156 : }
157 : }
158 0 : for(char const * s(value.c_str()); *s != '\0'; ++s)
159 : {
160 0 : if(*s == '"'
161 0 : || *s < ' ')
162 : {
163 0 : throw link_parameter_exception("the value of a link parameter cannot include a control character or a double quote (\").");
164 : }
165 : }
166 :
167 0 : f_params[name] = value;
168 0 : }
169 :
170 :
171 : /** \brief Check whether a named parameter exists.
172 : *
173 : * This function checks whether a parameter with the specified name exists
174 : * in the list of parameters.
175 : *
176 : * \param[in] name The new value of the cookie.
177 : *
178 : * \return true if the named parameter is defined.
179 : */
180 0 : bool http_link::has_param(std::string const & name) const
181 : {
182 0 : return f_params.find(name) != f_params.end();
183 : }
184 :
185 :
186 : /** \brief Retrieve the value of a parameter.
187 : *
188 : * This function returns the value of the specified parameter. If the
189 : * parameter is not defined, the empty string is returned.
190 : *
191 : * \param[in] name The name of the parameter to read.
192 : *
193 : * \sa add_param();
194 : */
195 0 : std::string http_link::get_param(std::string const & name) const
196 : {
197 0 : if(has_param(name))
198 : {
199 0 : auto const it(f_params.find(name));
200 0 : return it->second;
201 : }
202 :
203 0 : return std::string();
204 : }
205 :
206 :
207 : /** \brief Get the complete list of parameters.
208 : *
209 : * This function can be used to retrieve the entire list of parameters from
210 : * this link.
211 : *
212 : * \warning
213 : * By default the function returns a reference meaning that a call to
214 : * add_param() will change the map you are dealing with here.
215 : *
216 : * \return The list of parameters, a map.
217 : */
218 0 : http_link::param_t const & http_link::get_params() const
219 : {
220 0 : return f_params;
221 : }
222 :
223 :
224 : /** \brief Transform the link for the HTTP header.
225 : *
226 : * This function transforms the link so it works as an HTTP header.
227 : *
228 : * \warning
229 : * This generates that one link string. Not the actual header. The
230 : * header requires all the links to be added in one "Link: ..." entry.
231 : *
232 : * See https://tools.ietf.org/html/rfc5988
233 : *
234 : * \return A valid HTTP link header.
235 : */
236 0 : std::string http_link::to_http_header() const
237 : {
238 : // Note: the name was already checked for invalid characters
239 0 : std::string result;
240 :
241 0 : result += "<";
242 0 : result += f_link;
243 0 : result += ">; rel=";
244 0 : result += f_rel;
245 :
246 0 : for(auto p : f_params)
247 : {
248 : // Note: if we test the value of each parameter, then we could
249 : // already know whether it needs quoting or not when we
250 : // reach here
251 : //
252 0 : result += "; ";
253 0 : result += p.first;
254 0 : result += "=\"";
255 0 : result += p.second;
256 0 : result += "\"";
257 : }
258 :
259 0 : return result;
260 : }
261 :
262 :
263 :
264 6 : } // namespace edhttp
265 : // vim: ts=4 sw=4 et
|