31
31
<a name="l00008"></a>00008 <span class="comment">//</span>
32
32
<a name="l00009"></a>00009
33
33
<a name="l00010"></a>00010 <span class="preprocessor">#include <boost/exception/diagnostic_information.hpp></span>
34
<a name="l00011"></a>00011 <span class="preprocessor">#include <pion/http/server.hpp></span>
35
<a name="l00012"></a>00012 <span class="preprocessor">#include <pion/http/request.hpp></span>
36
<a name="l00013"></a>00013 <span class="preprocessor">#include <pion/http/request_reader.hpp></span>
37
<a name="l00014"></a>00014 <span class="preprocessor">#include <pion/http/response_writer.hpp></span>
38
<a name="l00015"></a>00015
34
<a name="l00011"></a>00011 <span class="preprocessor">#include <pion/algorithm.hpp></span>
35
<a name="l00012"></a>00012 <span class="preprocessor">#include <pion/http/server.hpp></span>
36
<a name="l00013"></a>00013 <span class="preprocessor">#include <pion/http/request.hpp></span>
37
<a name="l00014"></a>00014 <span class="preprocessor">#include <pion/http/request_reader.hpp></span>
38
<a name="l00015"></a>00015 <span class="preprocessor">#include <pion/http/response_writer.hpp></span>
39
39
<a name="l00016"></a>00016
40
<a name="l00017"></a>00017 <span class="keyword">namespace </span>pion { <span class="comment">// begin namespace pion</span>
41
<a name="l00018"></a>00018 <span class="keyword">namespace </span>http { <span class="comment">// begin namespace http</span>
42
<a name="l00019"></a>00019
40
<a name="l00017"></a>00017
41
<a name="l00018"></a>00018 <span class="keyword">namespace </span>pion { <span class="comment">// begin namespace pion</span>
42
<a name="l00019"></a>00019 <span class="keyword">namespace </span>http { <span class="comment">// begin namespace http</span>
43
43
<a name="l00020"></a>00020
44
<a name="l00021"></a>00021 <span class="comment">// static members of server</span>
45
<a name="l00022"></a>00022
46
<a name="l00023"></a>00023 <span class="keyword">const</span> <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> server::MAX_REDIRECTS = 10;
47
<a name="l00024"></a>00024
44
<a name="l00021"></a>00021
45
<a name="l00022"></a>00022 <span class="comment">// static members of server</span>
46
<a name="l00023"></a>00023
47
<a name="l00024"></a>00024 <span class="keyword">const</span> <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> server::MAX_REDIRECTS = 10;
48
48
<a name="l00025"></a>00025
49
<a name="l00026"></a>00026 <span class="comment">// server member functions</span>
50
<a name="l00027"></a>00027
51
<a name="l00028"></a><a class="code" href="classpion_1_1http_1_1server.html#a3366fd6be76ebb5ade34413be330aa6a">00028</a> <span class="keywordtype">void</span> <a class="code" href="classpion_1_1http_1_1server.html#a3366fd6be76ebb5ade34413be330aa6a">server::handle_connection</a>(tcp::connection_ptr& tcp_conn)
52
<a name="l00029"></a>00029 {
53
<a name="l00030"></a>00030 request_reader_ptr my_reader_ptr;
54
<a name="l00031"></a>00031 my_reader_ptr = <a class="code" href="classpion_1_1http_1_1request__reader.html#a889653828718972c32e8671a3b6e29b0">request_reader::create</a>(tcp_conn, boost::bind(&<a class="code" href="classpion_1_1http_1_1server.html#ad3e6180d412e8d2f135423e7e15f43ea">server::handle_request</a>,
55
<a name="l00032"></a>00032 <span class="keyword">this</span>, _1, _2, _3));
56
<a name="l00033"></a>00033 my_reader_ptr->set_max_content_length(m_max_content_length);
57
<a name="l00034"></a>00034 my_reader_ptr->receive();
58
<a name="l00035"></a>00035 }
59
<a name="l00036"></a>00036
60
<a name="l00037"></a><a class="code" href="classpion_1_1http_1_1server.html#ad3e6180d412e8d2f135423e7e15f43ea">00037</a> <span class="keywordtype">void</span> <a class="code" href="classpion_1_1http_1_1server.html#ad3e6180d412e8d2f135423e7e15f43ea">server::handle_request</a>(http::request_ptr& http_request_ptr,
61
<a name="l00038"></a>00038 tcp::connection_ptr& tcp_conn, <span class="keyword">const</span> boost::system::error_code& ec)
62
<a name="l00039"></a>00039 {
63
<a name="l00040"></a>00040 <span class="keywordflow">if</span> (ec || ! http_request_ptr->is_valid()) {
64
<a name="l00041"></a>00041 tcp_conn->set_lifecycle(tcp::connection::LIFECYCLE_CLOSE); <span class="comment">// make sure it will get closed</span>
65
<a name="l00042"></a>00042 <span class="keywordflow">if</span> (tcp_conn->is_open() && (ec.category() == <a class="code" href="classpion_1_1http_1_1parser.html#a9313aa230ae4af4c30702c0605a1f701" title="returns an instance of parser::error_category_t">http::parser::get_error_category</a>())) {
66
<a name="l00043"></a>00043 <span class="comment">// HTTP parser error</span>
67
<a name="l00044"></a>00044 PION_LOG_INFO(<a class="code" href="classpion_1_1tcp_1_1server.html#a0fd391b946961fca8604b902ddb06f7d" title="primary logging interface used by this class">m_logger</a>, <span class="stringliteral">"Invalid HTTP request ("</span> << ec.message() << <span class="stringliteral">")"</span>);
68
<a name="l00045"></a>00045 m_bad_request_handler(http_request_ptr, tcp_conn);
69
<a name="l00046"></a>00046 } <span class="keywordflow">else</span> {
70
<a name="l00047"></a>00047 <span class="keyword">static</span> <span class="keyword">const</span> boost::system::error_condition
71
<a name="l00048"></a>00048 ERRCOND_CANCELED(boost::system::errc::operation_canceled, boost::system::system_category()),
72
<a name="l00049"></a>00049 ERRCOND_EOF(boost::asio::error::eof, boost::asio::error::misc_category);
73
<a name="l00050"></a>00050
74
<a name="l00051"></a>00051 <span class="keywordflow">if</span> (ec == ERRCOND_CANCELED || ec == ERRCOND_EOF) {
75
<a name="l00052"></a>00052 <span class="comment">// don't spam the log with common (non-)errors that happen during normal operation</span>
76
<a name="l00053"></a>00053 PION_LOG_DEBUG(<a class="code" href="classpion_1_1tcp_1_1server.html#a0fd391b946961fca8604b902ddb06f7d" title="primary logging interface used by this class">m_logger</a>, <span class="stringliteral">"Lost connection on port "</span> << <a class="code" href="classpion_1_1tcp_1_1server.html#a46c1027475b8748e2a3047c7b738ef0b" title="returns tcp port number that the server listens for connections on">get_port</a>() << <span class="stringliteral">" ("</span> << ec.message() << <span class="stringliteral">")"</span>);
77
<a name="l00054"></a>00054 } <span class="keywordflow">else</span> {
78
<a name="l00055"></a>00055 PION_LOG_INFO(<a class="code" href="classpion_1_1tcp_1_1server.html#a0fd391b946961fca8604b902ddb06f7d" title="primary logging interface used by this class">m_logger</a>, <span class="stringliteral">"Lost connection on port "</span> << <a class="code" href="classpion_1_1tcp_1_1server.html#a46c1027475b8748e2a3047c7b738ef0b" title="returns tcp port number that the server listens for connections on">get_port</a>() << <span class="stringliteral">" ("</span> << ec.message() << <span class="stringliteral">")"</span>);
79
<a name="l00056"></a>00056 }
80
<a name="l00057"></a>00057
81
<a name="l00058"></a>00058 tcp_conn->finish();
82
<a name="l00059"></a>00059 }
83
<a name="l00060"></a>00060 <span class="keywordflow">return</span>;
84
<a name="l00061"></a>00061 }
85
<a name="l00062"></a>00062
86
<a name="l00063"></a>00063 PION_LOG_DEBUG(<a class="code" href="classpion_1_1tcp_1_1server.html#a0fd391b946961fca8604b902ddb06f7d" title="primary logging interface used by this class">m_logger</a>, <span class="stringliteral">"Received a valid HTTP request"</span>);
87
<a name="l00064"></a>00064
88
<a name="l00065"></a>00065 <span class="comment">// strip off trailing slash if the request has one</span>
89
<a name="l00066"></a>00066 std::string resource_requested(<a class="code" href="classpion_1_1http_1_1server.html#a375e54d0970e5d3dfc0eb50f902cf4c9">strip_trailing_slash</a>(http_request_ptr->get_resource()));
90
<a name="l00067"></a>00067
91
<a name="l00068"></a>00068 <span class="comment">// apply any redirection</span>
92
<a name="l00069"></a>00069 redirect_map_t::const_iterator it = m_redirects.find(resource_requested);
93
<a name="l00070"></a>00070 <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> num_redirects = 0;
94
<a name="l00071"></a>00071 <span class="keywordflow">while</span> (it != m_redirects.end()) {
95
<a name="l00072"></a>00072 <span class="keywordflow">if</span> (++num_redirects > MAX_REDIRECTS) {
96
<a name="l00073"></a>00073 PION_LOG_ERROR(<a class="code" href="classpion_1_1tcp_1_1server.html#a0fd391b946961fca8604b902ddb06f7d" title="primary logging interface used by this class">m_logger</a>, <span class="stringliteral">"Maximum number of redirects (server::MAX_REDIRECTS) exceeded for requested resource: "</span> << http_request_ptr->get_original_resource());
97
<a name="l00074"></a>00074 m_server_error_handler(http_request_ptr, tcp_conn, <span class="stringliteral">"Maximum number of redirects (server::MAX_REDIRECTS) exceeded for requested resource"</span>);
98
<a name="l00075"></a>00075 <span class="keywordflow">return</span>;
99
<a name="l00076"></a>00076 }
100
<a name="l00077"></a>00077 resource_requested = it->second;
101
<a name="l00078"></a>00078 http_request_ptr->change_resource(resource_requested);
102
<a name="l00079"></a>00079 it = m_redirects.find(resource_requested);
103
<a name="l00080"></a>00080 }
104
<a name="l00081"></a>00081
105
<a name="l00082"></a>00082 <span class="comment">// if authentication activated, check current request</span>
106
<a name="l00083"></a>00083 <span class="keywordflow">if</span> (m_auth_ptr) {
107
<a name="l00084"></a>00084 <span class="comment">// try to verify authentication</span>
108
<a name="l00085"></a>00085 <span class="keywordflow">if</span> (! m_auth_ptr->handle_request(http_request_ptr, tcp_conn)) {
109
<a name="l00086"></a>00086 <span class="comment">// the HTTP 401 message has already been sent by the authentication object</span>
110
<a name="l00087"></a>00087 PION_LOG_DEBUG(<a class="code" href="classpion_1_1tcp_1_1server.html#a0fd391b946961fca8604b902ddb06f7d" title="primary logging interface used by this class">m_logger</a>, <span class="stringliteral">"Authentication required for HTTP resource: "</span>
111
<a name="l00088"></a>00088 << resource_requested);
112
<a name="l00089"></a>00089 <span class="keywordflow">if</span> (http_request_ptr->get_resource() != http_request_ptr->get_original_resource()) {
113
<a name="l00090"></a>00090 PION_LOG_DEBUG(<a class="code" href="classpion_1_1tcp_1_1server.html#a0fd391b946961fca8604b902ddb06f7d" title="primary logging interface used by this class">m_logger</a>, <span class="stringliteral">"Original resource requested was: "</span> << http_request_ptr->get_original_resource());
114
<a name="l00091"></a>00091 }
115
<a name="l00092"></a>00092 <span class="keywordflow">return</span>;
116
<a name="l00093"></a>00093 }
117
<a name="l00094"></a>00094 }
118
<a name="l00095"></a>00095
119
<a name="l00096"></a>00096 <span class="comment">// search for a handler matching the resource requested</span>
120
<a name="l00097"></a>00097 <a class="code" href="classpion_1_1http_1_1server.html#a74c41bc6ca8355497abb1401339a1306" title="type of function that is used to handle requests">request_handler_t</a> request_handler;
121
<a name="l00098"></a>00098 <span class="keywordflow">if</span> (<a class="code" href="classpion_1_1http_1_1server.html#a2a0e8e0c21438a9928e680cb0d94430c">find_request_handler</a>(resource_requested, request_handler)) {
122
<a name="l00099"></a>00099
123
<a name="l00100"></a>00100 <span class="comment">// try to handle the request</span>
124
<a name="l00101"></a>00101 <span class="keywordflow">try</span> {
125
<a name="l00102"></a>00102 request_handler(http_request_ptr, tcp_conn);
126
<a name="l00103"></a>00103 PION_LOG_DEBUG(<a class="code" href="classpion_1_1tcp_1_1server.html#a0fd391b946961fca8604b902ddb06f7d" title="primary logging interface used by this class">m_logger</a>, <span class="stringliteral">"Found request handler for HTTP resource: "</span>
127
<a name="l00104"></a>00104 << resource_requested);
128
<a name="l00105"></a>00105 <span class="keywordflow">if</span> (http_request_ptr->get_resource() != http_request_ptr->get_original_resource()) {
129
<a name="l00106"></a>00106 PION_LOG_DEBUG(<a class="code" href="classpion_1_1tcp_1_1server.html#a0fd391b946961fca8604b902ddb06f7d" title="primary logging interface used by this class">m_logger</a>, <span class="stringliteral">"Original resource requested was: "</span> << http_request_ptr->get_original_resource());
130
<a name="l00107"></a>00107 }
131
<a name="l00108"></a>00108 } <span class="keywordflow">catch</span> (std::bad_alloc&) {
132
<a name="l00109"></a>00109 <span class="comment">// propagate memory errors (FATAL)</span>
133
<a name="l00110"></a>00110 <span class="keywordflow">throw</span>;
134
<a name="l00111"></a>00111 } <span class="keywordflow">catch</span> (std::exception& e) {
135
<a name="l00112"></a>00112 <span class="comment">// recover gracefully from other exceptions thrown request handlers</span>
136
<a name="l00113"></a>00113 PION_LOG_ERROR(<a class="code" href="classpion_1_1tcp_1_1server.html#a0fd391b946961fca8604b902ddb06f7d" title="primary logging interface used by this class">m_logger</a>, <span class="stringliteral">"HTTP request handler: "</span> << boost::diagnostic_information(e));
137
<a name="l00114"></a>00114 m_server_error_handler(http_request_ptr, tcp_conn, boost::diagnostic_information(e));
138
<a name="l00115"></a>00115 }
139
<a name="l00116"></a>00116
140
<a name="l00117"></a>00117 } <span class="keywordflow">else</span> {
141
<a name="l00118"></a>00118
142
<a name="l00119"></a>00119 <span class="comment">// no web services found that could handle the request</span>
143
<a name="l00120"></a>00120 PION_LOG_INFO(<a class="code" href="classpion_1_1tcp_1_1server.html#a0fd391b946961fca8604b902ddb06f7d" title="primary logging interface used by this class">m_logger</a>, <span class="stringliteral">"No HTTP request handlers found for resource: "</span>
144
<a name="l00121"></a>00121 << resource_requested);
145
<a name="l00122"></a>00122 <span class="keywordflow">if</span> (http_request_ptr->get_resource() != http_request_ptr->get_original_resource()) {
146
<a name="l00123"></a>00123 PION_LOG_DEBUG(<a class="code" href="classpion_1_1tcp_1_1server.html#a0fd391b946961fca8604b902ddb06f7d" title="primary logging interface used by this class">m_logger</a>, <span class="stringliteral">"Original resource requested was: "</span> << http_request_ptr->get_original_resource());
147
<a name="l00124"></a>00124 }
148
<a name="l00125"></a>00125 m_not_found_handler(http_request_ptr, tcp_conn);
149
<a name="l00126"></a>00126 }
150
<a name="l00127"></a>00127 }
151
<a name="l00128"></a>00128
152
<a name="l00129"></a><a class="code" href="classpion_1_1http_1_1server.html#a2a0e8e0c21438a9928e680cb0d94430c">00129</a> <span class="keywordtype">bool</span> <a class="code" href="classpion_1_1http_1_1server.html#a2a0e8e0c21438a9928e680cb0d94430c">server::find_request_handler</a>(<span class="keyword">const</span> std::string& resource,
153
<a name="l00130"></a>00130 request_handler_t& request_handler)<span class="keyword"> const</span>
154
<a name="l00131"></a>00131 <span class="keyword"></span>{
155
<a name="l00132"></a>00132 <span class="comment">// first make sure that HTTP resources are registered</span>
156
<a name="l00133"></a>00133 boost::mutex::scoped_lock resource_lock(m_resource_mutex);
157
<a name="l00134"></a>00134 <span class="keywordflow">if</span> (m_resources.empty())
158
<a name="l00135"></a>00135 <span class="keywordflow">return</span> <span class="keyword">false</span>;
159
<a name="l00136"></a>00136
160
<a name="l00137"></a>00137 <span class="comment">// iterate through each resource entry that may match the resource</span>
161
<a name="l00138"></a>00138 resource_map_t::const_iterator i = m_resources.upper_bound(resource);
162
<a name="l00139"></a>00139 <span class="keywordflow">while</span> (i != m_resources.begin()) {
163
<a name="l00140"></a>00140 --i;
164
<a name="l00141"></a>00141 <span class="comment">// check for a match if the first part of the strings match</span>
165
<a name="l00142"></a>00142 <span class="keywordflow">if</span> (i->first.empty() || resource.compare(0, i->first.size(), i->first) == 0) {
166
<a name="l00143"></a>00143 <span class="comment">// only if the resource matches the plug-in's identifier</span>
167
<a name="l00144"></a>00144 <span class="comment">// or if resource is followed first with a '/' character</span>
168
<a name="l00145"></a>00145 <span class="keywordflow">if</span> (resource.size() == i->first.size() || resource[i->first.size()]==<span class="charliteral">'/'</span>) {
169
<a name="l00146"></a>00146 request_handler = i->second;
170
<a name="l00147"></a>00147 <span class="keywordflow">return</span> <span class="keyword">true</span>;
171
<a name="l00148"></a>00148 }
172
<a name="l00149"></a>00149 }
173
<a name="l00150"></a>00150 }
174
<a name="l00151"></a>00151
175
<a name="l00152"></a>00152 <span class="keywordflow">return</span> <span class="keyword">false</span>;
176
<a name="l00153"></a>00153 }
177
<a name="l00154"></a>00154
178
<a name="l00155"></a><a class="code" href="classpion_1_1http_1_1server.html#a312ad564b529bda2b4ddd12f02fd6d62">00155</a> <span class="keywordtype">void</span> <a class="code" href="classpion_1_1http_1_1server.html#a312ad564b529bda2b4ddd12f02fd6d62">server::add_resource</a>(<span class="keyword">const</span> std::string& resource,
179
<a name="l00156"></a>00156 request_handler_t request_handler)
180
<a name="l00157"></a>00157 {
181
<a name="l00158"></a>00158 boost::mutex::scoped_lock resource_lock(m_resource_mutex);
182
<a name="l00159"></a>00159 <span class="keyword">const</span> std::string clean_resource(<a class="code" href="classpion_1_1http_1_1server.html#a375e54d0970e5d3dfc0eb50f902cf4c9">strip_trailing_slash</a>(resource));
183
<a name="l00160"></a>00160 m_resources.insert(std::make_pair(clean_resource, request_handler));
184
<a name="l00161"></a>00161 PION_LOG_INFO(<a class="code" href="classpion_1_1tcp_1_1server.html#a0fd391b946961fca8604b902ddb06f7d" title="primary logging interface used by this class">m_logger</a>, <span class="stringliteral">"Added request handler for HTTP resource: "</span> << clean_resource);
185
<a name="l00162"></a>00162 }
186
<a name="l00163"></a>00163
187
<a name="l00164"></a><a class="code" href="classpion_1_1http_1_1server.html#ac75fe5968f4d5e5c68e6328d483d0794">00164</a> <span class="keywordtype">void</span> <a class="code" href="classpion_1_1http_1_1server.html#ac75fe5968f4d5e5c68e6328d483d0794">server::remove_resource</a>(<span class="keyword">const</span> std::string& resource)
188
<a name="l00165"></a>00165 {
189
<a name="l00166"></a>00166 boost::mutex::scoped_lock resource_lock(m_resource_mutex);
190
<a name="l00167"></a>00167 <span class="keyword">const</span> std::string clean_resource(<a class="code" href="classpion_1_1http_1_1server.html#a375e54d0970e5d3dfc0eb50f902cf4c9">strip_trailing_slash</a>(resource));
191
<a name="l00168"></a>00168 m_resources.erase(clean_resource);
192
<a name="l00169"></a>00169 PION_LOG_INFO(<a class="code" href="classpion_1_1tcp_1_1server.html#a0fd391b946961fca8604b902ddb06f7d" title="primary logging interface used by this class">m_logger</a>, <span class="stringliteral">"Removed request handler for HTTP resource: "</span> << clean_resource);
193
<a name="l00170"></a>00170 }
194
<a name="l00171"></a>00171
195
<a name="l00172"></a><a class="code" href="classpion_1_1http_1_1server.html#a114c86a620ac425e4da9ebacebda3f21">00172</a> <span class="keywordtype">void</span> <a class="code" href="classpion_1_1http_1_1server.html#a114c86a620ac425e4da9ebacebda3f21">server::add_redirect</a>(<span class="keyword">const</span> std::string& requested_resource,
196
<a name="l00173"></a>00173 <span class="keyword">const</span> std::string& new_resource)
197
<a name="l00174"></a>00174 {
198
<a name="l00175"></a>00175 boost::mutex::scoped_lock resource_lock(m_resource_mutex);
199
<a name="l00176"></a>00176 <span class="keyword">const</span> std::string clean_requested_resource(<a class="code" href="classpion_1_1http_1_1server.html#a375e54d0970e5d3dfc0eb50f902cf4c9">strip_trailing_slash</a>(requested_resource));
200
<a name="l00177"></a>00177 <span class="keyword">const</span> std::string clean_new_resource(<a class="code" href="classpion_1_1http_1_1server.html#a375e54d0970e5d3dfc0eb50f902cf4c9">strip_trailing_slash</a>(new_resource));
201
<a name="l00178"></a>00178 m_redirects.insert(std::make_pair(clean_requested_resource, clean_new_resource));
202
<a name="l00179"></a>00179 PION_LOG_INFO(<a class="code" href="classpion_1_1tcp_1_1server.html#a0fd391b946961fca8604b902ddb06f7d" title="primary logging interface used by this class">m_logger</a>, <span class="stringliteral">"Added redirection for HTTP resource "</span> << clean_requested_resource << <span class="stringliteral">" to resource "</span> << clean_new_resource);
203
<a name="l00180"></a>00180 }
204
<a name="l00181"></a>00181
205
<a name="l00182"></a><a class="code" href="classpion_1_1http_1_1server.html#a080297b6789515f60ef8b856d6e0f372">00182</a> <span class="keywordtype">void</span> <a class="code" href="classpion_1_1http_1_1server.html#a080297b6789515f60ef8b856d6e0f372">server::handle_bad_request</a>(http::request_ptr& http_request_ptr,
206
<a name="l00183"></a>00183 tcp::connection_ptr& tcp_conn)
207
<a name="l00184"></a>00184 {
208
<a name="l00185"></a>00185 <span class="keyword">static</span> <span class="keyword">const</span> std::string BAD_REQUEST_HTML =
209
<a name="l00186"></a>00186 <span class="stringliteral">"<html><head>\n"</span>
210
<a name="l00187"></a>00187 <span class="stringliteral">"<title>400 Bad Request</title>\n"</span>
211
<a name="l00188"></a>00188 <span class="stringliteral">"</head><body>\n"</span>
212
<a name="l00189"></a>00189 <span class="stringliteral">"<h1>Bad Request</h1>\n"</span>
213
<a name="l00190"></a>00190 <span class="stringliteral">"<p>Your browser sent a request that this server could not understand.</p>\n"</span>
214
<a name="l00191"></a>00191 <span class="stringliteral">"</body></html>\n"</span>;
215
<a name="l00192"></a>00192 http::response_writer_ptr <a class="code" href="classpion_1_1http_1_1writer.html">writer</a>(<a class="code" href="classpion_1_1http_1_1response__writer.html#a75084960d3162f724342ae947e7d07e3">http::response_writer::create</a>(tcp_conn, *http_request_ptr,
216
<a name="l00193"></a>00193 boost::bind(&<a class="code" href="classpion_1_1tcp_1_1connection.html#aa7ff7a6d8325c9cbfb026c1a441523fe">tcp::connection::finish</a>, tcp_conn)));
217
<a name="l00194"></a>00194 writer->get_response().set_status_code(http::types::RESPONSE_CODE_BAD_REQUEST);
218
<a name="l00195"></a>00195 writer->get_response().set_status_message(http::types::RESPONSE_MESSAGE_BAD_REQUEST);
219
<a name="l00196"></a>00196 writer->write_no_copy(BAD_REQUEST_HTML);
220
<a name="l00197"></a>00197 writer->send();
221
<a name="l00198"></a>00198 }
222
<a name="l00199"></a>00199
223
<a name="l00200"></a><a class="code" href="classpion_1_1http_1_1server.html#ae2484144be6281ac5c1cbbcea99da81b">00200</a> <span class="keywordtype">void</span> <a class="code" href="classpion_1_1http_1_1server.html#ae2484144be6281ac5c1cbbcea99da81b">server::handle_not_found_request</a>(http::request_ptr& http_request_ptr,
224
<a name="l00201"></a>00201 tcp::connection_ptr& tcp_conn)
225
<a name="l00202"></a>00202 {
226
<a name="l00203"></a>00203 <span class="keyword">static</span> <span class="keyword">const</span> std::string NOT_FOUND_HTML_START =
227
<a name="l00204"></a>00204 <span class="stringliteral">"<html><head>\n"</span>
228
<a name="l00205"></a>00205 <span class="stringliteral">"<title>404 Not Found</title>\n"</span>
229
<a name="l00206"></a>00206 <span class="stringliteral">"</head><body>\n"</span>
230
<a name="l00207"></a>00207 <span class="stringliteral">"<h1>Not Found</h1>\n"</span>
231
<a name="l00208"></a>00208 <span class="stringliteral">"<p>The requested URL "</span>;
232
<a name="l00209"></a>00209 <span class="keyword">static</span> <span class="keyword">const</span> std::string NOT_FOUND_HTML_FINISH =
233
<a name="l00210"></a>00210 <span class="stringliteral">" was not found on this server.</p>\n"</span>
234
<a name="l00211"></a>00211 <span class="stringliteral">"</body></html>\n"</span>;
235
<a name="l00212"></a>00212 http::response_writer_ptr <a class="code" href="classpion_1_1http_1_1writer.html">writer</a>(<a class="code" href="classpion_1_1http_1_1response__writer.html#a75084960d3162f724342ae947e7d07e3">http::response_writer::create</a>(tcp_conn, *http_request_ptr,
236
<a name="l00213"></a>00213 boost::bind(&<a class="code" href="classpion_1_1tcp_1_1connection.html#aa7ff7a6d8325c9cbfb026c1a441523fe">tcp::connection::finish</a>, tcp_conn)));
237
<a name="l00214"></a>00214 writer->get_response().set_status_code(http::types::RESPONSE_CODE_NOT_FOUND);
238
<a name="l00215"></a>00215 writer->get_response().set_status_message(http::types::RESPONSE_MESSAGE_NOT_FOUND);
239
<a name="l00216"></a>00216 writer->write_no_copy(NOT_FOUND_HTML_START);
240
<a name="l00217"></a>00217 writer << http_request_ptr->get_resource();
241
<a name="l00218"></a>00218 writer->write_no_copy(NOT_FOUND_HTML_FINISH);
242
<a name="l00219"></a>00219 writer->send();
243
<a name="l00220"></a>00220 }
244
<a name="l00221"></a>00221
245
<a name="l00222"></a><a class="code" href="classpion_1_1http_1_1server.html#aae06fc86091293ff3168822f0018c183">00222</a> <span class="keywordtype">void</span> <a class="code" href="classpion_1_1http_1_1server.html#aae06fc86091293ff3168822f0018c183">server::handle_server_error</a>(http::request_ptr& http_request_ptr,
246
<a name="l00223"></a>00223 tcp::connection_ptr& tcp_conn,
247
<a name="l00224"></a>00224 <span class="keyword">const</span> std::string& error_msg)
248
<a name="l00225"></a>00225 {
249
<a name="l00226"></a>00226 <span class="keyword">static</span> <span class="keyword">const</span> std::string SERVER_ERROR_HTML_START =
250
<a name="l00227"></a>00227 <span class="stringliteral">"<html><head>\n"</span>
251
<a name="l00228"></a>00228 <span class="stringliteral">"<title>500 Server Error</title>\n"</span>
252
<a name="l00229"></a>00229 <span class="stringliteral">"</head><body>\n"</span>
253
<a name="l00230"></a>00230 <span class="stringliteral">"<h1>Internal Server Error</h1>\n"</span>
254
<a name="l00231"></a>00231 <span class="stringliteral">"<p>The server encountered an internal error: <strong>"</span>;
255
<a name="l00232"></a>00232 <span class="keyword">static</span> <span class="keyword">const</span> std::string SERVER_ERROR_HTML_FINISH =
256
<a name="l00233"></a>00233 <span class="stringliteral">"</strong></p>\n"</span>
257
<a name="l00234"></a>00234 <span class="stringliteral">"</body></html>\n"</span>;
258
<a name="l00235"></a>00235 http::response_writer_ptr <a class="code" href="classpion_1_1http_1_1writer.html">writer</a>(<a class="code" href="classpion_1_1http_1_1response__writer.html#a75084960d3162f724342ae947e7d07e3">http::response_writer::create</a>(tcp_conn, *http_request_ptr,
259
<a name="l00236"></a>00236 boost::bind(&<a class="code" href="classpion_1_1tcp_1_1connection.html#aa7ff7a6d8325c9cbfb026c1a441523fe">tcp::connection::finish</a>, tcp_conn)));
260
<a name="l00237"></a>00237 writer->get_response().set_status_code(http::types::RESPONSE_CODE_SERVER_ERROR);
261
<a name="l00238"></a>00238 writer->get_response().set_status_message(http::types::RESPONSE_MESSAGE_SERVER_ERROR);
262
<a name="l00239"></a>00239 writer->write_no_copy(SERVER_ERROR_HTML_START);
263
<a name="l00240"></a>00240 writer << error_msg;
264
<a name="l00241"></a>00241 writer->write_no_copy(SERVER_ERROR_HTML_FINISH);
265
<a name="l00242"></a>00242 writer->send();
266
<a name="l00243"></a>00243 }
267
<a name="l00244"></a>00244
268
<a name="l00245"></a><a class="code" href="classpion_1_1http_1_1server.html#acc9ff11da47156419e059bebdddb5941">00245</a> <span class="keywordtype">void</span> <a class="code" href="classpion_1_1http_1_1server.html#acc9ff11da47156419e059bebdddb5941">server::handle_forbidden_request</a>(http::request_ptr& http_request_ptr,
269
<a name="l00246"></a>00246 tcp::connection_ptr& tcp_conn,
270
<a name="l00247"></a>00247 <span class="keyword">const</span> std::string& error_msg)
271
<a name="l00248"></a>00248 {
272
<a name="l00249"></a>00249 <span class="keyword">static</span> <span class="keyword">const</span> std::string FORBIDDEN_HTML_START =
273
<a name="l00250"></a>00250 <span class="stringliteral">"<html><head>\n"</span>
274
<a name="l00251"></a>00251 <span class="stringliteral">"<title>403 Forbidden</title>\n"</span>
275
<a name="l00252"></a>00252 <span class="stringliteral">"</head><body>\n"</span>
276
<a name="l00253"></a>00253 <span class="stringliteral">"<h1>Forbidden</h1>\n"</span>
277
<a name="l00254"></a>00254 <span class="stringliteral">"<p>User not authorized to access the requested URL "</span>;
278
<a name="l00255"></a>00255 <span class="keyword">static</span> <span class="keyword">const</span> std::string FORBIDDEN_HTML_MIDDLE =
279
<a name="l00256"></a>00256 <span class="stringliteral">"</p><p><strong>\n"</span>;
280
<a name="l00257"></a>00257 <span class="keyword">static</span> <span class="keyword">const</span> std::string FORBIDDEN_HTML_FINISH =
281
<a name="l00258"></a>00258 <span class="stringliteral">"</strong></p>\n"</span>
282
<a name="l00259"></a>00259 <span class="stringliteral">"</body></html>\n"</span>;
283
<a name="l00260"></a>00260 http::response_writer_ptr <a class="code" href="classpion_1_1http_1_1writer.html">writer</a>(<a class="code" href="classpion_1_1http_1_1response__writer.html#a75084960d3162f724342ae947e7d07e3">http::response_writer::create</a>(tcp_conn, *http_request_ptr,
284
<a name="l00261"></a>00261 boost::bind(&<a class="code" href="classpion_1_1tcp_1_1connection.html#aa7ff7a6d8325c9cbfb026c1a441523fe">tcp::connection::finish</a>, tcp_conn)));
285
<a name="l00262"></a>00262 writer->get_response().set_status_code(http::types::RESPONSE_CODE_FORBIDDEN);
286
<a name="l00263"></a>00263 writer->get_response().set_status_message(http::types::RESPONSE_MESSAGE_FORBIDDEN);
287
<a name="l00264"></a>00264 writer->write_no_copy(FORBIDDEN_HTML_START);
288
<a name="l00265"></a>00265 writer << http_request_ptr->get_resource();
289
<a name="l00266"></a>00266 writer->write_no_copy(FORBIDDEN_HTML_MIDDLE);
290
<a name="l00267"></a>00267 writer << error_msg;
291
<a name="l00268"></a>00268 writer->write_no_copy(FORBIDDEN_HTML_FINISH);
292
<a name="l00269"></a>00269 writer->send();
293
<a name="l00270"></a>00270 }
294
<a name="l00271"></a>00271
295
<a name="l00272"></a><a class="code" href="classpion_1_1http_1_1server.html#a6c9f8330d4c0569da5f719438dccbc22">00272</a> <span class="keywordtype">void</span> <a class="code" href="classpion_1_1http_1_1server.html#a6c9f8330d4c0569da5f719438dccbc22">server::handle_method_not_allowed</a>(http::request_ptr& http_request_ptr,
296
<a name="l00273"></a>00273 tcp::connection_ptr& tcp_conn,
297
<a name="l00274"></a>00274 <span class="keyword">const</span> std::string& allowed_methods)
298
<a name="l00275"></a>00275 {
299
<a name="l00276"></a>00276 <span class="keyword">static</span> <span class="keyword">const</span> std::string NOT_ALLOWED_HTML_START =
300
<a name="l00277"></a>00277 <span class="stringliteral">"<html><head>\n"</span>
301
<a name="l00278"></a>00278 <span class="stringliteral">"<title>405 Method Not Allowed</title>\n"</span>
302
<a name="l00279"></a>00279 <span class="stringliteral">"</head><body>\n"</span>
303
<a name="l00280"></a>00280 <span class="stringliteral">"<h1>Not Allowed</h1>\n"</span>
304
<a name="l00281"></a>00281 <span class="stringliteral">"<p>The requested method "</span>;
305
<a name="l00282"></a>00282 <span class="keyword">static</span> <span class="keyword">const</span> std::string NOT_ALLOWED_HTML_FINISH =
306
<a name="l00283"></a>00283 <span class="stringliteral">" is not allowed on this server.</p>\n"</span>
307
<a name="l00284"></a>00284 <span class="stringliteral">"</body></html>\n"</span>;
308
<a name="l00285"></a>00285 http::response_writer_ptr <a class="code" href="classpion_1_1http_1_1writer.html">writer</a>(<a class="code" href="classpion_1_1http_1_1response__writer.html#a75084960d3162f724342ae947e7d07e3">http::response_writer::create</a>(tcp_conn, *http_request_ptr,
309
<a name="l00286"></a>00286 boost::bind(&<a class="code" href="classpion_1_1tcp_1_1connection.html#aa7ff7a6d8325c9cbfb026c1a441523fe">tcp::connection::finish</a>, tcp_conn)));
310
<a name="l00287"></a>00287 writer->get_response().set_status_code(http::types::RESPONSE_CODE_METHOD_NOT_ALLOWED);
311
<a name="l00288"></a>00288 writer->get_response().set_status_message(http::types::RESPONSE_MESSAGE_METHOD_NOT_ALLOWED);
312
<a name="l00289"></a>00289 <span class="keywordflow">if</span> (! allowed_methods.empty())
313
<a name="l00290"></a>00290 writer->get_response().add_header(<span class="stringliteral">"Allow"</span>, allowed_methods);
314
<a name="l00291"></a>00291 writer->write_no_copy(NOT_ALLOWED_HTML_START);
315
<a name="l00292"></a>00292 writer << http_request_ptr->get_method();
316
<a name="l00293"></a>00293 writer->write_no_copy(NOT_ALLOWED_HTML_FINISH);
317
<a name="l00294"></a>00294 writer->send();
318
<a name="l00295"></a>00295 }
319
<a name="l00296"></a>00296
320
<a name="l00297"></a>00297 } <span class="comment">// end namespace http</span>
321
<a name="l00298"></a>00298 } <span class="comment">// end namespace pion</span>
49
<a name="l00026"></a>00026
50
<a name="l00027"></a>00027 <span class="comment">// server member functions</span>
51
<a name="l00028"></a>00028
52
<a name="l00029"></a><a class="code" href="classpion_1_1http_1_1server.html#a3366fd6be76ebb5ade34413be330aa6a">00029</a> <span class="keywordtype">void</span> <a class="code" href="classpion_1_1http_1_1server.html#a3366fd6be76ebb5ade34413be330aa6a">server::handle_connection</a>(tcp::connection_ptr& tcp_conn)
53
<a name="l00030"></a>00030 {
54
<a name="l00031"></a>00031 request_reader_ptr my_reader_ptr;
55
<a name="l00032"></a>00032 my_reader_ptr = <a class="code" href="classpion_1_1http_1_1request__reader.html#a889653828718972c32e8671a3b6e29b0">request_reader::create</a>(tcp_conn, boost::bind(&<a class="code" href="classpion_1_1http_1_1server.html#ad3e6180d412e8d2f135423e7e15f43ea">server::handle_request</a>,
56
<a name="l00033"></a>00033 <span class="keyword">this</span>, _1, _2, _3));
57
<a name="l00034"></a>00034 my_reader_ptr->set_max_content_length(m_max_content_length);
58
<a name="l00035"></a>00035 my_reader_ptr->receive();
59
<a name="l00036"></a>00036 }
60
<a name="l00037"></a>00037
61
<a name="l00038"></a><a class="code" href="classpion_1_1http_1_1server.html#ad3e6180d412e8d2f135423e7e15f43ea">00038</a> <span class="keywordtype">void</span> <a class="code" href="classpion_1_1http_1_1server.html#ad3e6180d412e8d2f135423e7e15f43ea">server::handle_request</a>(http::request_ptr& http_request_ptr,
62
<a name="l00039"></a>00039 tcp::connection_ptr& tcp_conn, <span class="keyword">const</span> boost::system::error_code& ec)
63
<a name="l00040"></a>00040 {
64
<a name="l00041"></a>00041 <span class="keywordflow">if</span> (ec || ! http_request_ptr->is_valid()) {
65
<a name="l00042"></a>00042 tcp_conn->set_lifecycle(tcp::connection::LIFECYCLE_CLOSE); <span class="comment">// make sure it will get closed</span>
66
<a name="l00043"></a>00043 <span class="keywordflow">if</span> (tcp_conn->is_open() && (ec.category() == <a class="code" href="classpion_1_1http_1_1parser.html#a9313aa230ae4af4c30702c0605a1f701" title="returns an instance of parser::error_category_t">http::parser::get_error_category</a>())) {
67
<a name="l00044"></a>00044 <span class="comment">// HTTP parser error</span>
68
<a name="l00045"></a>00045 PION_LOG_INFO(<a class="code" href="classpion_1_1tcp_1_1server.html#a0fd391b946961fca8604b902ddb06f7d" title="primary logging interface used by this class">m_logger</a>, <span class="stringliteral">"Invalid HTTP request ("</span> << ec.message() << <span class="stringliteral">")"</span>);
69
<a name="l00046"></a>00046 m_bad_request_handler(http_request_ptr, tcp_conn);
70
<a name="l00047"></a>00047 } <span class="keywordflow">else</span> {
71
<a name="l00048"></a>00048 <span class="keyword">static</span> <span class="keyword">const</span> boost::system::error_condition
72
<a name="l00049"></a>00049 ERRCOND_CANCELED(boost::system::errc::operation_canceled, boost::system::system_category()),
73
<a name="l00050"></a>00050 ERRCOND_EOF(boost::asio::error::eof, boost::asio::error::misc_category);
74
<a name="l00051"></a>00051
75
<a name="l00052"></a>00052 <span class="keywordflow">if</span> (ec == ERRCOND_CANCELED || ec == ERRCOND_EOF) {
76
<a name="l00053"></a>00053 <span class="comment">// don't spam the log with common (non-)errors that happen during normal operation</span>
77
<a name="l00054"></a>00054 PION_LOG_DEBUG(<a class="code" href="classpion_1_1tcp_1_1server.html#a0fd391b946961fca8604b902ddb06f7d" title="primary logging interface used by this class">m_logger</a>, <span class="stringliteral">"Lost connection on port "</span> << <a class="code" href="classpion_1_1tcp_1_1server.html#a46c1027475b8748e2a3047c7b738ef0b" title="returns tcp port number that the server listens for connections on">get_port</a>() << <span class="stringliteral">" ("</span> << ec.message() << <span class="stringliteral">")"</span>);
78
<a name="l00055"></a>00055 } <span class="keywordflow">else</span> {
79
<a name="l00056"></a>00056 PION_LOG_INFO(<a class="code" href="classpion_1_1tcp_1_1server.html#a0fd391b946961fca8604b902ddb06f7d" title="primary logging interface used by this class">m_logger</a>, <span class="stringliteral">"Lost connection on port "</span> << <a class="code" href="classpion_1_1tcp_1_1server.html#a46c1027475b8748e2a3047c7b738ef0b" title="returns tcp port number that the server listens for connections on">get_port</a>() << <span class="stringliteral">" ("</span> << ec.message() << <span class="stringliteral">")"</span>);
80
<a name="l00057"></a>00057 }
81
<a name="l00058"></a>00058
82
<a name="l00059"></a>00059 tcp_conn->finish();
83
<a name="l00060"></a>00060 }
84
<a name="l00061"></a>00061 <span class="keywordflow">return</span>;
85
<a name="l00062"></a>00062 }
86
<a name="l00063"></a>00063
87
<a name="l00064"></a>00064 PION_LOG_DEBUG(<a class="code" href="classpion_1_1tcp_1_1server.html#a0fd391b946961fca8604b902ddb06f7d" title="primary logging interface used by this class">m_logger</a>, <span class="stringliteral">"Received a valid HTTP request"</span>);
88
<a name="l00065"></a>00065
89
<a name="l00066"></a>00066 <span class="comment">// strip off trailing slash if the request has one</span>
90
<a name="l00067"></a>00067 std::string resource_requested(<a class="code" href="classpion_1_1http_1_1server.html#a375e54d0970e5d3dfc0eb50f902cf4c9">strip_trailing_slash</a>(http_request_ptr->get_resource()));
91
<a name="l00068"></a>00068
92
<a name="l00069"></a>00069 <span class="comment">// apply any redirection</span>
93
<a name="l00070"></a>00070 redirect_map_t::const_iterator it = m_redirects.find(resource_requested);
94
<a name="l00071"></a>00071 <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> num_redirects = 0;
95
<a name="l00072"></a>00072 <span class="keywordflow">while</span> (it != m_redirects.end()) {
96
<a name="l00073"></a>00073 <span class="keywordflow">if</span> (++num_redirects > MAX_REDIRECTS) {
97
<a name="l00074"></a>00074 PION_LOG_ERROR(<a class="code" href="classpion_1_1tcp_1_1server.html#a0fd391b946961fca8604b902ddb06f7d" title="primary logging interface used by this class">m_logger</a>, <span class="stringliteral">"Maximum number of redirects (server::MAX_REDIRECTS) exceeded for requested resource: "</span> << http_request_ptr->get_original_resource());
98
<a name="l00075"></a>00075 m_server_error_handler(http_request_ptr, tcp_conn, <span class="stringliteral">"Maximum number of redirects (server::MAX_REDIRECTS) exceeded for requested resource"</span>);
99
<a name="l00076"></a>00076 <span class="keywordflow">return</span>;
100
<a name="l00077"></a>00077 }
101
<a name="l00078"></a>00078 resource_requested = it->second;
102
<a name="l00079"></a>00079 http_request_ptr->change_resource(resource_requested);
103
<a name="l00080"></a>00080 it = m_redirects.find(resource_requested);
104
<a name="l00081"></a>00081 }
105
<a name="l00082"></a>00082
106
<a name="l00083"></a>00083 <span class="comment">// if authentication activated, check current request</span>
107
<a name="l00084"></a>00084 <span class="keywordflow">if</span> (m_auth_ptr) {
108
<a name="l00085"></a>00085 <span class="comment">// try to verify authentication</span>
109
<a name="l00086"></a>00086 <span class="keywordflow">if</span> (! m_auth_ptr->handle_request(http_request_ptr, tcp_conn)) {
110
<a name="l00087"></a>00087 <span class="comment">// the HTTP 401 message has already been sent by the authentication object</span>
111
<a name="l00088"></a>00088 PION_LOG_DEBUG(<a class="code" href="classpion_1_1tcp_1_1server.html#a0fd391b946961fca8604b902ddb06f7d" title="primary logging interface used by this class">m_logger</a>, <span class="stringliteral">"Authentication required for HTTP resource: "</span>
112
<a name="l00089"></a>00089 << resource_requested);
113
<a name="l00090"></a>00090 <span class="keywordflow">if</span> (http_request_ptr->get_resource() != http_request_ptr->get_original_resource()) {
114
<a name="l00091"></a>00091 PION_LOG_DEBUG(<a class="code" href="classpion_1_1tcp_1_1server.html#a0fd391b946961fca8604b902ddb06f7d" title="primary logging interface used by this class">m_logger</a>, <span class="stringliteral">"Original resource requested was: "</span> << http_request_ptr->get_original_resource());
115
<a name="l00092"></a>00092 }
116
<a name="l00093"></a>00093 <span class="keywordflow">return</span>;
117
<a name="l00094"></a>00094 }
118
<a name="l00095"></a>00095 }
119
<a name="l00096"></a>00096
120
<a name="l00097"></a>00097 <span class="comment">// search for a handler matching the resource requested</span>
121
<a name="l00098"></a>00098 <a class="code" href="classpion_1_1http_1_1server.html#a74c41bc6ca8355497abb1401339a1306" title="type of function that is used to handle requests">request_handler_t</a> request_handler;
122
<a name="l00099"></a>00099 <span class="keywordflow">if</span> (<a class="code" href="classpion_1_1http_1_1server.html#a2a0e8e0c21438a9928e680cb0d94430c">find_request_handler</a>(resource_requested, request_handler)) {
123
<a name="l00100"></a>00100
124
<a name="l00101"></a>00101 <span class="comment">// try to handle the request</span>
125
<a name="l00102"></a>00102 <span class="keywordflow">try</span> {
126
<a name="l00103"></a>00103 request_handler(http_request_ptr, tcp_conn);
127
<a name="l00104"></a>00104 PION_LOG_DEBUG(<a class="code" href="classpion_1_1tcp_1_1server.html#a0fd391b946961fca8604b902ddb06f7d" title="primary logging interface used by this class">m_logger</a>, <span class="stringliteral">"Found request handler for HTTP resource: "</span>
128
<a name="l00105"></a>00105 << resource_requested);
129
<a name="l00106"></a>00106 <span class="keywordflow">if</span> (http_request_ptr->get_resource() != http_request_ptr->get_original_resource()) {
130
<a name="l00107"></a>00107 PION_LOG_DEBUG(<a class="code" href="classpion_1_1tcp_1_1server.html#a0fd391b946961fca8604b902ddb06f7d" title="primary logging interface used by this class">m_logger</a>, <span class="stringliteral">"Original resource requested was: "</span> << http_request_ptr->get_original_resource());
131
<a name="l00108"></a>00108 }
132
<a name="l00109"></a>00109 } <span class="keywordflow">catch</span> (std::bad_alloc&) {
133
<a name="l00110"></a>00110 <span class="comment">// propagate memory errors (FATAL)</span>
134
<a name="l00111"></a>00111 <span class="keywordflow">throw</span>;
135
<a name="l00112"></a>00112 } <span class="keywordflow">catch</span> (std::exception& e) {
136
<a name="l00113"></a>00113 <span class="comment">// recover gracefully from other exceptions thrown by request handlers</span>
137
<a name="l00114"></a>00114 PION_LOG_ERROR(<a class="code" href="classpion_1_1tcp_1_1server.html#a0fd391b946961fca8604b902ddb06f7d" title="primary logging interface used by this class">m_logger</a>, <span class="stringliteral">"HTTP request handler: "</span> << pion::diagnostic_information(e));
138
<a name="l00115"></a>00115 m_server_error_handler(http_request_ptr, tcp_conn, e.what());
139
<a name="l00116"></a>00116 } <span class="keywordflow">catch</span> (boost::exception& e) {
140
<a name="l00117"></a>00117 <span class="comment">// recover gracefully from boost exceptions thrown by request handlers</span>
141
<a name="l00118"></a>00118 PION_LOG_ERROR(<a class="code" href="classpion_1_1tcp_1_1server.html#a0fd391b946961fca8604b902ddb06f7d" title="primary logging interface used by this class">m_logger</a>, <span class="stringliteral">"HTTP request handler: "</span> << pion::diagnostic_information(e));
142
<a name="l00119"></a>00119 m_server_error_handler(http_request_ptr, tcp_conn, pion::diagnostic_information(e));
143
<a name="l00120"></a>00120 }
144
<a name="l00121"></a>00121
145
<a name="l00122"></a>00122 } <span class="keywordflow">else</span> {
146
<a name="l00123"></a>00123
147
<a name="l00124"></a>00124 <span class="comment">// no web services found that could handle the request</span>
148
<a name="l00125"></a>00125 PION_LOG_INFO(<a class="code" href="classpion_1_1tcp_1_1server.html#a0fd391b946961fca8604b902ddb06f7d" title="primary logging interface used by this class">m_logger</a>, <span class="stringliteral">"No HTTP request handlers found for resource: "</span>
149
<a name="l00126"></a>00126 << resource_requested);
150
<a name="l00127"></a>00127 <span class="keywordflow">if</span> (http_request_ptr->get_resource() != http_request_ptr->get_original_resource()) {
151
<a name="l00128"></a>00128 PION_LOG_DEBUG(<a class="code" href="classpion_1_1tcp_1_1server.html#a0fd391b946961fca8604b902ddb06f7d" title="primary logging interface used by this class">m_logger</a>, <span class="stringliteral">"Original resource requested was: "</span> << http_request_ptr->get_original_resource());
152
<a name="l00129"></a>00129 }
153
<a name="l00130"></a>00130 m_not_found_handler(http_request_ptr, tcp_conn);
154
<a name="l00131"></a>00131 }
155
<a name="l00132"></a>00132 }
156
<a name="l00133"></a>00133
157
<a name="l00134"></a><a class="code" href="classpion_1_1http_1_1server.html#a2a0e8e0c21438a9928e680cb0d94430c">00134</a> <span class="keywordtype">bool</span> <a class="code" href="classpion_1_1http_1_1server.html#a2a0e8e0c21438a9928e680cb0d94430c">server::find_request_handler</a>(<span class="keyword">const</span> std::string& resource,
158
<a name="l00135"></a>00135 request_handler_t& request_handler)<span class="keyword"> const</span>
159
<a name="l00136"></a>00136 <span class="keyword"></span>{
160
<a name="l00137"></a>00137 <span class="comment">// first make sure that HTTP resources are registered</span>
161
<a name="l00138"></a>00138 boost::mutex::scoped_lock resource_lock(m_resource_mutex);
162
<a name="l00139"></a>00139 <span class="keywordflow">if</span> (m_resources.empty())
163
<a name="l00140"></a>00140 <span class="keywordflow">return</span> <span class="keyword">false</span>;
164
<a name="l00141"></a>00141
165
<a name="l00142"></a>00142 <span class="comment">// iterate through each resource entry that may match the resource</span>
166
<a name="l00143"></a>00143 resource_map_t::const_iterator i = m_resources.upper_bound(resource);
167
<a name="l00144"></a>00144 <span class="keywordflow">while</span> (i != m_resources.begin()) {
168
<a name="l00145"></a>00145 --i;
169
<a name="l00146"></a>00146 <span class="comment">// check for a match if the first part of the strings match</span>
170
<a name="l00147"></a>00147 <span class="keywordflow">if</span> (i->first.empty() || resource.compare(0, i->first.size(), i->first) == 0) {
171
<a name="l00148"></a>00148 <span class="comment">// only if the resource matches the plug-in's identifier</span>
172
<a name="l00149"></a>00149 <span class="comment">// or if resource is followed first with a '/' character</span>
173
<a name="l00150"></a>00150 <span class="keywordflow">if</span> (resource.size() == i->first.size() || resource[i->first.size()]==<span class="charliteral">'/'</span>) {
174
<a name="l00151"></a>00151 request_handler = i->second;
175
<a name="l00152"></a>00152 <span class="keywordflow">return</span> <span class="keyword">true</span>;
176
<a name="l00153"></a>00153 }
177
<a name="l00154"></a>00154 }
178
<a name="l00155"></a>00155 }
179
<a name="l00156"></a>00156
180
<a name="l00157"></a>00157 <span class="keywordflow">return</span> <span class="keyword">false</span>;
181
<a name="l00158"></a>00158 }
182
<a name="l00159"></a>00159
183
<a name="l00160"></a><a class="code" href="classpion_1_1http_1_1server.html#a312ad564b529bda2b4ddd12f02fd6d62">00160</a> <span class="keywordtype">void</span> <a class="code" href="classpion_1_1http_1_1server.html#a312ad564b529bda2b4ddd12f02fd6d62">server::add_resource</a>(<span class="keyword">const</span> std::string& resource,
184
<a name="l00161"></a>00161 request_handler_t request_handler)
185
<a name="l00162"></a>00162 {
186
<a name="l00163"></a>00163 boost::mutex::scoped_lock resource_lock(m_resource_mutex);
187
<a name="l00164"></a>00164 <span class="keyword">const</span> std::string clean_resource(<a class="code" href="classpion_1_1http_1_1server.html#a375e54d0970e5d3dfc0eb50f902cf4c9">strip_trailing_slash</a>(resource));
188
<a name="l00165"></a>00165 m_resources.insert(std::make_pair(clean_resource, request_handler));
189
<a name="l00166"></a>00166 PION_LOG_INFO(<a class="code" href="classpion_1_1tcp_1_1server.html#a0fd391b946961fca8604b902ddb06f7d" title="primary logging interface used by this class">m_logger</a>, <span class="stringliteral">"Added request handler for HTTP resource: "</span> << clean_resource);
190
<a name="l00167"></a>00167 }
191
<a name="l00168"></a>00168
192
<a name="l00169"></a><a class="code" href="classpion_1_1http_1_1server.html#ac75fe5968f4d5e5c68e6328d483d0794">00169</a> <span class="keywordtype">void</span> <a class="code" href="classpion_1_1http_1_1server.html#ac75fe5968f4d5e5c68e6328d483d0794">server::remove_resource</a>(<span class="keyword">const</span> std::string& resource)
193
<a name="l00170"></a>00170 {
194
<a name="l00171"></a>00171 boost::mutex::scoped_lock resource_lock(m_resource_mutex);
195
<a name="l00172"></a>00172 <span class="keyword">const</span> std::string clean_resource(<a class="code" href="classpion_1_1http_1_1server.html#a375e54d0970e5d3dfc0eb50f902cf4c9">strip_trailing_slash</a>(resource));
196
<a name="l00173"></a>00173 m_resources.erase(clean_resource);
197
<a name="l00174"></a>00174 PION_LOG_INFO(<a class="code" href="classpion_1_1tcp_1_1server.html#a0fd391b946961fca8604b902ddb06f7d" title="primary logging interface used by this class">m_logger</a>, <span class="stringliteral">"Removed request handler for HTTP resource: "</span> << clean_resource);
198
<a name="l00175"></a>00175 }
199
<a name="l00176"></a>00176
200
<a name="l00177"></a><a class="code" href="classpion_1_1http_1_1server.html#a114c86a620ac425e4da9ebacebda3f21">00177</a> <span class="keywordtype">void</span> <a class="code" href="classpion_1_1http_1_1server.html#a114c86a620ac425e4da9ebacebda3f21">server::add_redirect</a>(<span class="keyword">const</span> std::string& requested_resource,
201
<a name="l00178"></a>00178 <span class="keyword">const</span> std::string& new_resource)
202
<a name="l00179"></a>00179 {
203
<a name="l00180"></a>00180 boost::mutex::scoped_lock resource_lock(m_resource_mutex);
204
<a name="l00181"></a>00181 <span class="keyword">const</span> std::string clean_requested_resource(<a class="code" href="classpion_1_1http_1_1server.html#a375e54d0970e5d3dfc0eb50f902cf4c9">strip_trailing_slash</a>(requested_resource));
205
<a name="l00182"></a>00182 <span class="keyword">const</span> std::string clean_new_resource(<a class="code" href="classpion_1_1http_1_1server.html#a375e54d0970e5d3dfc0eb50f902cf4c9">strip_trailing_slash</a>(new_resource));
206
<a name="l00183"></a>00183 m_redirects.insert(std::make_pair(clean_requested_resource, clean_new_resource));
207
<a name="l00184"></a>00184 PION_LOG_INFO(<a class="code" href="classpion_1_1tcp_1_1server.html#a0fd391b946961fca8604b902ddb06f7d" title="primary logging interface used by this class">m_logger</a>, <span class="stringliteral">"Added redirection for HTTP resource "</span> << clean_requested_resource << <span class="stringliteral">" to resource "</span> << clean_new_resource);
208
<a name="l00185"></a>00185 }
209
<a name="l00186"></a>00186
210
<a name="l00187"></a><a class="code" href="classpion_1_1http_1_1server.html#a080297b6789515f60ef8b856d6e0f372">00187</a> <span class="keywordtype">void</span> <a class="code" href="classpion_1_1http_1_1server.html#a080297b6789515f60ef8b856d6e0f372">server::handle_bad_request</a>(http::request_ptr& http_request_ptr,
211
<a name="l00188"></a>00188 tcp::connection_ptr& tcp_conn)
212
<a name="l00189"></a>00189 {
213
<a name="l00190"></a>00190 <span class="keyword">static</span> <span class="keyword">const</span> std::string BAD_REQUEST_HTML =
214
<a name="l00191"></a>00191 <span class="stringliteral">"<html><head>\n"</span>
215
<a name="l00192"></a>00192 <span class="stringliteral">"<title>400 Bad Request</title>\n"</span>
216
<a name="l00193"></a>00193 <span class="stringliteral">"</head><body>\n"</span>
217
<a name="l00194"></a>00194 <span class="stringliteral">"<h1>Bad Request</h1>\n"</span>
218
<a name="l00195"></a>00195 <span class="stringliteral">"<p>Your browser sent a request that this server could not understand.</p>\n"</span>
219
<a name="l00196"></a>00196 <span class="stringliteral">"</body></html>\n"</span>;
220
<a name="l00197"></a>00197 http::response_writer_ptr <a class="code" href="classpion_1_1http_1_1writer.html">writer</a>(<a class="code" href="classpion_1_1http_1_1response__writer.html#a75084960d3162f724342ae947e7d07e3">http::response_writer::create</a>(tcp_conn, *http_request_ptr,
221
<a name="l00198"></a>00198 boost::bind(&<a class="code" href="classpion_1_1tcp_1_1connection.html#aa7ff7a6d8325c9cbfb026c1a441523fe">tcp::connection::finish</a>, tcp_conn)));
222
<a name="l00199"></a>00199 writer->get_response().set_status_code(http::types::RESPONSE_CODE_BAD_REQUEST);
223
<a name="l00200"></a>00200 writer->get_response().set_status_message(http::types::RESPONSE_MESSAGE_BAD_REQUEST);
224
<a name="l00201"></a>00201 writer->write_no_copy(BAD_REQUEST_HTML);
225
<a name="l00202"></a>00202 writer->send();
226
<a name="l00203"></a>00203 }
227
<a name="l00204"></a>00204
228
<a name="l00205"></a><a class="code" href="classpion_1_1http_1_1server.html#ae2484144be6281ac5c1cbbcea99da81b">00205</a> <span class="keywordtype">void</span> <a class="code" href="classpion_1_1http_1_1server.html#ae2484144be6281ac5c1cbbcea99da81b">server::handle_not_found_request</a>(http::request_ptr& http_request_ptr,
229
<a name="l00206"></a>00206 tcp::connection_ptr& tcp_conn)
230
<a name="l00207"></a>00207 {
231
<a name="l00208"></a>00208 <span class="keyword">static</span> <span class="keyword">const</span> std::string NOT_FOUND_HTML_START =
232
<a name="l00209"></a>00209 <span class="stringliteral">"<html><head>\n"</span>
233
<a name="l00210"></a>00210 <span class="stringliteral">"<title>404 Not Found</title>\n"</span>
234
<a name="l00211"></a>00211 <span class="stringliteral">"</head><body>\n"</span>
235
<a name="l00212"></a>00212 <span class="stringliteral">"<h1>Not Found</h1>\n"</span>
236
<a name="l00213"></a>00213 <span class="stringliteral">"<p>The requested URL "</span>;
237
<a name="l00214"></a>00214 <span class="keyword">static</span> <span class="keyword">const</span> std::string NOT_FOUND_HTML_FINISH =
238
<a name="l00215"></a>00215 <span class="stringliteral">" was not found on this server.</p>\n"</span>
239
<a name="l00216"></a>00216 <span class="stringliteral">"</body></html>\n"</span>;
240
<a name="l00217"></a>00217 http::response_writer_ptr <a class="code" href="classpion_1_1http_1_1writer.html">writer</a>(<a class="code" href="classpion_1_1http_1_1response__writer.html#a75084960d3162f724342ae947e7d07e3">http::response_writer::create</a>(tcp_conn, *http_request_ptr,
241
<a name="l00218"></a>00218 boost::bind(&<a class="code" href="classpion_1_1tcp_1_1connection.html#aa7ff7a6d8325c9cbfb026c1a441523fe">tcp::connection::finish</a>, tcp_conn)));
242
<a name="l00219"></a>00219 writer->get_response().set_status_code(http::types::RESPONSE_CODE_NOT_FOUND);
243
<a name="l00220"></a>00220 writer->get_response().set_status_message(http::types::RESPONSE_MESSAGE_NOT_FOUND);
244
<a name="l00221"></a>00221 writer->write_no_copy(NOT_FOUND_HTML_START);
245
<a name="l00222"></a>00222 writer << <a class="code" href="structpion_1_1algorithm.html#a2177ca0d0f01e6ef6d4d3bceb73d82bb" title="TODO: escapes XML/HTML-encoded strings (1 &lt; 2).">algorithm::xml_encode</a>(http_request_ptr->get_resource());
246
<a name="l00223"></a>00223 writer->write_no_copy(NOT_FOUND_HTML_FINISH);
247
<a name="l00224"></a>00224 writer->send();
248
<a name="l00225"></a>00225 }
249
<a name="l00226"></a>00226
250
<a name="l00227"></a><a class="code" href="classpion_1_1http_1_1server.html#aae06fc86091293ff3168822f0018c183">00227</a> <span class="keywordtype">void</span> <a class="code" href="classpion_1_1http_1_1server.html#aae06fc86091293ff3168822f0018c183">server::handle_server_error</a>(http::request_ptr& http_request_ptr,
251
<a name="l00228"></a>00228 tcp::connection_ptr& tcp_conn,
252
<a name="l00229"></a>00229 <span class="keyword">const</span> std::string& error_msg)
253
<a name="l00230"></a>00230 {
254
<a name="l00231"></a>00231 <span class="keyword">static</span> <span class="keyword">const</span> std::string SERVER_ERROR_HTML_START =
255
<a name="l00232"></a>00232 <span class="stringliteral">"<html><head>\n"</span>
256
<a name="l00233"></a>00233 <span class="stringliteral">"<title>500 Server Error</title>\n"</span>
257
<a name="l00234"></a>00234 <span class="stringliteral">"</head><body>\n"</span>
258
<a name="l00235"></a>00235 <span class="stringliteral">"<h1>Internal Server Error</h1>\n"</span>
259
<a name="l00236"></a>00236 <span class="stringliteral">"<p>The server encountered an internal error: <strong>"</span>;
260
<a name="l00237"></a>00237 <span class="keyword">static</span> <span class="keyword">const</span> std::string SERVER_ERROR_HTML_FINISH =
261
<a name="l00238"></a>00238 <span class="stringliteral">"</strong></p>\n"</span>
262
<a name="l00239"></a>00239 <span class="stringliteral">"</body></html>\n"</span>;
263
<a name="l00240"></a>00240 http::response_writer_ptr <a class="code" href="classpion_1_1http_1_1writer.html">writer</a>(<a class="code" href="classpion_1_1http_1_1response__writer.html#a75084960d3162f724342ae947e7d07e3">http::response_writer::create</a>(tcp_conn, *http_request_ptr,
264
<a name="l00241"></a>00241 boost::bind(&<a class="code" href="classpion_1_1tcp_1_1connection.html#aa7ff7a6d8325c9cbfb026c1a441523fe">tcp::connection::finish</a>, tcp_conn)));
265
<a name="l00242"></a>00242 writer->get_response().set_status_code(http::types::RESPONSE_CODE_SERVER_ERROR);
266
<a name="l00243"></a>00243 writer->get_response().set_status_message(http::types::RESPONSE_MESSAGE_SERVER_ERROR);
267
<a name="l00244"></a>00244 writer->write_no_copy(SERVER_ERROR_HTML_START);
268
<a name="l00245"></a>00245 writer << <a class="code" href="structpion_1_1algorithm.html#a2177ca0d0f01e6ef6d4d3bceb73d82bb" title="TODO: escapes XML/HTML-encoded strings (1 &lt; 2).">algorithm::xml_encode</a>(error_msg);
269
<a name="l00246"></a>00246 writer->write_no_copy(SERVER_ERROR_HTML_FINISH);
270
<a name="l00247"></a>00247 writer->send();
271
<a name="l00248"></a>00248 }
272
<a name="l00249"></a>00249
273
<a name="l00250"></a><a class="code" href="classpion_1_1http_1_1server.html#acc9ff11da47156419e059bebdddb5941">00250</a> <span class="keywordtype">void</span> <a class="code" href="classpion_1_1http_1_1server.html#acc9ff11da47156419e059bebdddb5941">server::handle_forbidden_request</a>(http::request_ptr& http_request_ptr,
274
<a name="l00251"></a>00251 tcp::connection_ptr& tcp_conn,
275
<a name="l00252"></a>00252 <span class="keyword">const</span> std::string& error_msg)
276
<a name="l00253"></a>00253 {
277
<a name="l00254"></a>00254 <span class="keyword">static</span> <span class="keyword">const</span> std::string FORBIDDEN_HTML_START =
278
<a name="l00255"></a>00255 <span class="stringliteral">"<html><head>\n"</span>
279
<a name="l00256"></a>00256 <span class="stringliteral">"<title>403 Forbidden</title>\n"</span>
280
<a name="l00257"></a>00257 <span class="stringliteral">"</head><body>\n"</span>
281
<a name="l00258"></a>00258 <span class="stringliteral">"<h1>Forbidden</h1>\n"</span>
282
<a name="l00259"></a>00259 <span class="stringliteral">"<p>User not authorized to access the requested URL "</span>;
283
<a name="l00260"></a>00260 <span class="keyword">static</span> <span class="keyword">const</span> std::string FORBIDDEN_HTML_MIDDLE =
284
<a name="l00261"></a>00261 <span class="stringliteral">"</p><p><strong>\n"</span>;
285
<a name="l00262"></a>00262 <span class="keyword">static</span> <span class="keyword">const</span> std::string FORBIDDEN_HTML_FINISH =
286
<a name="l00263"></a>00263 <span class="stringliteral">"</strong></p>\n"</span>
287
<a name="l00264"></a>00264 <span class="stringliteral">"</body></html>\n"</span>;
288
<a name="l00265"></a>00265 http::response_writer_ptr <a class="code" href="classpion_1_1http_1_1writer.html">writer</a>(<a class="code" href="classpion_1_1http_1_1response__writer.html#a75084960d3162f724342ae947e7d07e3">http::response_writer::create</a>(tcp_conn, *http_request_ptr,
289
<a name="l00266"></a>00266 boost::bind(&<a class="code" href="classpion_1_1tcp_1_1connection.html#aa7ff7a6d8325c9cbfb026c1a441523fe">tcp::connection::finish</a>, tcp_conn)));
290
<a name="l00267"></a>00267 writer->get_response().set_status_code(http::types::RESPONSE_CODE_FORBIDDEN);
291
<a name="l00268"></a>00268 writer->get_response().set_status_message(http::types::RESPONSE_MESSAGE_FORBIDDEN);
292
<a name="l00269"></a>00269 writer->write_no_copy(FORBIDDEN_HTML_START);
293
<a name="l00270"></a>00270 writer << <a class="code" href="structpion_1_1algorithm.html#a2177ca0d0f01e6ef6d4d3bceb73d82bb" title="TODO: escapes XML/HTML-encoded strings (1 &lt; 2).">algorithm::xml_encode</a>(http_request_ptr->get_resource());
294
<a name="l00271"></a>00271 writer->write_no_copy(FORBIDDEN_HTML_MIDDLE);
295
<a name="l00272"></a>00272 writer << error_msg;
296
<a name="l00273"></a>00273 writer->write_no_copy(FORBIDDEN_HTML_FINISH);
297
<a name="l00274"></a>00274 writer->send();
298
<a name="l00275"></a>00275 }
299
<a name="l00276"></a>00276
300
<a name="l00277"></a><a class="code" href="classpion_1_1http_1_1server.html#a6c9f8330d4c0569da5f719438dccbc22">00277</a> <span class="keywordtype">void</span> <a class="code" href="classpion_1_1http_1_1server.html#a6c9f8330d4c0569da5f719438dccbc22">server::handle_method_not_allowed</a>(http::request_ptr& http_request_ptr,
301
<a name="l00278"></a>00278 tcp::connection_ptr& tcp_conn,
302
<a name="l00279"></a>00279 <span class="keyword">const</span> std::string& allowed_methods)
303
<a name="l00280"></a>00280 {
304
<a name="l00281"></a>00281 <span class="keyword">static</span> <span class="keyword">const</span> std::string NOT_ALLOWED_HTML_START =
305
<a name="l00282"></a>00282 <span class="stringliteral">"<html><head>\n"</span>
306
<a name="l00283"></a>00283 <span class="stringliteral">"<title>405 Method Not Allowed</title>\n"</span>
307
<a name="l00284"></a>00284 <span class="stringliteral">"</head><body>\n"</span>
308
<a name="l00285"></a>00285 <span class="stringliteral">"<h1>Not Allowed</h1>\n"</span>
309
<a name="l00286"></a>00286 <span class="stringliteral">"<p>The requested method "</span>;
310
<a name="l00287"></a>00287 <span class="keyword">static</span> <span class="keyword">const</span> std::string NOT_ALLOWED_HTML_FINISH =
311
<a name="l00288"></a>00288 <span class="stringliteral">" is not allowed on this server.</p>\n"</span>
312
<a name="l00289"></a>00289 <span class="stringliteral">"</body></html>\n"</span>;
313
<a name="l00290"></a>00290 http::response_writer_ptr <a class="code" href="classpion_1_1http_1_1writer.html">writer</a>(<a class="code" href="classpion_1_1http_1_1response__writer.html#a75084960d3162f724342ae947e7d07e3">http::response_writer::create</a>(tcp_conn, *http_request_ptr,
314
<a name="l00291"></a>00291 boost::bind(&<a class="code" href="classpion_1_1tcp_1_1connection.html#aa7ff7a6d8325c9cbfb026c1a441523fe">tcp::connection::finish</a>, tcp_conn)));
315
<a name="l00292"></a>00292 writer->get_response().set_status_code(http::types::RESPONSE_CODE_METHOD_NOT_ALLOWED);
316
<a name="l00293"></a>00293 writer->get_response().set_status_message(http::types::RESPONSE_MESSAGE_METHOD_NOT_ALLOWED);
317
<a name="l00294"></a>00294 <span class="keywordflow">if</span> (! allowed_methods.empty())
318
<a name="l00295"></a>00295 writer->get_response().add_header(<span class="stringliteral">"Allow"</span>, allowed_methods);
319
<a name="l00296"></a>00296 writer->write_no_copy(NOT_ALLOWED_HTML_START);
320
<a name="l00297"></a>00297 writer << <a class="code" href="structpion_1_1algorithm.html#a2177ca0d0f01e6ef6d4d3bceb73d82bb" title="TODO: escapes XML/HTML-encoded strings (1 &lt; 2).">algorithm::xml_encode</a>(http_request_ptr->get_method());
321
<a name="l00298"></a>00298 writer->write_no_copy(NOT_ALLOWED_HTML_FINISH);
322
<a name="l00299"></a>00299 writer->send();
323
<a name="l00300"></a>00300 }
324
<a name="l00301"></a>00301
325
<a name="l00302"></a>00302 } <span class="comment">// end namespace http</span>
326
<a name="l00303"></a>00303 } <span class="comment">// end namespace pion</span>
322
327
</pre></div></div>
323
<hr size="1"/><address style="text-align: right;"><small>Generated on 15 Apr 2013 for pion by
328
<hr size="1"/><address style="text-align: right;"><small>Generated on 26 Jul 2013 for pion by
324
329
<a href="http://www.doxygen.org/index.html">
325
330
<img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.6.1 </small></address>