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