blob: 11940e361b02918822dee0caf1350b8ae161cdb1 [file] [log] [blame]
Dave Barach1015a1e2017-05-08 19:15:03 -04001/*
Florin Coras54a51fd2019-02-07 15:34:52 -08002* Copyright (c) 2015-2019 Cisco and/or its affiliates.
Dave Barach1015a1e2017-05-08 19:15:03 -04003* Licensed under the Apache License, Version 2.0 (the "License");
4* you may not use this file except in compliance with the License.
5* You may obtain a copy of the License at:
6*
7* http://www.apache.org/licenses/LICENSE-2.0
8*
9* Unless required by applicable law or agreed to in writing, software
10* distributed under the License is distributed on an "AS IS" BASIS,
11* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12* See the License for the specific language governing permissions and
13* limitations under the License.
14*/
15
16#include <vnet/vnet.h>
Dave Barach1015a1e2017-05-08 19:15:03 -040017#include <vnet/session/application.h>
18#include <vnet/session/application_interface.h>
Florin Coras54a51fd2019-02-07 15:34:52 -080019#include <vnet/session/session.h>
Dave Barach1015a1e2017-05-08 19:15:03 -040020
Dave Barach1015a1e2017-05-08 19:15:03 -040021typedef enum
22{
23 EVENT_WAKEUP = 1,
24} http_process_event_t;
25
26typedef struct
27{
Florin Coras844a36d2018-12-20 09:50:50 -080028 u32 hs_index;
29 u32 thread_index;
Florin Coras0e9c33b2017-08-14 22:33:41 -070030 u64 node_index;
Florin Coras4399c2e2018-01-25 06:34:42 -080031} http_server_args;
Florin Coras0e9c33b2017-08-14 22:33:41 -070032
Florin Coras844a36d2018-12-20 09:50:50 -080033typedef enum
34{
35 HTTP_STATE_CLOSED,
36 HTTP_STATE_ESTABLISHED,
37 HTTP_STATE_OK_SENT,
38} http_session_state_t;
39typedef struct
40{
41 CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
42#define _(type, name) type name;
43 foreach_app_session_field
44#undef _
45 u32 thread_index;
46 u8 *rx_buf;
47 u32 vpp_session_index;
48 u64 vpp_session_handle;
49} http_session_t;
50
Florin Coras0e9c33b2017-08-14 22:33:41 -070051typedef struct
52{
Florin Coras844a36d2018-12-20 09:50:50 -080053 http_session_t **sessions;
54 clib_rwlock_t sessions_lock;
55 u32 **session_to_http_session;
56
Florin Coras3c2fed52018-07-04 04:15:05 -070057 svm_msg_q_t **vpp_queue;
Dave Barach1015a1e2017-05-08 19:15:03 -040058
59 uword *handler_by_get_request;
60
61 u32 *free_http_cli_process_node_indices;
62
63 /* Sever's event queue */
Florin Corase86a8ed2018-01-05 03:20:25 -080064 svm_queue_t *vl_input_queue;
Dave Barach1015a1e2017-05-08 19:15:03 -040065
66 /* API client handle */
67 u32 my_client_index;
68
69 u32 app_index;
70
71 /* process node index for evnt scheduling */
72 u32 node_index;
Florin Coras1d6d0852017-11-17 14:26:01 -080073
74 u32 prealloc_fifos;
75 u32 private_segment_size;
76 u32 fifo_size;
Florin Coras371ca502018-02-21 12:07:41 -080077 u8 *uri;
Florin Coras844a36d2018-12-20 09:50:50 -080078 u32 is_static;
Dave Barach1015a1e2017-05-08 19:15:03 -040079 vlib_main_t *vlib_main;
80} http_server_main_t;
81
82http_server_main_t http_server_main;
83
84static void
Florin Coras844a36d2018-12-20 09:50:50 -080085http_server_sessions_reader_lock (void)
86{
87 clib_rwlock_reader_lock (&http_server_main.sessions_lock);
88}
89
90static void
91http_server_sessions_reader_unlock (void)
92{
93 clib_rwlock_reader_unlock (&http_server_main.sessions_lock);
94}
95
96static void
97http_server_sessions_writer_lock (void)
98{
99 clib_rwlock_writer_lock (&http_server_main.sessions_lock);
100}
101
102static void
103http_server_sessions_writer_unlock (void)
104{
105 clib_rwlock_writer_unlock (&http_server_main.sessions_lock);
106}
107
108static void
109http_server_session_lookup_add (u32 thread_index, u32 s_index, u32 hs_index)
110{
111 http_server_main_t *hsm = &http_server_main;
112 vec_validate (hsm->session_to_http_session[thread_index], s_index);
113 hsm->session_to_http_session[thread_index][s_index] = hs_index;
114}
115
116static void
117http_server_session_lookup_del (u32 thread_index, u32 s_index)
118{
119 http_server_main_t *hsm = &http_server_main;
120 hsm->session_to_http_session[thread_index][s_index] = ~0;
121}
122
123static http_session_t *
124http_server_session_lookup (u32 thread_index, u32 s_index)
125{
126 http_server_main_t *hsm = &http_server_main;
127 u32 hs_index;
128
129 if (s_index < vec_len (hsm->session_to_http_session[thread_index]))
130 {
131 hs_index = hsm->session_to_http_session[thread_index][s_index];
132 if (hs_index < vec_len (hsm->sessions[thread_index]))
133 return &hsm->sessions[thread_index][hs_index];
134 }
135 return 0;
136}
137
138static http_session_t *
139http_server_session_alloc (u32 thread_index)
140{
141 http_server_main_t *hsm = &http_server_main;
142 http_session_t *hs;
143 pool_get (hsm->sessions[thread_index], hs);
144 memset (hs, 0, sizeof (*hs));
145 hs->session_index = hs - hsm->sessions[thread_index];
146 hs->thread_index = thread_index;
147 return hs;
148}
149
150static http_session_t *
151http_server_session_get (u32 thread_index, u32 hs_index)
152{
153 http_server_main_t *hsm = &http_server_main;
154 return pool_elt_at_index (hsm->sessions[thread_index], hs_index);
155}
156
157static void
158http_server_session_free (http_session_t * hs)
159{
160 http_server_main_t *hsm = &http_server_main;
161 pool_put (hsm->sessions[hs->thread_index], hs);
162 if (CLIB_DEBUG)
163 memset (hs, 0xfa, sizeof (*hs));
164}
165
166static void
167http_server_session_cleanup (http_session_t * hs)
168{
169 if (!hs)
170 return;
171 http_server_session_lookup_del (hs->thread_index, hs->vpp_session_index);
172 vec_free (hs->rx_buf);
173 http_server_session_free (hs);
174}
175
176static void
177http_process_free (http_server_args * args)
Dave Barach1015a1e2017-05-08 19:15:03 -0400178{
179 vlib_node_runtime_t *rt;
180 vlib_main_t *vm = &vlib_global_main;
181 http_server_main_t *hsm = &http_server_main;
182 vlib_node_t *n;
183 u32 node_index;
Florin Coras4399c2e2018-01-25 06:34:42 -0800184 http_server_args **save_args;
Dave Barach1015a1e2017-05-08 19:15:03 -0400185
Florin Coras0e9c33b2017-08-14 22:33:41 -0700186 node_index = args->node_index;
Dave Barach1015a1e2017-05-08 19:15:03 -0400187 ASSERT (node_index != 0);
188
189 n = vlib_get_node (vm, node_index);
Florin Coras0e9c33b2017-08-14 22:33:41 -0700190 rt = vlib_node_get_runtime (vm, n->index);
191 save_args = vlib_node_get_runtime_data (vm, n->index);
Dave Barach1015a1e2017-05-08 19:15:03 -0400192
Dave Barach1015a1e2017-05-08 19:15:03 -0400193 /* Reset process session pointer */
Florin Coras0e9c33b2017-08-14 22:33:41 -0700194 clib_mem_free (*save_args);
195 *save_args = 0;
Dave Barach1015a1e2017-05-08 19:15:03 -0400196
197 /* Turn off the process node */
198 vlib_node_set_state (vm, rt->node_index, VLIB_NODE_STATE_DISABLED);
199
200 /* add node index to the freelist */
201 vec_add1 (hsm->free_http_cli_process_node_indices, node_index);
202}
203
Florin Coras898cd8f2018-06-08 02:02:13 -0700204/* *INDENT-OFF* */
Florin Coras844a36d2018-12-20 09:50:50 -0800205static const char *http_ok =
206 "HTTP/1.1 200 OK\r\n";
207
Florin Coras898cd8f2018-06-08 02:02:13 -0700208static const char *http_response =
Florin Coras898cd8f2018-06-08 02:02:13 -0700209 "Content-Type: text/html\r\n"
210 "Expires: Mon, 11 Jan 1970 10:10:10 GMT\r\n"
Florin Coras844a36d2018-12-20 09:50:50 -0800211 "Connection: close \r\n"
Florin Coras898cd8f2018-06-08 02:02:13 -0700212 "Pragma: no-cache\r\n"
213 "Content-Length: %d\r\n\r\n%s";
Dave Barach1015a1e2017-05-08 19:15:03 -0400214
Florin Coras898cd8f2018-06-08 02:02:13 -0700215static const char *http_error_template =
216 "HTTP/1.1 %s\r\n"
217 "Content-Type: text/html\r\n"
218 "Expires: Mon, 11 Jan 1970 10:10:10 GMT\r\n"
219 "Connection: close\r\n"
220 "Pragma: no-cache\r\n"
221 "Content-Length: 0\r\n\r\n";
Dave Barach1015a1e2017-05-08 19:15:03 -0400222
223/* Header, including incantation to suppress favicon.ico requests */
Florin Coras898cd8f2018-06-08 02:02:13 -0700224static const char *html_header_template =
225 "<html><head><title>%v</title></head>"
226 "<link rel=\"icon\" href=\"data:,\">"
227 "<body><pre>";
Dave Barach1015a1e2017-05-08 19:15:03 -0400228
Florin Coras898cd8f2018-06-08 02:02:13 -0700229static const char *html_footer =
230 "</pre></body></html>\r\n";
Dave Barach1015a1e2017-05-08 19:15:03 -0400231
Florin Coras898cd8f2018-06-08 02:02:13 -0700232static const char *html_header_static =
233 "<html><head><title>static reply</title></head>"
234 "<link rel=\"icon\" href=\"data:,\">"
235 "<body><pre>hello</pre></body></html>\r\n";
236/* *INDENT-ON* */
Florin Coras149d62f2017-11-01 15:05:49 -0700237
238static u8 *static_http;
Florin Coras844a36d2018-12-20 09:50:50 -0800239static u8 *static_ok;
Florin Coras149d62f2017-11-01 15:05:49 -0700240
Dave Barach1015a1e2017-05-08 19:15:03 -0400241static void
242http_cli_output (uword arg, u8 * buffer, uword buffer_bytes)
243{
244 u8 **output_vecp = (u8 **) arg;
245 u8 *output_vec;
246 u32 offset;
247
248 output_vec = *output_vecp;
249
250 offset = vec_len (output_vec);
251 vec_validate (output_vec, offset + buffer_bytes - 1);
Dave Barach178cf492018-11-13 16:34:13 -0500252 clib_memcpy_fast (output_vec + offset, buffer, buffer_bytes);
Dave Barach1015a1e2017-05-08 19:15:03 -0400253
254 *output_vecp = output_vec;
255}
256
257void
Florin Coras844a36d2018-12-20 09:50:50 -0800258send_data (http_session_t * hs, u8 * data)
Dave Barach1015a1e2017-05-08 19:15:03 -0400259{
Florin Coras844a36d2018-12-20 09:50:50 -0800260 http_server_main_t *hsm = &http_server_main;
261 vnet_disconnect_args_t _a = { 0 }, *a = &_a;
262 vlib_main_t *vm = vlib_get_main ();
263 f64 last_sent_timer = vlib_time_now (vm);
Dave Barach1015a1e2017-05-08 19:15:03 -0400264 u32 offset, bytes_to_send;
265 f64 delay = 10e-3;
Dave Barach1015a1e2017-05-08 19:15:03 -0400266
267 bytes_to_send = vec_len (data);
268 offset = 0;
269
270 while (bytes_to_send > 0)
271 {
272 int actual_transfer;
273
274 actual_transfer = svm_fifo_enqueue_nowait
Florin Coras844a36d2018-12-20 09:50:50 -0800275 (hs->tx_fifo, bytes_to_send, data + offset);
Dave Barach1015a1e2017-05-08 19:15:03 -0400276
277 /* Made any progress? */
278 if (actual_transfer <= 0)
279 {
Dave Barach26dc58b2019-03-29 14:08:45 -0400280 http_server_sessions_reader_unlock ();
Dave Barach1015a1e2017-05-08 19:15:03 -0400281 vlib_process_suspend (vm, delay);
Dave Barach26dc58b2019-03-29 14:08:45 -0400282 http_server_sessions_reader_lock ();
283
Dave Barach1015a1e2017-05-08 19:15:03 -0400284 /* 10s deadman timer */
285 if (vlib_time_now (vm) > last_sent_timer + 10.0)
286 {
Florin Coras844a36d2018-12-20 09:50:50 -0800287 a->handle = hs->vpp_session_handle;
288 a->app_index = hsm->app_index;
289 vnet_disconnect_session (a);
Dave Barach1015a1e2017-05-08 19:15:03 -0400290 break;
291 }
292 /* Exponential backoff, within reason */
293 if (delay < 1.0)
294 delay = delay * 2.0;
295 }
296 else
297 {
298 last_sent_timer = vlib_time_now (vm);
299 offset += actual_transfer;
300 bytes_to_send -= actual_transfer;
301
Florin Coras844a36d2018-12-20 09:50:50 -0800302 if (svm_fifo_set_event (hs->tx_fifo))
303 session_send_io_evt_to_thread (hs->tx_fifo,
304 SESSION_IO_EVT_TX_FLUSH);
Dave Barach1015a1e2017-05-08 19:15:03 -0400305 delay = 10e-3;
306 }
307 }
308}
309
310static void
Florin Coras844a36d2018-12-20 09:50:50 -0800311send_error (http_session_t * hs, char *str)
Dave Barach1015a1e2017-05-08 19:15:03 -0400312{
313 u8 *data;
314
315 data = format (0, http_error_template, str);
Florin Coras844a36d2018-12-20 09:50:50 -0800316 send_data (hs, data);
Dave Barach1015a1e2017-05-08 19:15:03 -0400317 vec_free (data);
318}
319
320static uword
Florin Coras844a36d2018-12-20 09:50:50 -0800321http_cli_process (vlib_main_t * vm, vlib_node_runtime_t * rt,
322 vlib_frame_t * f)
Dave Barach1015a1e2017-05-08 19:15:03 -0400323{
Florin Coras844a36d2018-12-20 09:50:50 -0800324 u8 *request = 0, *reply = 0, *http = 0, *html = 0;
Dave Barach1015a1e2017-05-08 19:15:03 -0400325 http_server_main_t *hsm = &http_server_main;
Florin Coras4399c2e2018-01-25 06:34:42 -0800326 http_server_args **save_args;
327 http_server_args *args;
Dave Barach1015a1e2017-05-08 19:15:03 -0400328 unformat_input_t input;
Florin Coras844a36d2018-12-20 09:50:50 -0800329 http_session_t *hs;
Dave Barach1015a1e2017-05-08 19:15:03 -0400330 int i;
Dave Barach1015a1e2017-05-08 19:15:03 -0400331
Florin Coras0e9c33b2017-08-14 22:33:41 -0700332 save_args = vlib_node_get_runtime_data (hsm->vlib_main, rt->node_index);
333 args = *save_args;
Dave Barach1015a1e2017-05-08 19:15:03 -0400334
Florin Coras844a36d2018-12-20 09:50:50 -0800335 http_server_sessions_reader_lock ();
336
337 hs = http_server_session_get (args->thread_index, args->hs_index);
338 ASSERT (hs);
339
340 request = hs->rx_buf;
Dave Barach1015a1e2017-05-08 19:15:03 -0400341 if (vec_len (request) < 7)
342 {
Florin Coras844a36d2018-12-20 09:50:50 -0800343 send_error (hs, "400 Bad Request");
Dave Barach1015a1e2017-05-08 19:15:03 -0400344 goto out;
345 }
346
347 for (i = 0; i < vec_len (request) - 4; i++)
348 {
349 if (request[i] == 'G' &&
350 request[i + 1] == 'E' &&
351 request[i + 2] == 'T' && request[i + 3] == ' ')
352 goto found;
353 }
354bad_request:
Florin Coras844a36d2018-12-20 09:50:50 -0800355 send_error (hs, "400 Bad Request");
Dave Barach1015a1e2017-05-08 19:15:03 -0400356 goto out;
357
358found:
359 /* Lose "GET " */
360 vec_delete (request, i + 5, 0);
361
362 /* Replace slashes with spaces, stop at the end of the path */
363 i = 0;
364 while (1)
365 {
366 if (request[i] == '/')
367 request[i] = ' ';
368 else if (request[i] == ' ')
369 {
370 /* vlib_cli_input is vector-based, no need for a NULL */
371 _vec_len (request) = i;
372 break;
373 }
374 i++;
375 /* Should never happen */
376 if (i == vec_len (request))
377 goto bad_request;
378 }
379
380 /* Generate the html header */
381 html = format (0, html_header_template, request /* title */ );
382
383 /* Run the command */
Florin Coras844a36d2018-12-20 09:50:50 -0800384 unformat_init_vector (&input, vec_dup (request));
Dave Barach1015a1e2017-05-08 19:15:03 -0400385 vlib_cli_input (vm, &input, http_cli_output, (uword) & reply);
386 unformat_free (&input);
387 request = 0;
388
389 /* Generate the html page */
390 html = format (html, "%v", reply);
391 html = format (html, html_footer);
392 /* And the http reply */
Florin Coras844a36d2018-12-20 09:50:50 -0800393 http = format (0, http_ok, vec_len (http_ok));
394 http = format (http, http_response, vec_len (html), html);
Dave Barach1015a1e2017-05-08 19:15:03 -0400395
396 /* Send it */
Florin Coras844a36d2018-12-20 09:50:50 -0800397 send_data (hs, http);
Dave Barach1015a1e2017-05-08 19:15:03 -0400398
399out:
400 /* Cleanup */
Florin Coras844a36d2018-12-20 09:50:50 -0800401 http_server_sessions_reader_unlock ();
Dave Barach1015a1e2017-05-08 19:15:03 -0400402 vec_free (reply);
403 vec_free (html);
404 vec_free (http);
405
Florin Coras844a36d2018-12-20 09:50:50 -0800406 http_process_free (args);
Dave Barach1015a1e2017-05-08 19:15:03 -0400407 return (0);
408}
409
410static void
Florin Coras4399c2e2018-01-25 06:34:42 -0800411alloc_http_process (http_server_args * args)
Dave Barach1015a1e2017-05-08 19:15:03 -0400412{
413 char *name;
414 vlib_node_t *n;
415 http_server_main_t *hsm = &http_server_main;
416 vlib_main_t *vm = hsm->vlib_main;
417 uword l = vec_len (hsm->free_http_cli_process_node_indices);
Florin Coras4399c2e2018-01-25 06:34:42 -0800418 http_server_args **save_args;
Dave Barach1015a1e2017-05-08 19:15:03 -0400419
420 if (vec_len (hsm->free_http_cli_process_node_indices) > 0)
421 {
422 n = vlib_get_node (vm, hsm->free_http_cli_process_node_indices[l - 1]);
Dave Barach1015a1e2017-05-08 19:15:03 -0400423 vlib_node_set_state (vm, n->index, VLIB_NODE_STATE_POLLING);
Dave Barach1015a1e2017-05-08 19:15:03 -0400424 _vec_len (hsm->free_http_cli_process_node_indices) = l - 1;
425 }
426 else
427 {
428 static vlib_node_registration_t r = {
429 .function = http_cli_process,
430 .type = VLIB_NODE_TYPE_PROCESS,
431 .process_log2_n_stack_bytes = 16,
432 .runtime_data_bytes = sizeof (void *),
433 };
434
435 name = (char *) format (0, "http-cli-%d", l);
Dave Barach1015a1e2017-05-08 19:15:03 -0400436 r.name = name;
437 vlib_register_node (vm, &r);
438 vec_free (name);
439
440 n = vlib_get_node (vm, r.index);
441 }
442
Florin Coras0e9c33b2017-08-14 22:33:41 -0700443 /* Save the node index in the args. It won't be zero. */
444 args->node_index = n->index;
Dave Barach1015a1e2017-05-08 19:15:03 -0400445
Florin Coras0e9c33b2017-08-14 22:33:41 -0700446 /* Save the args (pointer) in the node runtime */
447 save_args = vlib_node_get_runtime_data (vm, n->index);
448 *save_args = args;
Dave Barach1015a1e2017-05-08 19:15:03 -0400449
450 vlib_start_process (vm, n->runtime_index);
451}
452
Florin Coras0e9c33b2017-08-14 22:33:41 -0700453static void
454alloc_http_process_callback (void *cb_args)
455{
Florin Coras4399c2e2018-01-25 06:34:42 -0800456 alloc_http_process ((http_server_args *) cb_args);
Florin Coras0e9c33b2017-08-14 22:33:41 -0700457}
458
459static int
Florin Coras844a36d2018-12-20 09:50:50 -0800460session_rx_request (http_session_t * hs)
Florin Coras0e9c33b2017-08-14 22:33:41 -0700461{
Florin Coras844a36d2018-12-20 09:50:50 -0800462 u32 max_dequeue, cursize;
463 int n_read;
Florin Coras0e9c33b2017-08-14 22:33:41 -0700464
Florin Coras844a36d2018-12-20 09:50:50 -0800465 cursize = vec_len (hs->rx_buf);
466 max_dequeue = svm_fifo_max_dequeue (hs->rx_fifo);
Florin Coras0e9c33b2017-08-14 22:33:41 -0700467 if (PREDICT_FALSE (max_dequeue == 0))
Florin Coras149d62f2017-11-01 15:05:49 -0700468 return -1;
Florin Coras0e9c33b2017-08-14 22:33:41 -0700469
Florin Coras844a36d2018-12-20 09:50:50 -0800470 vec_validate (hs->rx_buf, cursize + max_dequeue - 1);
471 n_read = app_recv_stream_raw (hs->rx_fifo, hs->rx_buf + cursize,
472 max_dequeue, 0, 0 /* peek */ );
473 ASSERT (n_read == max_dequeue);
474 if (svm_fifo_is_empty (hs->rx_fifo))
475 svm_fifo_unset_event (hs->rx_fifo);
Florin Coras0e9c33b2017-08-14 22:33:41 -0700476
Florin Coras844a36d2018-12-20 09:50:50 -0800477 _vec_len (hs->rx_buf) = cursize + n_read;
Florin Coras149d62f2017-11-01 15:05:49 -0700478 return 0;
479}
480
481static int
Florin Coras288eaab2019-02-03 15:26:14 -0800482http_server_rx_callback (session_t * s)
Florin Coras149d62f2017-11-01 15:05:49 -0700483{
Florin Coras4399c2e2018-01-25 06:34:42 -0800484 http_server_args *args;
Florin Coras844a36d2018-12-20 09:50:50 -0800485 http_session_t *hs;
JingLiuZTE7cafe762017-11-08 15:01:27 +0800486 int rv;
Florin Coras149d62f2017-11-01 15:05:49 -0700487
Florin Coras844a36d2018-12-20 09:50:50 -0800488 http_server_sessions_reader_lock ();
489
490 hs = http_server_session_lookup (s->thread_index, s->session_index);
491 if (!hs || hs->session_state != HTTP_STATE_ESTABLISHED)
492 return -1;
493
494 rv = session_rx_request (hs);
JingLiuZTE7cafe762017-11-08 15:01:27 +0800495 if (rv)
496 return rv;
Florin Coras0e9c33b2017-08-14 22:33:41 -0700497
498 /* send the command to a new/recycled vlib process */
499 args = clib_mem_alloc (sizeof (*args));
Florin Coras844a36d2018-12-20 09:50:50 -0800500 args->hs_index = hs->session_index;
501 args->thread_index = hs->thread_index;
502
503 http_server_sessions_reader_unlock ();
Florin Coras0e9c33b2017-08-14 22:33:41 -0700504
505 /* Send an RPC request via the thread-0 input node */
506 if (vlib_get_thread_index () != 0)
Florin Coras3c2fed52018-07-04 04:15:05 -0700507 session_send_rpc_evt_to_thread (0, alloc_http_process_callback, args);
Florin Coras0e9c33b2017-08-14 22:33:41 -0700508 else
509 alloc_http_process (args);
510 return 0;
511}
512
Dave Barach1015a1e2017-05-08 19:15:03 -0400513static int
Florin Coras288eaab2019-02-03 15:26:14 -0800514http_server_rx_callback_static (session_t * s)
Florin Coras149d62f2017-11-01 15:05:49 -0700515{
516 http_server_main_t *hsm = &http_server_main;
Florin Coras844a36d2018-12-20 09:50:50 -0800517 vnet_disconnect_args_t _a = { 0 }, *a = &_a;
518 http_session_t *hs;
519 u32 request_len;
Florin Coras149d62f2017-11-01 15:05:49 -0700520 u8 *request = 0;
Florin Coras844a36d2018-12-20 09:50:50 -0800521 int i, rv;
Florin Coras149d62f2017-11-01 15:05:49 -0700522
Florin Coras844a36d2018-12-20 09:50:50 -0800523 hs = http_server_session_lookup (s->thread_index, s->session_index);
524 if (!hs || hs->session_state == HTTP_STATE_CLOSED)
525 return 0;
526
527 /* ok 200 was sent */
528 if (hs->session_state == HTTP_STATE_OK_SENT)
529 goto send_data;
530
531 rv = session_rx_request (hs);
JingLiuZTE7cafe762017-11-08 15:01:27 +0800532 if (rv)
Florin Coras844a36d2018-12-20 09:50:50 -0800533 goto wait_for_data;
Florin Coras149d62f2017-11-01 15:05:49 -0700534
Florin Coras844a36d2018-12-20 09:50:50 -0800535 request = hs->rx_buf;
536 request_len = vec_len (request);
Florin Coras149d62f2017-11-01 15:05:49 -0700537 if (vec_len (request) < 7)
538 {
Florin Coras844a36d2018-12-20 09:50:50 -0800539 send_error (hs, "400 Bad Request");
540 goto close_session;
Florin Coras149d62f2017-11-01 15:05:49 -0700541 }
542
Florin Coras844a36d2018-12-20 09:50:50 -0800543 for (i = 0; i < request_len - 4; i++)
Florin Coras149d62f2017-11-01 15:05:49 -0700544 {
545 if (request[i] == 'G' &&
546 request[i + 1] == 'E' &&
547 request[i + 2] == 'T' && request[i + 3] == ' ')
Florin Coras844a36d2018-12-20 09:50:50 -0800548 goto find_end;
Florin Coras149d62f2017-11-01 15:05:49 -0700549 }
Florin Coras844a36d2018-12-20 09:50:50 -0800550 send_error (hs, "400 Bad Request");
551 goto close_session;
Florin Coras149d62f2017-11-01 15:05:49 -0700552
Florin Coras844a36d2018-12-20 09:50:50 -0800553find_end:
Florin Coras149d62f2017-11-01 15:05:49 -0700554
Florin Coras844a36d2018-12-20 09:50:50 -0800555 /* check for the end sequence: /r/n/r/n */
556 if (request[request_len - 1] != 0xa || request[request_len - 3] != 0xa
557 || request[request_len - 2] != 0xd || request[request_len - 4] != 0xd)
558 goto wait_for_data;
Florin Coras149d62f2017-11-01 15:05:49 -0700559
Florin Coras844a36d2018-12-20 09:50:50 -0800560 /* send 200 OK first */
561 send_data (hs, static_ok);
562 hs->session_state = HTTP_STATE_OK_SENT;
563 goto postpone;
564
565send_data:
566 send_data (hs, static_http);
567 http_server_session_cleanup (hs);
568
569close_session:
570 a->handle = session_handle (s);
571 a->app_index = hsm->app_index;
572 vnet_disconnect_session (a);
573 return 0;
574
575postpone:
Florin Coras78b5fa62019-02-21 20:04:15 -0800576 (void) svm_fifo_set_event (hs->rx_fifo);
Florin Corasf6c43132019-03-01 12:41:21 -0800577 session_send_io_evt_to_thread (hs->rx_fifo, SESSION_IO_EVT_BUILTIN_RX);
Florin Coras844a36d2018-12-20 09:50:50 -0800578 return 0;
579
580wait_for_data:
Florin Coras149d62f2017-11-01 15:05:49 -0700581 return 0;
582}
583
584static int
Florin Coras288eaab2019-02-03 15:26:14 -0800585http_server_session_accept_callback (session_t * s)
Dave Barach1015a1e2017-05-08 19:15:03 -0400586{
Florin Coras844a36d2018-12-20 09:50:50 -0800587 http_server_main_t *hsm = &http_server_main;
588 http_session_t *hs;
Dave Barach1015a1e2017-05-08 19:15:03 -0400589
Florin Coras844a36d2018-12-20 09:50:50 -0800590 hsm->vpp_queue[s->thread_index] =
Florin Coras31c99552019-03-01 13:00:58 -0800591 session_main_get_vpp_event_queue (s->thread_index);
Florin Coras844a36d2018-12-20 09:50:50 -0800592
593 if (!hsm->is_static)
594 http_server_sessions_writer_lock ();
595
596 hs = http_server_session_alloc (s->thread_index);
597 http_server_session_lookup_add (s->thread_index, s->session_index,
598 hs->session_index);
Florin Coras288eaab2019-02-03 15:26:14 -0800599 hs->rx_fifo = s->rx_fifo;
600 hs->tx_fifo = s->tx_fifo;
Florin Coras844a36d2018-12-20 09:50:50 -0800601 hs->vpp_session_index = s->session_index;
602 hs->vpp_session_handle = session_handle (s);
603 hs->session_state = HTTP_STATE_ESTABLISHED;
604
605 if (!hsm->is_static)
606 http_server_sessions_writer_unlock ();
607
Dave Barach1015a1e2017-05-08 19:15:03 -0400608 s->session_state = SESSION_STATE_READY;
Dave Barach1015a1e2017-05-08 19:15:03 -0400609 return 0;
610}
611
612static void
Florin Coras288eaab2019-02-03 15:26:14 -0800613http_server_session_disconnect_callback (session_t * s)
Dave Barach1015a1e2017-05-08 19:15:03 -0400614{
Florin Coras844a36d2018-12-20 09:50:50 -0800615 http_server_main_t *hsm = &http_server_main;
Florin Coras4af830c2018-12-04 09:21:36 -0800616 vnet_disconnect_args_t _a = { 0 }, *a = &_a;
Florin Coras844a36d2018-12-20 09:50:50 -0800617 http_session_t *hs;
618
619 if (!hsm->is_static)
620 http_server_sessions_writer_lock ();
621
622 hs = http_server_session_lookup (s->thread_index, s->session_index);
623 http_server_session_cleanup (hs);
624
625 if (!hsm->is_static)
626 http_server_sessions_writer_unlock ();
Dave Barach1015a1e2017-05-08 19:15:03 -0400627
Florin Coras3cbc04b2017-10-02 00:18:51 -0700628 a->handle = session_handle (s);
Florin Coras844a36d2018-12-20 09:50:50 -0800629 a->app_index = hsm->app_index;
Dave Barach1015a1e2017-05-08 19:15:03 -0400630 vnet_disconnect_session (a);
631}
632
633static void
Florin Coras288eaab2019-02-03 15:26:14 -0800634http_server_session_reset_callback (session_t * s)
Dave Barach1015a1e2017-05-08 19:15:03 -0400635{
Florin Coras844a36d2018-12-20 09:50:50 -0800636 http_server_main_t *hsm = &http_server_main;
Florin Coras4af830c2018-12-04 09:21:36 -0800637 vnet_disconnect_args_t _a = { 0 }, *a = &_a;
Florin Coras844a36d2018-12-20 09:50:50 -0800638 http_session_t *hs;
639
640 if (!hsm->is_static)
641 http_server_sessions_writer_lock ();
642
643 hs = http_server_session_lookup (s->thread_index, s->session_index);
644 http_server_session_cleanup (hs);
645
646 if (!hsm->is_static)
647 http_server_sessions_writer_unlock ();
648
Florin Coras4af830c2018-12-04 09:21:36 -0800649 a->handle = session_handle (s);
Florin Coras844a36d2018-12-20 09:50:50 -0800650 a->app_index = hsm->app_index;
Florin Coras4af830c2018-12-04 09:21:36 -0800651 vnet_disconnect_session (a);
Dave Barach1015a1e2017-05-08 19:15:03 -0400652}
653
Dave Barach1015a1e2017-05-08 19:15:03 -0400654static int
Florin Coras4399c2e2018-01-25 06:34:42 -0800655http_server_session_connected_callback (u32 app_index, u32 api_context,
Florin Coras288eaab2019-02-03 15:26:14 -0800656 session_t * s, u8 is_fail)
Dave Barach1015a1e2017-05-08 19:15:03 -0400657{
658 clib_warning ("called...");
659 return -1;
660}
661
662static int
Florin Corasfa76a762018-11-29 12:40:10 -0800663http_server_add_segment_callback (u32 client_index, u64 segment_handle)
Dave Barach1015a1e2017-05-08 19:15:03 -0400664{
665 clib_warning ("called...");
666 return -1;
667}
668
Florin Coras4399c2e2018-01-25 06:34:42 -0800669static session_cb_vft_t http_server_session_cb_vft = {
670 .session_accept_callback = http_server_session_accept_callback,
671 .session_disconnect_callback = http_server_session_disconnect_callback,
672 .session_connected_callback = http_server_session_connected_callback,
673 .add_segment_callback = http_server_add_segment_callback,
Florin Coras371ca502018-02-21 12:07:41 -0800674 .builtin_app_rx_callback = http_server_rx_callback,
Florin Coras4399c2e2018-01-25 06:34:42 -0800675 .session_reset_callback = http_server_session_reset_callback
Dave Barach1015a1e2017-05-08 19:15:03 -0400676};
677
Dave Barach1015a1e2017-05-08 19:15:03 -0400678static int
Florin Coras844a36d2018-12-20 09:50:50 -0800679http_server_attach ()
Dave Barach1015a1e2017-05-08 19:15:03 -0400680{
Florin Coras371ca502018-02-21 12:07:41 -0800681 vnet_app_add_tls_cert_args_t _a_cert, *a_cert = &_a_cert;
682 vnet_app_add_tls_key_args_t _a_key, *a_key = &_a_key;
Dave Barach1015a1e2017-05-08 19:15:03 -0400683 http_server_main_t *hsm = &http_server_main;
Florin Corasff6e7692017-12-11 04:59:01 -0800684 u64 options[APP_OPTIONS_N_OPTIONS];
Dave Barach1015a1e2017-05-08 19:15:03 -0400685 vnet_app_attach_args_t _a, *a = &_a;
Florin Corasff6e7692017-12-11 04:59:01 -0800686 u32 segment_size = 128 << 20;
Dave Barach1015a1e2017-05-08 19:15:03 -0400687
Dave Barachb7b92992018-10-17 10:38:51 -0400688 clib_memset (a, 0, sizeof (*a));
689 clib_memset (options, 0, sizeof (options));
Dave Barach1015a1e2017-05-08 19:15:03 -0400690
Florin Corasff6e7692017-12-11 04:59:01 -0800691 if (hsm->private_segment_size)
692 segment_size = hsm->private_segment_size;
693
Florin Coras844a36d2018-12-20 09:50:50 -0800694 a->api_client_index = ~0;
695 a->name = format (0, "test_http_server");
Florin Coras4399c2e2018-01-25 06:34:42 -0800696 a->session_cb_vft = &http_server_session_cb_vft;
Dave Barach1015a1e2017-05-08 19:15:03 -0400697 a->options = options;
Florin Corasff6e7692017-12-11 04:59:01 -0800698 a->options[APP_OPTIONS_SEGMENT_SIZE] = segment_size;
699 a->options[APP_OPTIONS_RX_FIFO_SIZE] =
Florin Coras1d6d0852017-11-17 14:26:01 -0800700 hsm->fifo_size ? hsm->fifo_size : 8 << 10;
Florin Corasff6e7692017-12-11 04:59:01 -0800701 a->options[APP_OPTIONS_TX_FIFO_SIZE] =
Florin Coras1d6d0852017-11-17 14:26:01 -0800702 hsm->fifo_size ? hsm->fifo_size : 32 << 10;
Florin Coras7999e832017-10-31 01:51:04 -0700703 a->options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
Florin Coras1d6d0852017-11-17 14:26:01 -0800704 a->options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] = hsm->prealloc_fifos;
Dave Barach1015a1e2017-05-08 19:15:03 -0400705
706 if (vnet_application_attach (a))
707 {
Florin Coras844a36d2018-12-20 09:50:50 -0800708 vec_free (a->name);
Dave Barach1015a1e2017-05-08 19:15:03 -0400709 clib_warning ("failed to attach server");
710 return -1;
711 }
Florin Coras844a36d2018-12-20 09:50:50 -0800712 vec_free (a->name);
Dave Barach1015a1e2017-05-08 19:15:03 -0400713 hsm->app_index = a->app_index;
Florin Coras371ca502018-02-21 12:07:41 -0800714
Dave Barachb7b92992018-10-17 10:38:51 -0400715 clib_memset (a_cert, 0, sizeof (*a_cert));
Florin Coras371ca502018-02-21 12:07:41 -0800716 a_cert->app_index = a->app_index;
717 vec_validate (a_cert->cert, test_srv_crt_rsa_len);
Dave Barach178cf492018-11-13 16:34:13 -0500718 clib_memcpy_fast (a_cert->cert, test_srv_crt_rsa, test_srv_crt_rsa_len);
Florin Coras371ca502018-02-21 12:07:41 -0800719 vnet_app_add_tls_cert (a_cert);
720
Dave Barachb7b92992018-10-17 10:38:51 -0400721 clib_memset (a_key, 0, sizeof (*a_key));
Florin Coras371ca502018-02-21 12:07:41 -0800722 a_key->app_index = a->app_index;
723 vec_validate (a_key->key, test_srv_key_rsa_len);
Dave Barach178cf492018-11-13 16:34:13 -0500724 clib_memcpy_fast (a_key->key, test_srv_key_rsa, test_srv_key_rsa_len);
Florin Coras371ca502018-02-21 12:07:41 -0800725 vnet_app_add_tls_key (a_key);
726
Dave Barach1015a1e2017-05-08 19:15:03 -0400727 return 0;
728}
729
730static int
Florin Coras4399c2e2018-01-25 06:34:42 -0800731http_server_listen ()
Dave Barach1015a1e2017-05-08 19:15:03 -0400732{
733 http_server_main_t *hsm = &http_server_main;
Florin Corasc9940fc2019-02-05 20:55:11 -0800734 vnet_listen_args_t _a, *a = &_a;
Dave Barachb7b92992018-10-17 10:38:51 -0400735 clib_memset (a, 0, sizeof (*a));
Dave Barach1015a1e2017-05-08 19:15:03 -0400736 a->app_index = hsm->app_index;
737 a->uri = "tcp://0.0.0.0/80";
Florin Coras371ca502018-02-21 12:07:41 -0800738 if (hsm->uri)
739 a->uri = (char *) hsm->uri;
Dave Barach1015a1e2017-05-08 19:15:03 -0400740 return vnet_bind_uri (a);
741}
742
743static int
Florin Coras4399c2e2018-01-25 06:34:42 -0800744http_server_create (vlib_main_t * vm)
Dave Barach1015a1e2017-05-08 19:15:03 -0400745{
Florin Coras844a36d2018-12-20 09:50:50 -0800746 vlib_thread_main_t *vtm = vlib_get_thread_main ();
Dave Barach1015a1e2017-05-08 19:15:03 -0400747 http_server_main_t *hsm = &http_server_main;
748 u32 num_threads;
Dave Barach1015a1e2017-05-08 19:15:03 -0400749
750 num_threads = 1 /* main thread */ + vtm->n_threads;
Florin Coras844a36d2018-12-20 09:50:50 -0800751 vec_validate (hsm->vpp_queue, num_threads - 1);
752 vec_validate (hsm->sessions, num_threads - 1);
753 vec_validate (hsm->session_to_http_session, num_threads - 1);
Dave Barach1015a1e2017-05-08 19:15:03 -0400754
Florin Coras844a36d2018-12-20 09:50:50 -0800755 clib_rwlock_init (&hsm->sessions_lock);
756
757 if (http_server_attach ())
Dave Barach1015a1e2017-05-08 19:15:03 -0400758 {
759 clib_warning ("failed to attach server");
760 return -1;
761 }
Florin Coras4399c2e2018-01-25 06:34:42 -0800762 if (http_server_listen ())
Dave Barach1015a1e2017-05-08 19:15:03 -0400763 {
764 clib_warning ("failed to start listening");
765 return -1;
766 }
767 return 0;
768}
769
Dave Barach1015a1e2017-05-08 19:15:03 -0400770static clib_error_t *
Florin Coras4399c2e2018-01-25 06:34:42 -0800771http_server_create_command_fn (vlib_main_t * vm,
772 unformat_input_t * input,
773 vlib_cli_command_t * cmd)
Dave Barach1015a1e2017-05-08 19:15:03 -0400774{
Florin Coras0e9c33b2017-08-14 22:33:41 -0700775 http_server_main_t *hsm = &http_server_main;
Dave Barach26dc58b2019-03-29 14:08:45 -0400776 unformat_input_t _line_input, *line_input = &_line_input;
Florin Coras1d6d0852017-11-17 14:26:01 -0800777 u64 seg_size;
Florin Coras149d62f2017-11-01 15:05:49 -0700778 u8 *html;
Florin Coras844a36d2018-12-20 09:50:50 -0800779 int rv;
Dave Barach1015a1e2017-05-08 19:15:03 -0400780
Florin Coras1d6d0852017-11-17 14:26:01 -0800781 hsm->prealloc_fifos = 0;
782 hsm->private_segment_size = 0;
783 hsm->fifo_size = 0;
Florin Coras844a36d2018-12-20 09:50:50 -0800784 hsm->is_static = 0;
Dave Barach26dc58b2019-03-29 14:08:45 -0400785
786 /* Get a line of input. */
787 if (!unformat_user (input, unformat_line_input, line_input))
788 goto start_server;
789
790 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
Florin Coras149d62f2017-11-01 15:05:49 -0700791 {
Dave Barach26dc58b2019-03-29 14:08:45 -0400792 if (unformat (line_input, "static"))
Florin Coras844a36d2018-12-20 09:50:50 -0800793 hsm->is_static = 1;
Dave Barach26dc58b2019-03-29 14:08:45 -0400794 else
795 if (unformat (line_input, "prealloc-fifos %d", &hsm->prealloc_fifos))
Florin Coras1d6d0852017-11-17 14:26:01 -0800796 ;
Dave Barach26dc58b2019-03-29 14:08:45 -0400797 else if (unformat (line_input, "private-segment-size %U",
Florin Coras1d6d0852017-11-17 14:26:01 -0800798 unformat_memory_size, &seg_size))
799 {
800 if (seg_size >= 0x100000000ULL)
801 {
802 vlib_cli_output (vm, "private segment size %llu, too large",
803 seg_size);
804 return 0;
805 }
806 hsm->private_segment_size = seg_size;
807 }
Dave Barach26dc58b2019-03-29 14:08:45 -0400808 else if (unformat (line_input, "fifo-size %d", &hsm->fifo_size))
Florin Coras1d6d0852017-11-17 14:26:01 -0800809 hsm->fifo_size <<= 10;
Dave Barach26dc58b2019-03-29 14:08:45 -0400810 else if (unformat (line_input, "uri %s", &hsm->uri))
Florin Coras371ca502018-02-21 12:07:41 -0800811 ;
Florin Coras149d62f2017-11-01 15:05:49 -0700812 else
813 return clib_error_return (0, "unknown input `%U'",
Dave Barach26dc58b2019-03-29 14:08:45 -0400814 format_unformat_error, line_input);
Florin Coras149d62f2017-11-01 15:05:49 -0700815 }
Dave Barach26dc58b2019-03-29 14:08:45 -0400816 unformat_free (line_input);
817
818start_server:
819
Florin Coras0e9c33b2017-08-14 22:33:41 -0700820 if (hsm->my_client_index != (u32) ~ 0)
821 return clib_error_return (0, "test http server is already running");
822
Dave Barach1015a1e2017-05-08 19:15:03 -0400823 vnet_session_enable_disable (vm, 1 /* turn on TCP, etc. */ );
Florin Coras149d62f2017-11-01 15:05:49 -0700824
Florin Coras844a36d2018-12-20 09:50:50 -0800825 if (hsm->is_static)
Florin Coras149d62f2017-11-01 15:05:49 -0700826 {
Florin Coras371ca502018-02-21 12:07:41 -0800827 http_server_session_cb_vft.builtin_app_rx_callback =
Florin Coras149d62f2017-11-01 15:05:49 -0700828 http_server_rx_callback_static;
829 html = format (0, html_header_static);
830 static_http = format (0, http_response, vec_len (html), html);
Florin Coras844a36d2018-12-20 09:50:50 -0800831 static_ok = format (0, http_ok);
Florin Coras149d62f2017-11-01 15:05:49 -0700832 }
Florin Coras4399c2e2018-01-25 06:34:42 -0800833 rv = http_server_create (vm);
Dave Barach1015a1e2017-05-08 19:15:03 -0400834 switch (rv)
835 {
836 case 0:
837 break;
838 default:
839 return clib_error_return (0, "server_create returned %d", rv);
840 }
841 return 0;
842}
843
844/* *INDENT-OFF* */
Florin Coras4399c2e2018-01-25 06:34:42 -0800845VLIB_CLI_COMMAND (http_server_create_command, static) =
Dave Barach1015a1e2017-05-08 19:15:03 -0400846{
847 .path = "test http server",
848 .short_help = "test http server",
Florin Coras4399c2e2018-01-25 06:34:42 -0800849 .function = http_server_create_command_fn,
Dave Barach1015a1e2017-05-08 19:15:03 -0400850};
851/* *INDENT-ON* */
852
853static clib_error_t *
Florin Coras4399c2e2018-01-25 06:34:42 -0800854http_server_main_init (vlib_main_t * vm)
Dave Barach1015a1e2017-05-08 19:15:03 -0400855{
856 http_server_main_t *hsm = &http_server_main;
Florin Coras149d62f2017-11-01 15:05:49 -0700857
Dave Barach1015a1e2017-05-08 19:15:03 -0400858 hsm->my_client_index = ~0;
859 hsm->vlib_main = vm;
Dave Barach1015a1e2017-05-08 19:15:03 -0400860 return 0;
861}
862
Florin Coras4399c2e2018-01-25 06:34:42 -0800863VLIB_INIT_FUNCTION (http_server_main_init);
Dave Barach1015a1e2017-05-08 19:15:03 -0400864
865/*
866* fd.io coding-style-patch-verification: ON
867*
868* Local Variables:
869* eval: (c-set-style "gnu")
870* End:
871*/