blob: b33a086f99a6709552b4e917b7451af158cc70c0 [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 {
280 vlib_process_suspend (vm, delay);
281 /* 10s deadman timer */
282 if (vlib_time_now (vm) > last_sent_timer + 10.0)
283 {
Florin Coras844a36d2018-12-20 09:50:50 -0800284 a->handle = hs->vpp_session_handle;
285 a->app_index = hsm->app_index;
286 vnet_disconnect_session (a);
Dave Barach1015a1e2017-05-08 19:15:03 -0400287 break;
288 }
289 /* Exponential backoff, within reason */
290 if (delay < 1.0)
291 delay = delay * 2.0;
292 }
293 else
294 {
295 last_sent_timer = vlib_time_now (vm);
296 offset += actual_transfer;
297 bytes_to_send -= actual_transfer;
298
Florin Coras844a36d2018-12-20 09:50:50 -0800299 if (svm_fifo_set_event (hs->tx_fifo))
300 session_send_io_evt_to_thread (hs->tx_fifo,
301 SESSION_IO_EVT_TX_FLUSH);
Dave Barach1015a1e2017-05-08 19:15:03 -0400302 delay = 10e-3;
303 }
304 }
305}
306
307static void
Florin Coras844a36d2018-12-20 09:50:50 -0800308send_error (http_session_t * hs, char *str)
Dave Barach1015a1e2017-05-08 19:15:03 -0400309{
310 u8 *data;
311
312 data = format (0, http_error_template, str);
Florin Coras844a36d2018-12-20 09:50:50 -0800313 send_data (hs, data);
Dave Barach1015a1e2017-05-08 19:15:03 -0400314 vec_free (data);
315}
316
317static uword
Florin Coras844a36d2018-12-20 09:50:50 -0800318http_cli_process (vlib_main_t * vm, vlib_node_runtime_t * rt,
319 vlib_frame_t * f)
Dave Barach1015a1e2017-05-08 19:15:03 -0400320{
Florin Coras844a36d2018-12-20 09:50:50 -0800321 u8 *request = 0, *reply = 0, *http = 0, *html = 0;
Dave Barach1015a1e2017-05-08 19:15:03 -0400322 http_server_main_t *hsm = &http_server_main;
Florin Coras4399c2e2018-01-25 06:34:42 -0800323 http_server_args **save_args;
324 http_server_args *args;
Dave Barach1015a1e2017-05-08 19:15:03 -0400325 unformat_input_t input;
Florin Coras844a36d2018-12-20 09:50:50 -0800326 http_session_t *hs;
Dave Barach1015a1e2017-05-08 19:15:03 -0400327 int i;
Dave Barach1015a1e2017-05-08 19:15:03 -0400328
Florin Coras0e9c33b2017-08-14 22:33:41 -0700329 save_args = vlib_node_get_runtime_data (hsm->vlib_main, rt->node_index);
330 args = *save_args;
Dave Barach1015a1e2017-05-08 19:15:03 -0400331
Florin Coras844a36d2018-12-20 09:50:50 -0800332 http_server_sessions_reader_lock ();
333
334 hs = http_server_session_get (args->thread_index, args->hs_index);
335 ASSERT (hs);
336
337 request = hs->rx_buf;
Dave Barach1015a1e2017-05-08 19:15:03 -0400338 if (vec_len (request) < 7)
339 {
Florin Coras844a36d2018-12-20 09:50:50 -0800340 send_error (hs, "400 Bad Request");
Dave Barach1015a1e2017-05-08 19:15:03 -0400341 goto out;
342 }
343
344 for (i = 0; i < vec_len (request) - 4; i++)
345 {
346 if (request[i] == 'G' &&
347 request[i + 1] == 'E' &&
348 request[i + 2] == 'T' && request[i + 3] == ' ')
349 goto found;
350 }
351bad_request:
Florin Coras844a36d2018-12-20 09:50:50 -0800352 send_error (hs, "400 Bad Request");
Dave Barach1015a1e2017-05-08 19:15:03 -0400353 goto out;
354
355found:
356 /* Lose "GET " */
357 vec_delete (request, i + 5, 0);
358
359 /* Replace slashes with spaces, stop at the end of the path */
360 i = 0;
361 while (1)
362 {
363 if (request[i] == '/')
364 request[i] = ' ';
365 else if (request[i] == ' ')
366 {
367 /* vlib_cli_input is vector-based, no need for a NULL */
368 _vec_len (request) = i;
369 break;
370 }
371 i++;
372 /* Should never happen */
373 if (i == vec_len (request))
374 goto bad_request;
375 }
376
377 /* Generate the html header */
378 html = format (0, html_header_template, request /* title */ );
379
380 /* Run the command */
Florin Coras844a36d2018-12-20 09:50:50 -0800381 unformat_init_vector (&input, vec_dup (request));
Dave Barach1015a1e2017-05-08 19:15:03 -0400382 vlib_cli_input (vm, &input, http_cli_output, (uword) & reply);
383 unformat_free (&input);
384 request = 0;
385
386 /* Generate the html page */
387 html = format (html, "%v", reply);
388 html = format (html, html_footer);
389 /* And the http reply */
Florin Coras844a36d2018-12-20 09:50:50 -0800390 http = format (0, http_ok, vec_len (http_ok));
391 http = format (http, http_response, vec_len (html), html);
Dave Barach1015a1e2017-05-08 19:15:03 -0400392
393 /* Send it */
Florin Coras844a36d2018-12-20 09:50:50 -0800394 send_data (hs, http);
Dave Barach1015a1e2017-05-08 19:15:03 -0400395
396out:
397 /* Cleanup */
Florin Coras844a36d2018-12-20 09:50:50 -0800398 http_server_sessions_reader_unlock ();
Dave Barach1015a1e2017-05-08 19:15:03 -0400399 vec_free (reply);
400 vec_free (html);
401 vec_free (http);
402
Florin Coras844a36d2018-12-20 09:50:50 -0800403 http_process_free (args);
Dave Barach1015a1e2017-05-08 19:15:03 -0400404 return (0);
405}
406
407static void
Florin Coras4399c2e2018-01-25 06:34:42 -0800408alloc_http_process (http_server_args * args)
Dave Barach1015a1e2017-05-08 19:15:03 -0400409{
410 char *name;
411 vlib_node_t *n;
412 http_server_main_t *hsm = &http_server_main;
413 vlib_main_t *vm = hsm->vlib_main;
414 uword l = vec_len (hsm->free_http_cli_process_node_indices);
Florin Coras4399c2e2018-01-25 06:34:42 -0800415 http_server_args **save_args;
Dave Barach1015a1e2017-05-08 19:15:03 -0400416
417 if (vec_len (hsm->free_http_cli_process_node_indices) > 0)
418 {
419 n = vlib_get_node (vm, hsm->free_http_cli_process_node_indices[l - 1]);
Dave Barach1015a1e2017-05-08 19:15:03 -0400420 vlib_node_set_state (vm, n->index, VLIB_NODE_STATE_POLLING);
Dave Barach1015a1e2017-05-08 19:15:03 -0400421 _vec_len (hsm->free_http_cli_process_node_indices) = l - 1;
422 }
423 else
424 {
425 static vlib_node_registration_t r = {
426 .function = http_cli_process,
427 .type = VLIB_NODE_TYPE_PROCESS,
428 .process_log2_n_stack_bytes = 16,
429 .runtime_data_bytes = sizeof (void *),
430 };
431
432 name = (char *) format (0, "http-cli-%d", l);
Dave Barach1015a1e2017-05-08 19:15:03 -0400433 r.name = name;
434 vlib_register_node (vm, &r);
435 vec_free (name);
436
437 n = vlib_get_node (vm, r.index);
438 }
439
Florin Coras0e9c33b2017-08-14 22:33:41 -0700440 /* Save the node index in the args. It won't be zero. */
441 args->node_index = n->index;
Dave Barach1015a1e2017-05-08 19:15:03 -0400442
Florin Coras0e9c33b2017-08-14 22:33:41 -0700443 /* Save the args (pointer) in the node runtime */
444 save_args = vlib_node_get_runtime_data (vm, n->index);
445 *save_args = args;
Dave Barach1015a1e2017-05-08 19:15:03 -0400446
447 vlib_start_process (vm, n->runtime_index);
448}
449
Florin Coras0e9c33b2017-08-14 22:33:41 -0700450static void
451alloc_http_process_callback (void *cb_args)
452{
Florin Coras4399c2e2018-01-25 06:34:42 -0800453 alloc_http_process ((http_server_args *) cb_args);
Florin Coras0e9c33b2017-08-14 22:33:41 -0700454}
455
456static int
Florin Coras844a36d2018-12-20 09:50:50 -0800457session_rx_request (http_session_t * hs)
Florin Coras0e9c33b2017-08-14 22:33:41 -0700458{
Florin Coras844a36d2018-12-20 09:50:50 -0800459 u32 max_dequeue, cursize;
460 int n_read;
Florin Coras0e9c33b2017-08-14 22:33:41 -0700461
Florin Coras844a36d2018-12-20 09:50:50 -0800462 cursize = vec_len (hs->rx_buf);
463 max_dequeue = svm_fifo_max_dequeue (hs->rx_fifo);
Florin Coras0e9c33b2017-08-14 22:33:41 -0700464 if (PREDICT_FALSE (max_dequeue == 0))
Florin Coras149d62f2017-11-01 15:05:49 -0700465 return -1;
Florin Coras0e9c33b2017-08-14 22:33:41 -0700466
Florin Coras844a36d2018-12-20 09:50:50 -0800467 vec_validate (hs->rx_buf, cursize + max_dequeue - 1);
468 n_read = app_recv_stream_raw (hs->rx_fifo, hs->rx_buf + cursize,
469 max_dequeue, 0, 0 /* peek */ );
470 ASSERT (n_read == max_dequeue);
471 if (svm_fifo_is_empty (hs->rx_fifo))
472 svm_fifo_unset_event (hs->rx_fifo);
Florin Coras0e9c33b2017-08-14 22:33:41 -0700473
Florin Coras844a36d2018-12-20 09:50:50 -0800474 _vec_len (hs->rx_buf) = cursize + n_read;
Florin Coras149d62f2017-11-01 15:05:49 -0700475 return 0;
476}
477
478static int
Florin Coras288eaab2019-02-03 15:26:14 -0800479http_server_rx_callback (session_t * s)
Florin Coras149d62f2017-11-01 15:05:49 -0700480{
Florin Coras4399c2e2018-01-25 06:34:42 -0800481 http_server_args *args;
Florin Coras844a36d2018-12-20 09:50:50 -0800482 http_session_t *hs;
JingLiuZTE7cafe762017-11-08 15:01:27 +0800483 int rv;
Florin Coras149d62f2017-11-01 15:05:49 -0700484
Florin Coras844a36d2018-12-20 09:50:50 -0800485 http_server_sessions_reader_lock ();
486
487 hs = http_server_session_lookup (s->thread_index, s->session_index);
488 if (!hs || hs->session_state != HTTP_STATE_ESTABLISHED)
489 return -1;
490
491 rv = session_rx_request (hs);
JingLiuZTE7cafe762017-11-08 15:01:27 +0800492 if (rv)
493 return rv;
Florin Coras0e9c33b2017-08-14 22:33:41 -0700494
495 /* send the command to a new/recycled vlib process */
496 args = clib_mem_alloc (sizeof (*args));
Florin Coras844a36d2018-12-20 09:50:50 -0800497 args->hs_index = hs->session_index;
498 args->thread_index = hs->thread_index;
499
500 http_server_sessions_reader_unlock ();
Florin Coras0e9c33b2017-08-14 22:33:41 -0700501
502 /* Send an RPC request via the thread-0 input node */
503 if (vlib_get_thread_index () != 0)
Florin Coras3c2fed52018-07-04 04:15:05 -0700504 session_send_rpc_evt_to_thread (0, alloc_http_process_callback, args);
Florin Coras0e9c33b2017-08-14 22:33:41 -0700505 else
506 alloc_http_process (args);
507 return 0;
508}
509
Dave Barach1015a1e2017-05-08 19:15:03 -0400510static int
Florin Coras288eaab2019-02-03 15:26:14 -0800511http_server_rx_callback_static (session_t * s)
Florin Coras149d62f2017-11-01 15:05:49 -0700512{
513 http_server_main_t *hsm = &http_server_main;
Florin Coras844a36d2018-12-20 09:50:50 -0800514 vnet_disconnect_args_t _a = { 0 }, *a = &_a;
515 http_session_t *hs;
516 u32 request_len;
Florin Coras149d62f2017-11-01 15:05:49 -0700517 u8 *request = 0;
Florin Coras844a36d2018-12-20 09:50:50 -0800518 int i, rv;
Florin Coras149d62f2017-11-01 15:05:49 -0700519
Florin Coras844a36d2018-12-20 09:50:50 -0800520 hs = http_server_session_lookup (s->thread_index, s->session_index);
521 if (!hs || hs->session_state == HTTP_STATE_CLOSED)
522 return 0;
523
524 /* ok 200 was sent */
525 if (hs->session_state == HTTP_STATE_OK_SENT)
526 goto send_data;
527
528 rv = session_rx_request (hs);
JingLiuZTE7cafe762017-11-08 15:01:27 +0800529 if (rv)
Florin Coras844a36d2018-12-20 09:50:50 -0800530 goto wait_for_data;
Florin Coras149d62f2017-11-01 15:05:49 -0700531
Florin Coras844a36d2018-12-20 09:50:50 -0800532 request = hs->rx_buf;
533 request_len = vec_len (request);
Florin Coras149d62f2017-11-01 15:05:49 -0700534 if (vec_len (request) < 7)
535 {
Florin Coras844a36d2018-12-20 09:50:50 -0800536 send_error (hs, "400 Bad Request");
537 goto close_session;
Florin Coras149d62f2017-11-01 15:05:49 -0700538 }
539
Florin Coras844a36d2018-12-20 09:50:50 -0800540 for (i = 0; i < request_len - 4; i++)
Florin Coras149d62f2017-11-01 15:05:49 -0700541 {
542 if (request[i] == 'G' &&
543 request[i + 1] == 'E' &&
544 request[i + 2] == 'T' && request[i + 3] == ' ')
Florin Coras844a36d2018-12-20 09:50:50 -0800545 goto find_end;
Florin Coras149d62f2017-11-01 15:05:49 -0700546 }
Florin Coras844a36d2018-12-20 09:50:50 -0800547 send_error (hs, "400 Bad Request");
548 goto close_session;
Florin Coras149d62f2017-11-01 15:05:49 -0700549
Florin Coras844a36d2018-12-20 09:50:50 -0800550find_end:
Florin Coras149d62f2017-11-01 15:05:49 -0700551
Florin Coras844a36d2018-12-20 09:50:50 -0800552 /* check for the end sequence: /r/n/r/n */
553 if (request[request_len - 1] != 0xa || request[request_len - 3] != 0xa
554 || request[request_len - 2] != 0xd || request[request_len - 4] != 0xd)
555 goto wait_for_data;
Florin Coras149d62f2017-11-01 15:05:49 -0700556
Florin Coras844a36d2018-12-20 09:50:50 -0800557 /* send 200 OK first */
558 send_data (hs, static_ok);
559 hs->session_state = HTTP_STATE_OK_SENT;
560 goto postpone;
561
562send_data:
563 send_data (hs, static_http);
564 http_server_session_cleanup (hs);
565
566close_session:
567 a->handle = session_handle (s);
568 a->app_index = hsm->app_index;
569 vnet_disconnect_session (a);
570 return 0;
571
572postpone:
Florin Coras78b5fa62019-02-21 20:04:15 -0800573 (void) svm_fifo_set_event (hs->rx_fifo);
Florin Corasf6c43132019-03-01 12:41:21 -0800574 session_send_io_evt_to_thread (hs->rx_fifo, SESSION_IO_EVT_BUILTIN_RX);
Florin Coras844a36d2018-12-20 09:50:50 -0800575 return 0;
576
577wait_for_data:
Florin Coras149d62f2017-11-01 15:05:49 -0700578 return 0;
579}
580
581static int
Florin Coras288eaab2019-02-03 15:26:14 -0800582http_server_session_accept_callback (session_t * s)
Dave Barach1015a1e2017-05-08 19:15:03 -0400583{
Florin Coras844a36d2018-12-20 09:50:50 -0800584 http_server_main_t *hsm = &http_server_main;
585 http_session_t *hs;
Dave Barach1015a1e2017-05-08 19:15:03 -0400586
Florin Coras844a36d2018-12-20 09:50:50 -0800587 hsm->vpp_queue[s->thread_index] =
Florin Coras31c99552019-03-01 13:00:58 -0800588 session_main_get_vpp_event_queue (s->thread_index);
Florin Coras844a36d2018-12-20 09:50:50 -0800589
590 if (!hsm->is_static)
591 http_server_sessions_writer_lock ();
592
593 hs = http_server_session_alloc (s->thread_index);
594 http_server_session_lookup_add (s->thread_index, s->session_index,
595 hs->session_index);
Florin Coras288eaab2019-02-03 15:26:14 -0800596 hs->rx_fifo = s->rx_fifo;
597 hs->tx_fifo = s->tx_fifo;
Florin Coras844a36d2018-12-20 09:50:50 -0800598 hs->vpp_session_index = s->session_index;
599 hs->vpp_session_handle = session_handle (s);
600 hs->session_state = HTTP_STATE_ESTABLISHED;
601
602 if (!hsm->is_static)
603 http_server_sessions_writer_unlock ();
604
Dave Barach1015a1e2017-05-08 19:15:03 -0400605 s->session_state = SESSION_STATE_READY;
Dave Barach1015a1e2017-05-08 19:15:03 -0400606 return 0;
607}
608
609static void
Florin Coras288eaab2019-02-03 15:26:14 -0800610http_server_session_disconnect_callback (session_t * s)
Dave Barach1015a1e2017-05-08 19:15:03 -0400611{
Florin Coras844a36d2018-12-20 09:50:50 -0800612 http_server_main_t *hsm = &http_server_main;
Florin Coras4af830c2018-12-04 09:21:36 -0800613 vnet_disconnect_args_t _a = { 0 }, *a = &_a;
Florin Coras844a36d2018-12-20 09:50:50 -0800614 http_session_t *hs;
615
616 if (!hsm->is_static)
617 http_server_sessions_writer_lock ();
618
619 hs = http_server_session_lookup (s->thread_index, s->session_index);
620 http_server_session_cleanup (hs);
621
622 if (!hsm->is_static)
623 http_server_sessions_writer_unlock ();
Dave Barach1015a1e2017-05-08 19:15:03 -0400624
Florin Coras3cbc04b2017-10-02 00:18:51 -0700625 a->handle = session_handle (s);
Florin Coras844a36d2018-12-20 09:50:50 -0800626 a->app_index = hsm->app_index;
Dave Barach1015a1e2017-05-08 19:15:03 -0400627 vnet_disconnect_session (a);
628}
629
630static void
Florin Coras288eaab2019-02-03 15:26:14 -0800631http_server_session_reset_callback (session_t * s)
Dave Barach1015a1e2017-05-08 19:15:03 -0400632{
Florin Coras844a36d2018-12-20 09:50:50 -0800633 http_server_main_t *hsm = &http_server_main;
Florin Coras4af830c2018-12-04 09:21:36 -0800634 vnet_disconnect_args_t _a = { 0 }, *a = &_a;
Florin Coras844a36d2018-12-20 09:50:50 -0800635 http_session_t *hs;
636
637 if (!hsm->is_static)
638 http_server_sessions_writer_lock ();
639
640 hs = http_server_session_lookup (s->thread_index, s->session_index);
641 http_server_session_cleanup (hs);
642
643 if (!hsm->is_static)
644 http_server_sessions_writer_unlock ();
645
Florin Coras4af830c2018-12-04 09:21:36 -0800646 a->handle = session_handle (s);
Florin Coras844a36d2018-12-20 09:50:50 -0800647 a->app_index = hsm->app_index;
Florin Coras4af830c2018-12-04 09:21:36 -0800648 vnet_disconnect_session (a);
Dave Barach1015a1e2017-05-08 19:15:03 -0400649}
650
Dave Barach1015a1e2017-05-08 19:15:03 -0400651static int
Florin Coras4399c2e2018-01-25 06:34:42 -0800652http_server_session_connected_callback (u32 app_index, u32 api_context,
Florin Coras288eaab2019-02-03 15:26:14 -0800653 session_t * s, u8 is_fail)
Dave Barach1015a1e2017-05-08 19:15:03 -0400654{
655 clib_warning ("called...");
656 return -1;
657}
658
659static int
Florin Corasfa76a762018-11-29 12:40:10 -0800660http_server_add_segment_callback (u32 client_index, u64 segment_handle)
Dave Barach1015a1e2017-05-08 19:15:03 -0400661{
662 clib_warning ("called...");
663 return -1;
664}
665
Florin Coras4399c2e2018-01-25 06:34:42 -0800666static session_cb_vft_t http_server_session_cb_vft = {
667 .session_accept_callback = http_server_session_accept_callback,
668 .session_disconnect_callback = http_server_session_disconnect_callback,
669 .session_connected_callback = http_server_session_connected_callback,
670 .add_segment_callback = http_server_add_segment_callback,
Florin Coras371ca502018-02-21 12:07:41 -0800671 .builtin_app_rx_callback = http_server_rx_callback,
Florin Coras4399c2e2018-01-25 06:34:42 -0800672 .session_reset_callback = http_server_session_reset_callback
Dave Barach1015a1e2017-05-08 19:15:03 -0400673};
674
Dave Barach1015a1e2017-05-08 19:15:03 -0400675static int
Florin Coras844a36d2018-12-20 09:50:50 -0800676http_server_attach ()
Dave Barach1015a1e2017-05-08 19:15:03 -0400677{
Florin Coras371ca502018-02-21 12:07:41 -0800678 vnet_app_add_tls_cert_args_t _a_cert, *a_cert = &_a_cert;
679 vnet_app_add_tls_key_args_t _a_key, *a_key = &_a_key;
Dave Barach1015a1e2017-05-08 19:15:03 -0400680 http_server_main_t *hsm = &http_server_main;
Florin Corasff6e7692017-12-11 04:59:01 -0800681 u64 options[APP_OPTIONS_N_OPTIONS];
Dave Barach1015a1e2017-05-08 19:15:03 -0400682 vnet_app_attach_args_t _a, *a = &_a;
Florin Corasff6e7692017-12-11 04:59:01 -0800683 u32 segment_size = 128 << 20;
Dave Barach1015a1e2017-05-08 19:15:03 -0400684
Dave Barachb7b92992018-10-17 10:38:51 -0400685 clib_memset (a, 0, sizeof (*a));
686 clib_memset (options, 0, sizeof (options));
Dave Barach1015a1e2017-05-08 19:15:03 -0400687
Florin Corasff6e7692017-12-11 04:59:01 -0800688 if (hsm->private_segment_size)
689 segment_size = hsm->private_segment_size;
690
Florin Coras844a36d2018-12-20 09:50:50 -0800691 a->api_client_index = ~0;
692 a->name = format (0, "test_http_server");
Florin Coras4399c2e2018-01-25 06:34:42 -0800693 a->session_cb_vft = &http_server_session_cb_vft;
Dave Barach1015a1e2017-05-08 19:15:03 -0400694 a->options = options;
Florin Corasff6e7692017-12-11 04:59:01 -0800695 a->options[APP_OPTIONS_SEGMENT_SIZE] = segment_size;
696 a->options[APP_OPTIONS_RX_FIFO_SIZE] =
Florin Coras1d6d0852017-11-17 14:26:01 -0800697 hsm->fifo_size ? hsm->fifo_size : 8 << 10;
Florin Corasff6e7692017-12-11 04:59:01 -0800698 a->options[APP_OPTIONS_TX_FIFO_SIZE] =
Florin Coras1d6d0852017-11-17 14:26:01 -0800699 hsm->fifo_size ? hsm->fifo_size : 32 << 10;
Florin Coras7999e832017-10-31 01:51:04 -0700700 a->options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
Florin Coras1d6d0852017-11-17 14:26:01 -0800701 a->options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] = hsm->prealloc_fifos;
Dave Barach1015a1e2017-05-08 19:15:03 -0400702
703 if (vnet_application_attach (a))
704 {
Florin Coras844a36d2018-12-20 09:50:50 -0800705 vec_free (a->name);
Dave Barach1015a1e2017-05-08 19:15:03 -0400706 clib_warning ("failed to attach server");
707 return -1;
708 }
Florin Coras844a36d2018-12-20 09:50:50 -0800709 vec_free (a->name);
Dave Barach1015a1e2017-05-08 19:15:03 -0400710 hsm->app_index = a->app_index;
Florin Coras371ca502018-02-21 12:07:41 -0800711
Dave Barachb7b92992018-10-17 10:38:51 -0400712 clib_memset (a_cert, 0, sizeof (*a_cert));
Florin Coras371ca502018-02-21 12:07:41 -0800713 a_cert->app_index = a->app_index;
714 vec_validate (a_cert->cert, test_srv_crt_rsa_len);
Dave Barach178cf492018-11-13 16:34:13 -0500715 clib_memcpy_fast (a_cert->cert, test_srv_crt_rsa, test_srv_crt_rsa_len);
Florin Coras371ca502018-02-21 12:07:41 -0800716 vnet_app_add_tls_cert (a_cert);
717
Dave Barachb7b92992018-10-17 10:38:51 -0400718 clib_memset (a_key, 0, sizeof (*a_key));
Florin Coras371ca502018-02-21 12:07:41 -0800719 a_key->app_index = a->app_index;
720 vec_validate (a_key->key, test_srv_key_rsa_len);
Dave Barach178cf492018-11-13 16:34:13 -0500721 clib_memcpy_fast (a_key->key, test_srv_key_rsa, test_srv_key_rsa_len);
Florin Coras371ca502018-02-21 12:07:41 -0800722 vnet_app_add_tls_key (a_key);
723
Dave Barach1015a1e2017-05-08 19:15:03 -0400724 return 0;
725}
726
727static int
Florin Coras4399c2e2018-01-25 06:34:42 -0800728http_server_listen ()
Dave Barach1015a1e2017-05-08 19:15:03 -0400729{
730 http_server_main_t *hsm = &http_server_main;
Florin Corasc9940fc2019-02-05 20:55:11 -0800731 vnet_listen_args_t _a, *a = &_a;
Dave Barachb7b92992018-10-17 10:38:51 -0400732 clib_memset (a, 0, sizeof (*a));
Dave Barach1015a1e2017-05-08 19:15:03 -0400733 a->app_index = hsm->app_index;
734 a->uri = "tcp://0.0.0.0/80";
Florin Coras371ca502018-02-21 12:07:41 -0800735 if (hsm->uri)
736 a->uri = (char *) hsm->uri;
Dave Barach1015a1e2017-05-08 19:15:03 -0400737 return vnet_bind_uri (a);
738}
739
740static int
Florin Coras4399c2e2018-01-25 06:34:42 -0800741http_server_create (vlib_main_t * vm)
Dave Barach1015a1e2017-05-08 19:15:03 -0400742{
Florin Coras844a36d2018-12-20 09:50:50 -0800743 vlib_thread_main_t *vtm = vlib_get_thread_main ();
Dave Barach1015a1e2017-05-08 19:15:03 -0400744 http_server_main_t *hsm = &http_server_main;
745 u32 num_threads;
Dave Barach1015a1e2017-05-08 19:15:03 -0400746
747 num_threads = 1 /* main thread */ + vtm->n_threads;
Florin Coras844a36d2018-12-20 09:50:50 -0800748 vec_validate (hsm->vpp_queue, num_threads - 1);
749 vec_validate (hsm->sessions, num_threads - 1);
750 vec_validate (hsm->session_to_http_session, num_threads - 1);
Dave Barach1015a1e2017-05-08 19:15:03 -0400751
Florin Coras844a36d2018-12-20 09:50:50 -0800752 clib_rwlock_init (&hsm->sessions_lock);
753
754 if (http_server_attach ())
Dave Barach1015a1e2017-05-08 19:15:03 -0400755 {
756 clib_warning ("failed to attach server");
757 return -1;
758 }
Florin Coras4399c2e2018-01-25 06:34:42 -0800759 if (http_server_listen ())
Dave Barach1015a1e2017-05-08 19:15:03 -0400760 {
761 clib_warning ("failed to start listening");
762 return -1;
763 }
764 return 0;
765}
766
Dave Barach1015a1e2017-05-08 19:15:03 -0400767static clib_error_t *
Florin Coras4399c2e2018-01-25 06:34:42 -0800768http_server_create_command_fn (vlib_main_t * vm,
769 unformat_input_t * input,
770 vlib_cli_command_t * cmd)
Dave Barach1015a1e2017-05-08 19:15:03 -0400771{
Florin Coras0e9c33b2017-08-14 22:33:41 -0700772 http_server_main_t *hsm = &http_server_main;
Florin Coras1d6d0852017-11-17 14:26:01 -0800773 u64 seg_size;
Florin Coras149d62f2017-11-01 15:05:49 -0700774 u8 *html;
Florin Coras844a36d2018-12-20 09:50:50 -0800775 int rv;
Dave Barach1015a1e2017-05-08 19:15:03 -0400776
Florin Coras1d6d0852017-11-17 14:26:01 -0800777 hsm->prealloc_fifos = 0;
778 hsm->private_segment_size = 0;
779 hsm->fifo_size = 0;
Florin Coras844a36d2018-12-20 09:50:50 -0800780 hsm->is_static = 0;
Florin Coras149d62f2017-11-01 15:05:49 -0700781 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
782 {
783 if (unformat (input, "static"))
Florin Coras844a36d2018-12-20 09:50:50 -0800784 hsm->is_static = 1;
Florin Coras1d6d0852017-11-17 14:26:01 -0800785 else if (unformat (input, "prealloc-fifos %d", &hsm->prealloc_fifos))
786 ;
787 else if (unformat (input, "private-segment-size %U",
788 unformat_memory_size, &seg_size))
789 {
790 if (seg_size >= 0x100000000ULL)
791 {
792 vlib_cli_output (vm, "private segment size %llu, too large",
793 seg_size);
794 return 0;
795 }
796 hsm->private_segment_size = seg_size;
797 }
798 else if (unformat (input, "fifo-size %d", &hsm->fifo_size))
799 hsm->fifo_size <<= 10;
Florin Coras371ca502018-02-21 12:07:41 -0800800 else if (unformat (input, "uri %s", &hsm->uri))
801 ;
Florin Coras149d62f2017-11-01 15:05:49 -0700802 else
803 return clib_error_return (0, "unknown input `%U'",
804 format_unformat_error, input);
805 }
Florin Coras0e9c33b2017-08-14 22:33:41 -0700806 if (hsm->my_client_index != (u32) ~ 0)
807 return clib_error_return (0, "test http server is already running");
808
Dave Barach1015a1e2017-05-08 19:15:03 -0400809 vnet_session_enable_disable (vm, 1 /* turn on TCP, etc. */ );
Florin Coras149d62f2017-11-01 15:05:49 -0700810
Florin Coras844a36d2018-12-20 09:50:50 -0800811 if (hsm->is_static)
Florin Coras149d62f2017-11-01 15:05:49 -0700812 {
Florin Coras371ca502018-02-21 12:07:41 -0800813 http_server_session_cb_vft.builtin_app_rx_callback =
Florin Coras149d62f2017-11-01 15:05:49 -0700814 http_server_rx_callback_static;
815 html = format (0, html_header_static);
816 static_http = format (0, http_response, vec_len (html), html);
Florin Coras844a36d2018-12-20 09:50:50 -0800817 static_ok = format (0, http_ok);
Florin Coras149d62f2017-11-01 15:05:49 -0700818 }
Florin Coras4399c2e2018-01-25 06:34:42 -0800819 rv = http_server_create (vm);
Dave Barach1015a1e2017-05-08 19:15:03 -0400820 switch (rv)
821 {
822 case 0:
823 break;
824 default:
825 return clib_error_return (0, "server_create returned %d", rv);
826 }
827 return 0;
828}
829
830/* *INDENT-OFF* */
Florin Coras4399c2e2018-01-25 06:34:42 -0800831VLIB_CLI_COMMAND (http_server_create_command, static) =
Dave Barach1015a1e2017-05-08 19:15:03 -0400832{
833 .path = "test http server",
834 .short_help = "test http server",
Florin Coras4399c2e2018-01-25 06:34:42 -0800835 .function = http_server_create_command_fn,
Dave Barach1015a1e2017-05-08 19:15:03 -0400836};
837/* *INDENT-ON* */
838
839static clib_error_t *
Florin Coras4399c2e2018-01-25 06:34:42 -0800840http_server_main_init (vlib_main_t * vm)
Dave Barach1015a1e2017-05-08 19:15:03 -0400841{
842 http_server_main_t *hsm = &http_server_main;
Florin Coras149d62f2017-11-01 15:05:49 -0700843
Dave Barach1015a1e2017-05-08 19:15:03 -0400844 hsm->my_client_index = ~0;
845 hsm->vlib_main = vm;
Dave Barach1015a1e2017-05-08 19:15:03 -0400846 return 0;
847}
848
Florin Coras4399c2e2018-01-25 06:34:42 -0800849VLIB_INIT_FUNCTION (http_server_main_init);
Dave Barach1015a1e2017-05-08 19:15:03 -0400850
851/*
852* fd.io coding-style-patch-verification: ON
853*
854* Local Variables:
855* eval: (c-set-style "gnu")
856* End:
857*/