A shell for running JSON-RPC 2.0 queries
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

4134 lines
109 KiB

  1. /*
  2. * json-rpc-shell.c: a shell for JSON-RPC 2.0
  3. *
  4. * Copyright (c) 2014 - 2020, Přemysl Eric Janouch <p@janouch.name>
  5. *
  6. * Permission to use, copy, modify, and/or distribute this software for any
  7. * purpose with or without fee is hereby granted.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  12. * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  14. * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  15. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. *
  17. */
  18. /// Some arbitrary limit for the history file
  19. #define HISTORY_LIMIT 10000
  20. // A table of all attributes we use for output
  21. #define ATTR_TABLE(XX) \
  22. XX( PROMPT, "prompt", "Terminal attrs for the prompt" ) \
  23. XX( RESET, "reset", "String to reset terminal attributes" ) \
  24. XX( WARNING, "warning", "Terminal attrs for warnings" ) \
  25. XX( ERROR, "error", "Terminal attrs for errors" ) \
  26. XX( INCOMING, "incoming", "Terminal attrs for incoming traffic" ) \
  27. XX( OUTGOING, "outgoing", "Terminal attrs for outgoing traffic" ) \
  28. XX( JSON_FIELD, "json_field", "Terminal attrs for JSON field names" ) \
  29. XX( JSON_NULL, "json_null", "Terminal attrs for JSON null values" ) \
  30. XX( JSON_BOOL, "json_bool", "Terminal attrs for JSON booleans" ) \
  31. XX( JSON_NUMBER, "json_number", "Terminal attrs for JSON numbers" ) \
  32. XX( JSON_STRING, "json_string", "Terminal attrs for JSON strings" )
  33. enum
  34. {
  35. #define XX(x, y, z) ATTR_ ## x,
  36. ATTR_TABLE (XX)
  37. #undef XX
  38. ATTR_COUNT
  39. };
  40. // User data for logger functions to enable formatted logging
  41. #define print_fatal_data ((void *) ATTR_ERROR)
  42. #define print_error_data ((void *) ATTR_ERROR)
  43. #define print_warning_data ((void *) ATTR_WARNING)
  44. #define LIBERTY_WANT_SSL
  45. #define LIBERTY_WANT_PROTO_HTTP
  46. #define LIBERTY_WANT_PROTO_WS
  47. #include "config.h"
  48. #include "liberty/liberty.c"
  49. #include "http-parser/http_parser.h"
  50. #include <langinfo.h>
  51. #include <locale.h>
  52. #include <arpa/inet.h>
  53. #include <ev.h>
  54. #include <curl/curl.h>
  55. #include <jansson.h>
  56. #include <openssl/rand.h>
  57. #include <curses.h>
  58. #include <term.h>
  59. /// Shorthand to set an error and return failure from the function
  60. #define FAIL(...) return error_set (e, __VA_ARGS__)
  61. // --- Terminal ----------------------------------------------------------------
  62. static struct
  63. {
  64. bool initialized; ///< Terminal is available
  65. bool stdout_is_tty; ///< `stdout' is a terminal
  66. bool stderr_is_tty; ///< `stderr' is a terminal
  67. struct termios termios; ///< Terminal attributes
  68. char *color_set[8]; ///< Codes to set the foreground colour
  69. }
  70. g_terminal;
  71. static bool
  72. init_terminal (void)
  73. {
  74. int tty_fd = -1;
  75. if ((g_terminal.stderr_is_tty = isatty (STDERR_FILENO)))
  76. tty_fd = STDERR_FILENO;
  77. if ((g_terminal.stdout_is_tty = isatty (STDOUT_FILENO)))
  78. tty_fd = STDOUT_FILENO;
  79. int err;
  80. if (tty_fd == -1 || setupterm (NULL, tty_fd, &err) == ERR)
  81. return false;
  82. if (tcgetattr (tty_fd, &g_terminal.termios))
  83. return false;
  84. // Make sure all terminal features used by us are supported
  85. if (!set_a_foreground || !enter_bold_mode || !exit_attribute_mode)
  86. {
  87. del_curterm (cur_term);
  88. return false;
  89. }
  90. for (size_t i = 0; i < N_ELEMENTS (g_terminal.color_set); i++)
  91. g_terminal.color_set[i] = xstrdup (tparm (set_a_foreground,
  92. i, 0, 0, 0, 0, 0, 0, 0, 0));
  93. return g_terminal.initialized = true;
  94. }
  95. static void
  96. free_terminal (void)
  97. {
  98. if (!g_terminal.initialized)
  99. return;
  100. for (size_t i = 0; i < N_ELEMENTS (g_terminal.color_set); i++)
  101. free (g_terminal.color_set[i]);
  102. del_curterm (cur_term);
  103. }
  104. // --- User interface ----------------------------------------------------------
  105. // Not trying to do anything crazy here like switchable buffers.
  106. // Not trying to be too universal here either, it's not going to be reusable.
  107. struct input
  108. {
  109. struct input_vtable *vtable; ///< Virtual methods
  110. void *user_data; ///< User data for callbacks
  111. /// Process a single line input by the user
  112. void (*on_input) (char *line, void *user_data);
  113. /// User requested external line editing
  114. void (*on_run_editor) (const char *line, void *user_data);
  115. /// Tab completion generator, returns locale encoding strings or NULL
  116. char *(*complete_start_word) (const char *text, int state);
  117. };
  118. struct input_vtable
  119. {
  120. /// Start the interface under the given program name
  121. void (*start) (struct input *input, const char *program_name);
  122. /// Stop the interface
  123. void (*stop) (struct input *input);
  124. /// Prepare or unprepare terminal for our needs
  125. void (*prepare) (struct input *input, bool enabled);
  126. /// Destroy the object
  127. void (*destroy) (struct input *input);
  128. /// Hide the prompt if shown
  129. void (*hide) (struct input *input);
  130. /// Show the prompt if hidden
  131. void (*show) (struct input *input);
  132. /// Change the prompt string; takes ownership
  133. void (*set_prompt) (struct input *input, char *prompt);
  134. /// Change the current line input
  135. bool (*replace_line) (struct input *input, const char *line);
  136. /// Ring the terminal bell
  137. void (*ding) (struct input *input);
  138. /// Load history from file
  139. bool (*load_history) (struct input *input, const char *filename,
  140. struct error **e);
  141. /// Save history to file
  142. bool (*save_history) (struct input *input, const char *filename,
  143. struct error **e);
  144. /// Handle terminal resize
  145. void (*on_terminal_resized) (struct input *input);
  146. /// Handle terminal input
  147. void (*on_tty_readable) (struct input *input);
  148. };
  149. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  150. #ifdef HAVE_READLINE
  151. #include <readline/readline.h>
  152. #include <readline/history.h>
  153. #define INPUT_START_IGNORE RL_PROMPT_START_IGNORE
  154. #define INPUT_END_IGNORE RL_PROMPT_END_IGNORE
  155. struct input_rl
  156. {
  157. struct input super; ///< Parent class
  158. bool active; ///< Interface has been started
  159. char *prompt; ///< The prompt we use
  160. int prompt_shown; ///< Whether the prompt is shown now
  161. char *saved_line; ///< Saved line content
  162. int saved_point; ///< Saved cursor position
  163. int saved_mark; ///< Saved mark
  164. };
  165. /// Unfortunately Readline cannot pass us any pointer value in its callbacks
  166. /// that would eliminate the need to use global variables ourselves
  167. static struct input_rl *g_input_rl;
  168. static void
  169. input_rl_erase (void)
  170. {
  171. rl_set_prompt ("");
  172. rl_replace_line ("", false);
  173. rl_redisplay ();
  174. }
  175. static void
  176. input_rl_on_input (char *line)
  177. {
  178. struct input_rl *self = g_input_rl;
  179. // The prompt should always be visible at the moment we process input keys;
  180. // confirming it de facto hides it because we move onto a new line
  181. if (line)
  182. self->prompt_shown = 0;
  183. if (line && *line)
  184. add_history (line);
  185. self->super.on_input (line, self->super.user_data);
  186. free (line);
  187. // Readline automatically redisplays the prompt after we're done here;
  188. // we could have actually hidden it by now in preparation of a quit though
  189. if (line)
  190. self->prompt_shown++;
  191. }
  192. static int
  193. input_rl_on_run_editor (int count, int key)
  194. {
  195. (void) count;
  196. (void) key;
  197. struct input_rl *self = g_input_rl;
  198. if (self->super.on_run_editor)
  199. self->super.on_run_editor (rl_line_buffer, self->super.user_data);
  200. return 0;
  201. }
  202. static int
  203. input_rl_newline_insert (int count, int key)
  204. {
  205. (void) count;
  206. (void) key;
  207. rl_insert_text ("\n");
  208. return 0;
  209. }
  210. static int
  211. input_rl_on_startup (void)
  212. {
  213. rl_add_defun ("run-editor", input_rl_on_run_editor, -1);
  214. rl_bind_keyseq ("\\ee", rl_named_function ("run-editor"));
  215. rl_add_defun ("newline-insert", input_rl_newline_insert, -1);
  216. rl_bind_keyseq ("\\e\\r", rl_named_function ("newline-insert"));
  217. return 0;
  218. }
  219. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  220. static char **
  221. app_readline_completion (const char *text, int start, int end)
  222. {
  223. (void) end;
  224. // Only customize matches for the first token, which is the method name
  225. if (start)
  226. return NULL;
  227. // Don't iterate over filenames and stuff in this case
  228. rl_attempted_completion_over = true;
  229. return rl_completion_matches (text, g_input_rl->super.complete_start_word);
  230. }
  231. static void
  232. input_rl_start (struct input *input, const char *program_name)
  233. {
  234. struct input_rl *self = (struct input_rl *) input;
  235. using_history ();
  236. // This can cause memory leaks, or maybe even a segfault. Funny, eh?
  237. stifle_history (HISTORY_LIMIT);
  238. const char *slash = strrchr (program_name, '/');
  239. rl_readline_name = slash ? ++slash : program_name;
  240. rl_startup_hook = input_rl_on_startup;
  241. rl_catch_sigwinch = false;
  242. rl_change_environment = false;
  243. rl_attempted_completion_function = app_readline_completion;
  244. hard_assert (self->prompt != NULL);
  245. rl_callback_handler_install (self->prompt, input_rl_on_input);
  246. self->active = true;
  247. self->prompt_shown = 1;
  248. g_input_rl = self;
  249. }
  250. static void
  251. input_rl_stop (struct input *input)
  252. {
  253. struct input_rl *self = (struct input_rl *) input;
  254. if (self->prompt_shown > 0)
  255. input_rl_erase ();
  256. // This is okay so long as we're not called from within readline
  257. rl_callback_handler_remove ();
  258. self->active = false;
  259. self->prompt_shown = 0;
  260. g_input_rl = NULL;
  261. }
  262. static void
  263. input_rl_prepare (struct input *input, bool enabled)
  264. {
  265. (void) input;
  266. if (enabled)
  267. rl_prep_terminal (true);
  268. else
  269. rl_deprep_terminal ();
  270. }
  271. static void
  272. input_rl_destroy (struct input *input)
  273. {
  274. struct input_rl *self = (struct input_rl *) input;
  275. if (self->active)
  276. input_rl_stop (input);
  277. free (self->saved_line);
  278. free (self->prompt);
  279. free (self);
  280. }
  281. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  282. static void
  283. input_rl_hide (struct input *input)
  284. {
  285. struct input_rl *self = (struct input_rl *) input;
  286. if (!self->active || self->prompt_shown-- < 1)
  287. return;
  288. hard_assert (!self->saved_line);
  289. self->saved_point = rl_point;
  290. self->saved_mark = rl_mark;
  291. self->saved_line = rl_copy_text (0, rl_end);
  292. input_rl_erase ();
  293. }
  294. static void
  295. input_rl_show (struct input *input)
  296. {
  297. struct input_rl *self = (struct input_rl *) input;
  298. if (!self->active || ++self->prompt_shown < 1)
  299. return;
  300. hard_assert (self->saved_line);
  301. rl_set_prompt (self->prompt);
  302. rl_replace_line (self->saved_line, false);
  303. rl_point = self->saved_point;
  304. rl_mark = self->saved_mark;
  305. cstr_set (&self->saved_line, NULL);
  306. rl_redisplay ();
  307. }
  308. static void
  309. input_rl_set_prompt (struct input *input, char *prompt)
  310. {
  311. struct input_rl *self = (struct input_rl *) input;
  312. cstr_set (&self->prompt, prompt);
  313. if (!self->active || self->prompt_shown <= 0)
  314. return;
  315. // First reset the prompt to work around a bug in readline
  316. rl_set_prompt ("");
  317. rl_redisplay ();
  318. rl_set_prompt (self->prompt);
  319. rl_redisplay ();
  320. }
  321. static bool
  322. input_rl_replace_line (struct input *input, const char *line)
  323. {
  324. struct input_rl *self = (struct input_rl *) input;
  325. if (!self->active || self->prompt_shown < 1)
  326. return false;
  327. rl_point = rl_mark = 0;
  328. rl_replace_line (line, false);
  329. rl_point = strlen (line);
  330. rl_redisplay ();
  331. return true;
  332. }
  333. static void
  334. input_rl_ding (struct input *input)
  335. {
  336. (void) input;
  337. rl_ding ();
  338. }
  339. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  340. static bool
  341. input_rl_load_history (struct input *input, const char *filename,
  342. struct error **e)
  343. {
  344. (void) input;
  345. if (!(errno = read_history (filename)))
  346. return true;
  347. error_set (e, "%s", strerror (errno));
  348. return false;
  349. }
  350. static bool
  351. input_rl_save_history (struct input *input, const char *filename,
  352. struct error **e)
  353. {
  354. (void) input;
  355. if (!(errno = write_history (filename)))
  356. return true;
  357. error_set (e, "%s", strerror (errno));
  358. return false;
  359. }
  360. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  361. static void
  362. input_rl_on_terminal_resized (struct input *input)
  363. {
  364. // This fucks up big time on terminals with automatic wrapping such as
  365. // rxvt-unicode or newer VTE when the current line overflows, however we
  366. // can't do much about that
  367. (void) input;
  368. rl_resize_terminal ();
  369. }
  370. static void
  371. input_rl_on_tty_readable (struct input *input)
  372. {
  373. (void) input;
  374. rl_callback_read_char ();
  375. }
  376. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  377. static struct input_vtable input_rl_vtable =
  378. {
  379. .start = input_rl_start,
  380. .stop = input_rl_stop,
  381. .prepare = input_rl_prepare,
  382. .destroy = input_rl_destroy,
  383. .hide = input_rl_hide,
  384. .show = input_rl_show,
  385. .set_prompt = input_rl_set_prompt,
  386. .replace_line = input_rl_replace_line,
  387. .ding = input_rl_ding,
  388. .load_history = input_rl_load_history,
  389. .save_history = input_rl_save_history,
  390. .on_terminal_resized = input_rl_on_terminal_resized,
  391. .on_tty_readable = input_rl_on_tty_readable,
  392. };
  393. static struct input *
  394. input_rl_new (void)
  395. {
  396. struct input_rl *self = xcalloc (1, sizeof *self);
  397. self->super.vtable = &input_rl_vtable;
  398. return &self->super;
  399. }
  400. #define input_new input_rl_new
  401. #endif // HAVE_READLINE
  402. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  403. #ifdef HAVE_EDITLINE
  404. #include <histedit.h>
  405. #define INPUT_START_IGNORE '\x01'
  406. #define INPUT_END_IGNORE '\x01'
  407. struct input_el
  408. {
  409. struct input super; ///< Parent class
  410. EditLine *editline; ///< The EditLine object
  411. HistoryW *history; ///< The history object
  412. char *entered_line; ///< Buffers the entered line
  413. bool active; ///< Interface has been started
  414. char *prompt; ///< The prompt we use
  415. int prompt_shown; ///< Whether the prompt is shown now
  416. wchar_t *saved_line; ///< Saved line content
  417. int saved_point; ///< Saved cursor position
  418. int saved_len; ///< Saved line length
  419. };
  420. static char *
  421. input_el_wcstombs (const wchar_t *s)
  422. {
  423. size_t len = wcstombs (NULL, s, 0);
  424. if (len++ == (size_t) -1)
  425. return NULL;
  426. char *mb = xmalloc (len);
  427. mb[wcstombs (mb, s, len)] = 0;
  428. return mb;
  429. }
  430. static int
  431. input_el_get_termios (int character, int fallback)
  432. {
  433. if (!g_terminal.initialized)
  434. return fallback;
  435. cc_t value = g_terminal.termios.c_cc[character];
  436. if (value == _POSIX_VDISABLE)
  437. return fallback;
  438. return value;
  439. }
  440. static void
  441. input_el_redisplay (struct input_el *self)
  442. {
  443. char x[] = { input_el_get_termios (VREPRINT, 'R' - 0x40), 0 };
  444. el_push (self->editline, x);
  445. // We have to do this or it gets stuck and nothing is done
  446. int count = 0;
  447. (void) el_wgets (self->editline, &count);
  448. }
  449. static char *
  450. input_el_make_prompt (EditLine *editline)
  451. {
  452. struct input_el *self;
  453. el_get (editline, EL_CLIENTDATA, &self);
  454. return self->prompt ? self->prompt : "";
  455. }
  456. static char *
  457. input_el_make_empty_prompt (EditLine *editline)
  458. {
  459. (void) editline;
  460. return "";
  461. }
  462. static void
  463. input_el_erase (struct input_el *self)
  464. {
  465. const LineInfoW *info = el_wline (self->editline);
  466. int len = info->lastchar - info->buffer;
  467. int point = info->cursor - info->buffer;
  468. el_cursor (self->editline, len - point);
  469. el_wdeletestr (self->editline, len);
  470. el_set (self->editline, EL_PROMPT, input_el_make_empty_prompt);
  471. input_el_redisplay (self);
  472. }
  473. static unsigned char
  474. input_el_on_return (EditLine *editline, int key)
  475. {
  476. (void) key;
  477. struct input_el *self;
  478. el_get (editline, EL_CLIENTDATA, &self);
  479. const LineInfoW *info = el_wline (editline);
  480. int len = info->lastchar - info->buffer;
  481. int point = info->cursor - info->buffer;
  482. wchar_t *line = calloc (sizeof *info->buffer, len + 1);
  483. memcpy (line, info->buffer, sizeof *info->buffer * len);
  484. if (*line)
  485. {
  486. HistEventW ev;
  487. history_w (self->history, &ev, H_ENTER, line);
  488. }
  489. free (line);
  490. // Convert to a multibyte string and store it for later
  491. const LineInfo *info_mb = el_line (editline);
  492. self->entered_line = xstrndup
  493. (info_mb->buffer, info_mb->lastchar - info_mb->buffer);
  494. // Now we need to force editline to actually print the newline
  495. el_cursor (editline, len++ - point);
  496. el_insertstr (editline, "\n");
  497. input_el_redisplay (self);
  498. // Finally we need to discard the old line's contents
  499. el_wdeletestr (editline, len);
  500. return CC_NEWLINE;
  501. }
  502. static unsigned char
  503. input_el_on_run_editor (EditLine *editline, int key)
  504. {
  505. (void) key;
  506. struct input_el *self;
  507. el_get (editline, EL_CLIENTDATA, &self);
  508. const LineInfo *info = el_line (editline);
  509. char *line = xstrndup (info->buffer, info->lastchar - info->buffer);
  510. if (self->super.on_run_editor)
  511. self->super.on_run_editor (line, self->super.user_data);
  512. free (line);
  513. return CC_NORM;
  514. }
  515. static unsigned char
  516. input_el_on_newline_insert (EditLine *editline, int key)
  517. {
  518. (void) key;
  519. el_insertstr (editline, "\n");
  520. return CC_REFRESH;
  521. }
  522. static void
  523. input_el_install_prompt (struct input_el *self)
  524. {
  525. el_set (self->editline, EL_PROMPT_ESC,
  526. input_el_make_prompt, INPUT_START_IGNORE);
  527. }
  528. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  529. static unsigned char input_el_on_complete (EditLine *editline, int key);
  530. static void
  531. input_el_addbind (EditLine *editline, const char *name, const char *desc,
  532. unsigned char (*function) (EditLine *, int), const char *binding)
  533. {
  534. el_set (editline, EL_ADDFN, name, desc, function);
  535. el_set (editline, EL_BIND, binding, name, NULL);
  536. }
  537. static void
  538. input_el_start (struct input *input, const char *program_name)
  539. {
  540. struct input_el *self = (struct input_el *) input;
  541. self->editline = el_init (program_name, stdin, stdout, stderr);
  542. el_set (self->editline, EL_CLIENTDATA, self);
  543. input_el_install_prompt (self);
  544. el_set (self->editline, EL_SIGNAL, false);
  545. el_set (self->editline, EL_UNBUFFERED, isatty (fileno (stdin)));
  546. el_set (self->editline, EL_EDITOR, "emacs");
  547. el_wset (self->editline, EL_HIST, history_w, self->history);
  548. // No, editline, it's not supposed to kill the entire line
  549. el_set (self->editline, EL_BIND, "^w", "ed-delete-prev-word", NULL);
  550. // Just what are you doing?
  551. el_set (self->editline, EL_BIND, "^u", "vi-kill-line-prev", NULL);
  552. // It's probably better to handle these ourselves
  553. input_el_addbind (self->editline, "send-line", "Send line",
  554. input_el_on_return, "\n");
  555. input_el_addbind (self->editline, "run-editor", "Run editor to edit line",
  556. input_el_on_run_editor, "M-e");
  557. input_el_addbind (self->editline, "complete", "Complete word",
  558. input_el_on_complete, "\t");
  559. input_el_addbind (self->editline, "newline-insert", "Insert a newline",
  560. input_el_on_newline_insert, "M-\n");
  561. // Source the user's defaults file
  562. el_source (self->editline, NULL);
  563. self->active = true;
  564. self->prompt_shown = 1;
  565. }
  566. static void
  567. input_el_stop (struct input *input)
  568. {
  569. struct input_el *self = (struct input_el *) input;
  570. if (self->prompt_shown > 0)
  571. input_el_erase (self);
  572. el_end (self->editline);
  573. self->editline = NULL;
  574. self->active = false;
  575. self->prompt_shown = 0;
  576. }
  577. static void
  578. input_el_prepare (struct input *input, bool enabled)
  579. {
  580. struct input_el *self = (struct input_el *) input;
  581. el_set (self->editline, EL_PREP_TERM, enabled);
  582. }
  583. static void
  584. input_el_destroy (struct input *input)
  585. {
  586. struct input_el *self = (struct input_el *) input;
  587. if (self->active)
  588. input_el_stop (input);
  589. history_wend (self->history);
  590. free (self->saved_line);
  591. free (self->prompt);
  592. free (self);
  593. }
  594. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  595. static void
  596. input_el_hide (struct input *input)
  597. {
  598. struct input_el *self = (struct input_el *) input;
  599. if (!self->active || self->prompt_shown-- < 1)
  600. return;
  601. hard_assert (!self->saved_line);
  602. const LineInfoW *info = el_wline (self->editline);
  603. int len = info->lastchar - info->buffer;
  604. int point = info->cursor - info->buffer;
  605. wchar_t *line = calloc (sizeof *info->buffer, len + 1);
  606. memcpy (line, info->buffer, sizeof *info->buffer * len);
  607. el_cursor (self->editline, len - point);
  608. el_wdeletestr (self->editline, len);
  609. self->saved_line = line;
  610. self->saved_point = point;
  611. self->saved_len = len;
  612. input_el_erase (self);
  613. }
  614. static void
  615. input_el_show (struct input *input)
  616. {
  617. struct input_el *self = (struct input_el *) input;
  618. if (!self->active || ++self->prompt_shown < 1)
  619. return;
  620. hard_assert (self->saved_line);
  621. el_winsertstr (self->editline, self->saved_line);
  622. el_cursor (self->editline,
  623. -(self->saved_len - self->saved_point));
  624. free (self->saved_line);
  625. self->saved_line = NULL;
  626. input_el_install_prompt (self);
  627. input_el_redisplay (self);
  628. }
  629. static void
  630. input_el_set_prompt (struct input *input, char *prompt)
  631. {
  632. struct input_el *self = (struct input_el *) input;
  633. cstr_set (&self->prompt, prompt);
  634. if (self->prompt_shown > 0)
  635. input_el_redisplay (self);
  636. }
  637. static bool
  638. input_el_replace_line (struct input *input, const char *line)
  639. {
  640. struct input_el *self = (struct input_el *) input;
  641. if (!self->active || self->prompt_shown < 1)
  642. return false;
  643. const LineInfoW *info = el_wline (self->editline);
  644. int len = info->lastchar - info->buffer;
  645. int point = info->cursor - info->buffer;
  646. el_cursor (self->editline, len - point);
  647. el_wdeletestr (self->editline, len);
  648. bool success = !*line || !el_insertstr (self->editline, line);
  649. input_el_redisplay (self);
  650. return success;
  651. }
  652. static void
  653. input_el_ding (struct input *input)
  654. {
  655. (void) input;
  656. const char *ding = bell ? bell : "\a";
  657. write (STDOUT_FILENO, ding, strlen (ding));
  658. }
  659. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  660. static int
  661. input_el_collate (const void *a, const void *b)
  662. {
  663. return strcoll (*(const char **) a, *(const char **) b);
  664. }
  665. static struct strv
  666. input_el_collect_candidates (struct input_el *self, const char *word)
  667. {
  668. struct strv v = strv_make ();
  669. int i = 0; char *candidate = NULL;
  670. while ((candidate = self->super.complete_start_word (word, i++)))
  671. strv_append_owned (&v, candidate);
  672. qsort (v.vector, v.len, sizeof *v.vector, input_el_collate);
  673. return v;
  674. }
  675. static void
  676. input_el_print_candidates (struct input_el *self, const struct strv *v)
  677. {
  678. EditLine *editline = self->editline;
  679. // This insanity seems to be required to make it reprint the prompt
  680. const LineInfoW *info = el_wline (editline);
  681. int from_cursor_until_end = info->lastchar - info->cursor;
  682. el_cursor (editline, from_cursor_until_end);
  683. el_insertstr (editline, "\n");
  684. input_el_redisplay (self);
  685. el_wdeletestr (editline, 1);
  686. el_set (editline, EL_REFRESH);
  687. input_el_hide (&self->super);
  688. for (size_t i = 0; i < v->len; i++)
  689. printf ("%s\n", v->vector[i]);
  690. input_el_show (&self->super);
  691. el_cursor (editline, -from_cursor_until_end);
  692. }
  693. static void
  694. input_el_insert_common_prefix (EditLine *editline, const struct strv *v)
  695. {
  696. char *p[v->len]; memcpy (p, v->vector, sizeof p);
  697. mbstate_t state[v->len]; memset (state, 0, sizeof state);
  698. wchar_t want[2] = {}; size_t len;
  699. while ((len = mbrtowc (&want[0], p[0], strlen (p[0]), &state[0])) > 0)
  700. {
  701. p[0] += len;
  702. for (size_t i = 1; i < v->len; i++)
  703. {
  704. wchar_t found = 0;
  705. if ((len = mbrtowc (&found, p[i], strlen (p[i]), &state[i])) <= 0
  706. || found != want[0])
  707. return;
  708. p[i] += len;
  709. }
  710. el_winsertstr (editline, want);
  711. }
  712. }
  713. static unsigned char
  714. input_el_on_complete (EditLine *editline, int key)
  715. {
  716. (void) key;
  717. struct input_el *self;
  718. el_get (editline, EL_CLIENTDATA, &self);
  719. // First prepare what Readline would have normally done for us...
  720. const LineInfo *info_mb = el_line (editline);
  721. int len = info_mb->lastchar - info_mb->buffer;
  722. int point = info_mb->cursor - info_mb->buffer;
  723. char *word = xstrndup (info_mb->buffer, len);
  724. int start = point;
  725. while (start && !isspace_ascii (word[start - 1]))
  726. start--;
  727. // Only complete the first word, when we're at the end of it
  728. if (start != 0
  729. || (word[point] && !isspace_ascii (word[point]))
  730. || (point && isspace_ascii (word[point - 1])))
  731. {
  732. free (word);
  733. return CC_REFRESH_BEEP;
  734. }
  735. word[point] = '\0';
  736. int word_len = mbstowcs (NULL, word, 0);
  737. struct strv v = input_el_collect_candidates (self, word);
  738. free (word);
  739. if (!v.len)
  740. {
  741. strv_free (&v);
  742. return CC_REFRESH_BEEP;
  743. }
  744. // Remove the original word and replace it with the best (sub)match
  745. el_wdeletestr (editline, word_len);
  746. if (v.len == 1)
  747. {
  748. el_insertstr (editline, v.vector[0]);
  749. el_insertstr (editline, " ");
  750. strv_free (&v);
  751. return CC_REFRESH;
  752. }
  753. input_el_insert_common_prefix (editline, &v);
  754. input_el_print_candidates (self, &v);
  755. strv_free (&v);
  756. return CC_REFRESH_BEEP;
  757. }
  758. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  759. static bool
  760. input_el_load_history (struct input *input, const char *filename,
  761. struct error **e)
  762. {
  763. struct input_el *self = (struct input_el *) input;
  764. HistEventW ev;
  765. if (history_w (self->history, &ev, H_LOAD, filename) != -1)
  766. return true;
  767. char *error = input_el_wcstombs (ev.str);
  768. error_set (e, "%s", error);
  769. free (error);
  770. return false;
  771. }
  772. static bool
  773. input_el_save_history (struct input *input, const char *filename,
  774. struct error **e)
  775. {
  776. struct input_el *self = (struct input_el *) input;
  777. HistEventW ev;
  778. if (history_w (self->history, &ev, H_SAVE, filename) != -1)
  779. return true;
  780. char *error = input_el_wcstombs (ev.str);
  781. error_set (e, "%s", error);
  782. free (error);
  783. return false;
  784. }
  785. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  786. static void
  787. input_el_on_terminal_resized (struct input *input)
  788. {
  789. struct input_el *self = (struct input_el *) input;
  790. el_resize (self->editline);
  791. }
  792. static void
  793. input_el_on_tty_readable (struct input *input)
  794. {
  795. // We bind the return key to process it how we need to
  796. struct input_el *self = (struct input_el *) input;
  797. // el_gets() with EL_UNBUFFERED doesn't work with UTF-8,
  798. // we must use the wide-character interface
  799. int count = 0;
  800. const wchar_t *buf = el_wgets (self->editline, &count);
  801. // Editline works in a funny NO_TTY mode when the input is not a tty,
  802. // we cannot use EL_UNBUFFERED and expect sane results then
  803. int unbuffered = 0;
  804. if (!el_get (self->editline, EL_UNBUFFERED, &unbuffered) && !unbuffered)
  805. {
  806. char *entered_line = buf ? input_el_wcstombs (buf) : NULL;
  807. self->super.on_input (entered_line, self->super.user_data);
  808. free (entered_line);
  809. return;
  810. }
  811. // Process data from our newline handler (async-friendly handling)
  812. if (self->entered_line)
  813. {
  814. // We can't have anything try to hide the old prompt with the appended
  815. // newline, it needs to stay where it is and as it is
  816. self->prompt_shown = 0;
  817. self->super.on_input (self->entered_line, self->super.user_data);
  818. cstr_set (&self->entered_line, NULL);
  819. // Forbid editline from trying to erase the old prompt (or worse)
  820. // and let it redisplay the prompt in its clean state
  821. el_set (self->editline, EL_REFRESH);
  822. self->prompt_shown = 1;
  823. }
  824. if (count == 1 && buf[0] == ('D' - 0x40) /* hardcoded VEOF in editline */)
  825. {
  826. el_deletestr (self->editline, 1);
  827. input_el_redisplay (self);
  828. self->super.on_input (NULL, self->super.user_data);
  829. }
  830. }
  831. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  832. static struct input_vtable input_el_vtable =
  833. {
  834. .start = input_el_start,
  835. .stop = input_el_stop,
  836. .prepare = input_el_prepare,
  837. .destroy = input_el_destroy,
  838. .hide = input_el_hide,
  839. .show = input_el_show,
  840. .set_prompt = input_el_set_prompt,
  841. .replace_line = input_el_replace_line,
  842. .ding = input_el_ding,
  843. .load_history = input_el_load_history,
  844. .save_history = input_el_save_history,
  845. .on_terminal_resized = input_el_on_terminal_resized,
  846. .on_tty_readable = input_el_on_tty_readable,
  847. };
  848. static struct input *
  849. input_el_new (void)
  850. {
  851. struct input_el *self = xcalloc (1, sizeof *self);
  852. self->super.vtable = &input_el_vtable;
  853. HistEventW ev;
  854. self->history = history_winit ();
  855. history_w (self->history, &ev, H_SETSIZE, HISTORY_LIMIT);
  856. return &self->super;
  857. }
  858. #define input_new input_el_new
  859. #endif // HAVE_EDITLINE
  860. // --- Main program ------------------------------------------------------------
  861. enum color_mode
  862. {
  863. COLOR_AUTO, ///< Autodetect if colours are available
  864. COLOR_ALWAYS, ///< Always use coloured output
  865. COLOR_NEVER ///< Never use coloured output
  866. };
  867. static struct app_context
  868. {
  869. ev_child child_watcher; ///< SIGCHLD watcher
  870. ev_signal winch_watcher; ///< SIGWINCH watcher
  871. ev_signal term_watcher; ///< SIGTERM watcher
  872. ev_signal int_watcher; ///< SIGINT watcher
  873. ev_io tty_watcher; ///< Terminal watcher
  874. struct input *input; ///< Input interface
  875. char *attrs_defaults[ATTR_COUNT]; ///< Default terminal attributes
  876. char *attrs[ATTR_COUNT]; ///< Terminal attributes
  877. struct backend *backend; ///< Our current backend
  878. char *editor_filename; ///< File for input line editor
  879. struct str_map methods; ///< Methods detected via OpenRPC
  880. bool awaiting; ///< Running a separate loop to wait?
  881. struct error *await_error; ///< Error while waiting for event
  882. struct str *await_response; ///< Buffer for a response to a message
  883. struct config config; ///< Program configuration
  884. enum color_mode color_mode; ///< Colour output mode
  885. bool compact; ///< Whether to not pretty print
  886. bool verbose; ///< Print requests
  887. bool trust_all; ///< Don't verify peer certificates
  888. bool null_as_id; ///< JSON null is used as an ID
  889. int64_t next_id; ///< Next autogenerated ID
  890. iconv_t term_to_utf8; ///< Terminal encoding to UTF-8
  891. iconv_t term_from_utf8; ///< UTF-8 to terminal encoding
  892. }
  893. g_ctx;
  894. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  895. // HTTP/S and WS/S require significantly different handling. While for HTTP we
  896. // can just use the cURL easy interface, with WebSocket it gets a bit more
  897. // complicated and we implement it all by ourselves.
  898. //
  899. // Luckily on a higher level the application doesn't need to bother itself with
  900. // the details and the backend API can be very simple.
  901. struct backend
  902. {
  903. struct backend_vtable *vtable; ///< Virtual methods
  904. };
  905. struct backend_vtable
  906. {
  907. /// Add an HTTP header to send with requests
  908. void (*add_header) (struct backend *backend, const char *header);
  909. /// Make an RPC call
  910. bool (*make_call) (struct backend *backend,
  911. const char *request, bool expect_content,
  912. struct str *buf, struct error **e);
  913. /// See if the child belongs to the backend and process the signal
  914. bool (*on_child) (struct backend *backend, pid_t pid, int status);
  915. /// Free any resources
  916. void (*destroy) (struct backend *backend);
  917. };
  918. // --- Asynchronous results ----------------------------------------------------
  919. static bool
  920. await (struct app_context *ctx, struct str *buf, struct error **e)
  921. {
  922. hard_assert (!ctx->awaiting);
  923. // Run an event loop to retrieve the response
  924. ctx->await_response = buf;
  925. ctx->awaiting = true;
  926. ev_run (EV_DEFAULT_ 0);
  927. ctx->awaiting = false;
  928. ctx->await_response = NULL;
  929. if (ctx->await_error)
  930. {
  931. error_propagate (e, ctx->await_error);
  932. ctx->await_error = NULL;
  933. return false;
  934. }
  935. return true;
  936. }
  937. static int normalize_whitespace (int c) { return isspace_ascii (c) ? ' ' : c; }
  938. /// Caller guarantees that data[len] is a NUL byte (because of iconv_xstrdup())
  939. static void
  940. await_try_finish (struct app_context *ctx, const char *data, size_t len)
  941. {
  942. // There is no buffer while connecting and after we obtain our result
  943. if (data && !ctx->await_response)
  944. {
  945. char *s = iconv_xstrdup (ctx->term_from_utf8,
  946. (char *) data, len + 1 /* null byte */, NULL);
  947. // Does not affect JSON and ensures the message is printed out okay
  948. cstr_transform (s, normalize_whitespace);
  949. print_warning ("unexpected message received: %s", s);
  950. free (s);
  951. return;
  952. }
  953. if (data && ctx->await_response)
  954. {
  955. str_append_data (ctx->await_response, data, len);
  956. ctx->await_response = NULL;
  957. }
  958. // Here we need to be very careful to not return from too many levels
  959. if (ctx->awaiting)
  960. ev_break (EV_DEFAULT_ EVBREAK_ONE);
  961. }
  962. static void
  963. await_try_cancel (struct app_context *ctx)
  964. {
  965. if (!ctx->awaiting)
  966. return;
  967. ctx->await_response = NULL;
  968. if (!ctx->await_error)
  969. error_set (&ctx->await_error, "unexpected connection close");
  970. ev_break (EV_DEFAULT_ EVBREAK_ONE);
  971. }
  972. // --- Configuration -----------------------------------------------------------
  973. static void on_config_attribute_change (struct config_item *item);
  974. static struct config_schema g_config_connection[] =
  975. {
  976. { .name = "tls_ca_file",
  977. .comment = "OpenSSL CA bundle file",
  978. .type = CONFIG_ITEM_STRING },
  979. { .name = "tls_ca_path",
  980. .comment = "OpenSSL CA bundle path",
  981. .type = CONFIG_ITEM_STRING },
  982. {}
  983. };
  984. static struct config_schema g_config_attributes[] =
  985. {
  986. #define XX(x, y, z) { .name = y, .comment = z, .type = CONFIG_ITEM_STRING, \
  987. .on_change = on_config_attribute_change },
  988. ATTR_TABLE (XX)
  989. #undef XX
  990. {}
  991. };
  992. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  993. static void
  994. load_config_connection (struct config_item *subtree, void *user_data)
  995. {
  996. config_schema_apply_to_object (g_config_connection, subtree, user_data);
  997. }
  998. static void
  999. load_config_attributes (struct config_item *subtree, void *user_data)
  1000. {
  1001. config_schema_apply_to_object (g_config_attributes, subtree, user_data);
  1002. }
  1003. static void
  1004. register_config_modules (struct app_context *ctx)
  1005. {
  1006. struct config *config = &ctx->config;
  1007. config_register_module (config, "connection", load_config_connection, ctx);
  1008. config_register_module (config, "attributes", load_config_attributes, ctx);
  1009. }
  1010. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1011. static const char *
  1012. get_config_string (struct config_item *root, const char *key)
  1013. {
  1014. struct config_item *item = config_item_get (root, key, NULL);
  1015. hard_assert (item);
  1016. if (item->type == CONFIG_ITEM_NULL)
  1017. return NULL;
  1018. hard_assert (config_item_type_is_string (item->type));
  1019. return item->value.string.str;
  1020. }
  1021. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1022. static void
  1023. save_configuration (struct config_item *root, const char *path_hint)
  1024. {
  1025. struct str data = str_make ();
  1026. str_append (&data,
  1027. "# " PROGRAM_NAME " " PROGRAM_VERSION " configuration file\n"
  1028. "#\n"
  1029. "# Relative paths are searched for in ${XDG_CONFIG_HOME:-~/.config}\n"
  1030. "# /" PROGRAM_NAME " as well as in $XDG_CONFIG_DIRS/" PROGRAM_NAME "\n"
  1031. "#\n"
  1032. "# All text must be in UTF-8.\n"
  1033. "\n");
  1034. config_item_write (root, true, &data);
  1035. struct error *e = NULL;
  1036. char *filename = write_configuration_file (path_hint, &data, &e);
  1037. str_free (&data);
  1038. if (!filename)
  1039. {
  1040. print_error ("%s: %s", "saving configuration failed", e->message);
  1041. error_free (e);
  1042. }
  1043. else
  1044. print_status ("configuration written to `%s'", filename);
  1045. free (filename);
  1046. }
  1047. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1048. static void
  1049. load_configuration (struct app_context *ctx)
  1050. {
  1051. char *filename = resolve_filename
  1052. (PROGRAM_NAME ".conf", resolve_relative_config_filename);
  1053. if (!filename)
  1054. return;
  1055. struct error *e = NULL;
  1056. struct config_item *root = config_read_from_file (filename, &e);
  1057. free (filename);
  1058. if (e)
  1059. {
  1060. print_error ("error loading configuration: %s", e->message);
  1061. error_free (e);
  1062. exit (EXIT_FAILURE);
  1063. }
  1064. if (root)
  1065. {
  1066. config_load (&ctx->config, root);
  1067. config_schema_call_changed (ctx->config.root);
  1068. }
  1069. }
  1070. // --- Attributed output -------------------------------------------------------
  1071. typedef int (*terminal_printer_fn) (int);
  1072. static int
  1073. putchar_stderr (int c)
  1074. {
  1075. return fputc (c, stderr);
  1076. }
  1077. static terminal_printer_fn
  1078. get_attribute_printer (FILE *stream)
  1079. {
  1080. if (stream == stdout && g_terminal.stdout_is_tty)
  1081. return putchar;
  1082. if (stream == stderr && g_terminal.stderr_is_tty)
  1083. return putchar_stderr;
  1084. return NULL;
  1085. }
  1086. static void
  1087. vprint_attributed (struct app_context *ctx,
  1088. FILE *stream, intptr_t attribute, const char *fmt, va_list ap)
  1089. {
  1090. terminal_printer_fn printer = get_attribute_printer (stream);
  1091. if (!attribute)
  1092. printer = NULL;
  1093. if (printer)
  1094. tputs (ctx->attrs[attribute], 1, printer);
  1095. vfprintf (stream, fmt, ap);
  1096. if (printer)
  1097. tputs (ctx->attrs[ATTR_RESET], 1, printer);
  1098. }
  1099. static void
  1100. print_attributed (struct app_context *ctx,
  1101. FILE *stream, intptr_t attribute, const char *fmt, ...)
  1102. {
  1103. va_list ap;
  1104. va_start (ap, fmt);
  1105. vprint_attributed (ctx, stream, attribute, fmt, ap);
  1106. va_end (ap);
  1107. }
  1108. static void
  1109. log_message_attributed (void *user_data, const char *quote, const char *fmt,
  1110. va_list ap)
  1111. {
  1112. FILE *stream = stderr;
  1113. g_ctx.input->vtable->hide (g_ctx.input);
  1114. print_attributed (&g_ctx, stream, (intptr_t) user_data, "%s", quote);
  1115. vprint_attributed (&g_ctx, stream, (intptr_t) user_data, fmt, ap);
  1116. fputs ("\n", stream);
  1117. g_ctx.input->vtable->show (g_ctx.input);
  1118. }
  1119. static void
  1120. init_colors (struct app_context *ctx)
  1121. {
  1122. char **defaults = ctx->attrs_defaults;
  1123. #define INIT_ATTR(id, ti) defaults[ATTR_ ## id] = xstrdup ((ti))
  1124. // Use escape sequences from terminfo if possible, and SGR as a fallback
  1125. if (init_terminal ())
  1126. {
  1127. INIT_ATTR (PROMPT, enter_bold_mode);
  1128. INIT_ATTR (RESET, exit_attribute_mode);
  1129. INIT_ATTR (WARNING, g_terminal.color_set[COLOR_YELLOW]);
  1130. INIT_ATTR (ERROR, g_terminal.color_set[COLOR_RED]);
  1131. INIT_ATTR (INCOMING, "");
  1132. INIT_ATTR (OUTGOING, "");
  1133. INIT_ATTR (JSON_FIELD, enter_bold_mode);
  1134. INIT_ATTR (JSON_NULL, g_terminal.color_set[COLOR_CYAN]);
  1135. INIT_ATTR (JSON_BOOL, g_terminal.color_set[COLOR_RED]);
  1136. INIT_ATTR (JSON_NUMBER, g_terminal.color_set[COLOR_MAGENTA]);
  1137. INIT_ATTR (JSON_STRING, g_terminal.color_set[COLOR_BLUE]);
  1138. }
  1139. else
  1140. {
  1141. INIT_ATTR (PROMPT, "\x1b[1m");
  1142. INIT_ATTR (RESET, "\x1b[0m");
  1143. INIT_ATTR (WARNING, "\x1b[33m");
  1144. INIT_ATTR (ERROR, "\x1b[31m");
  1145. INIT_ATTR (INCOMING, "");
  1146. INIT_ATTR (OUTGOING, "");
  1147. INIT_ATTR (JSON_FIELD, "\x1b[1m");
  1148. INIT_ATTR (JSON_NULL, "\x1b[36m");
  1149. INIT_ATTR (JSON_BOOL, "\x1b[31m");
  1150. INIT_ATTR (JSON_NUMBER, "\x1b[35m");
  1151. INIT_ATTR (JSON_STRING, "\x1b[32m");
  1152. }
  1153. #undef INIT_ATTR
  1154. switch (ctx->color_mode)
  1155. {
  1156. case COLOR_ALWAYS:
  1157. g_terminal.stdout_is_tty = true;
  1158. g_terminal.stderr_is_tty = true;
  1159. break;
  1160. case COLOR_AUTO:
  1161. if (!g_terminal.initialized)
  1162. {
  1163. case COLOR_NEVER:
  1164. g_terminal.stdout_is_tty = false;
  1165. g_terminal.stderr_is_tty = false;
  1166. }
  1167. }
  1168. g_log_message_real = log_message_attributed;
  1169. // Apply the default values so that we start with any formatting at all
  1170. config_schema_call_changed
  1171. (config_item_get (ctx->config.root, "attributes", NULL));
  1172. }
  1173. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1174. static ssize_t
  1175. attr_by_name (const char *name)
  1176. {
  1177. static const char *table[ATTR_COUNT] =
  1178. {
  1179. #define XX(x, y, z) [ATTR_ ## x] = y,
  1180. ATTR_TABLE (XX)
  1181. #undef XX
  1182. };
  1183. for (size_t i = 0; i < N_ELEMENTS (table); i++)
  1184. if (!strcmp (name, table[i]))
  1185. return i;
  1186. return -1;
  1187. }
  1188. static void
  1189. on_config_attribute_change (struct config_item *item)
  1190. {
  1191. struct app_context *ctx = item->user_data;
  1192. ssize_t id = attr_by_name (item->schema->name);
  1193. if (id != -1)
  1194. {
  1195. cstr_set (&ctx->attrs[id], xstrdup (item->type == CONFIG_ITEM_NULL
  1196. ? ctx->attrs_defaults[id]
  1197. : item->value.string.str));
  1198. }
  1199. }
  1200. // --- http-parser wrapper -----------------------------------------------------
  1201. struct http_parserpp
  1202. {
  1203. http_parser parser; ///< HTTP parser
  1204. bool have_header_value; ///< Parsing header value or field?
  1205. struct str field; ///< Field part buffer
  1206. struct str value; ///< Value part buffer
  1207. struct str_map headers; ///< HTTP headers
  1208. struct str message; ///< Message data
  1209. };
  1210. static void
  1211. http_parserpp_init (struct http_parserpp *self, enum http_parser_type type)
  1212. {
  1213. http_parser_init (&self->parser, type);
  1214. self->parser.data = self;
  1215. self->field = str_make ();
  1216. self->value = str_make ();
  1217. self->headers = str_map_make (free);
  1218. self->headers.key_xfrm = tolower_ascii_strxfrm;
  1219. self->message = str_make ();
  1220. }
  1221. static void
  1222. http_parserpp_free (struct http_parserpp *self)
  1223. {
  1224. str_free (&self->field);
  1225. str_free (&self->value);
  1226. str_map_free (&self->headers);
  1227. str_free (&self->message);
  1228. }
  1229. static bool
  1230. http_parserpp_header_field_is_a_list (const char *name)
  1231. {
  1232. // This must contain all header fields we use for anything
  1233. static const char *concatenable[] =
  1234. { SEC_WS_PROTOCOL, SEC_WS_EXTENSIONS, "Upgrade" };
  1235. for (size_t i = 0; i < N_ELEMENTS (concatenable); i++)
  1236. if (!strcasecmp_ascii (name, concatenable[i]))
  1237. return true;
  1238. return false;
  1239. }
  1240. static void
  1241. http_parserpp_on_header_read (struct http_parserpp *self)
  1242. {
  1243. // The HTTP parser unfolds values and removes preceding whitespace, but
  1244. // otherwise doesn't touch the values or the following whitespace.
  1245. // RFC 7230 states that trailing whitespace is not part of a field value
  1246. char *value = self->field.str;
  1247. size_t len = self->field.len;
  1248. while (len--)
  1249. if (value[len] == '\t' || value[len] == ' ')
  1250. value[len] = '\0';
  1251. else
  1252. break;
  1253. self->field.len = len;
  1254. const char *field = self->field.str;
  1255. const char *current = str_map_find (&self->headers, field);
  1256. if (http_parserpp_header_field_is_a_list (field) && current)
  1257. str_map_set (&self->headers, field,
  1258. xstrdup_printf ("%s, %s", current, self->value.str));
  1259. else
  1260. // If the field cannot be concatenated, just overwrite the last value.
  1261. // Maybe we should issue a warning or something.
  1262. str_map_set (&self->headers, field, xstrdup (self->value.str));
  1263. }
  1264. static int
  1265. http_parserpp_on_header_field (http_parser *parser, const char *at, size_t len)
  1266. {
  1267. struct http_parserpp *self = parser->data;
  1268. if (self->have_header_value)
  1269. {
  1270. http_parserpp_on_header_read (self);
  1271. str_reset (&self->field);
  1272. str_reset (&self->value);
  1273. }
  1274. str_append_data (&self->field, at, len);
  1275. self->have_header_value = false;
  1276. return 0;
  1277. }
  1278. static int
  1279. http_parserpp_on_header_value (http_parser *parser, const char *at, size_t len)
  1280. {
  1281. struct http_parserpp *self = parser->data;
  1282. str_append_data (&self->value, at, len);
  1283. self->have_header_value = true;
  1284. return 0;
  1285. }
  1286. static int
  1287. http_parserpp_on_headers_complete (http_parser *parser)
  1288. {
  1289. struct http_parserpp *self = parser->data;
  1290. if (self->have_header_value)
  1291. http_parserpp_on_header_read (self);
  1292. return 0;
  1293. }
  1294. static int
  1295. http_parserpp_on_message_begin (http_parser *parser)
  1296. {
  1297. struct http_parserpp *self = parser->data;
  1298. str_reset (&self->message);
  1299. return 0;
  1300. }
  1301. static int
  1302. http_parserpp_on_body (http_parser *parser, const char *at, size_t len)
  1303. {
  1304. struct http_parserpp *self = parser->data;
  1305. str_append_data (&self->message, at, len);
  1306. return 0;
  1307. }
  1308. // --- WebSocket backend -------------------------------------------------------
  1309. enum ws_handler_state
  1310. {
  1311. WS_HANDLER_CONNECTING, ///< Parsing HTTP
  1312. WS_HANDLER_OPEN, ///< Parsing WebSocket frames
  1313. WS_HANDLER_CLOSING, ///< Closing the connection
  1314. WS_HANDLER_CLOSED ///< Dead
  1315. };
  1316. #define BACKEND_WS_MAX_PAYLOAD_LEN UINT32_MAX
  1317. struct ws_context
  1318. {
  1319. struct backend super; ///< Parent class
  1320. struct app_context *ctx; ///< Application context
  1321. // Configuration:
  1322. char *endpoint; ///< Endpoint URL
  1323. struct http_parser_url url; ///< Parsed URL
  1324. struct strv extra_headers; ///< Extra headers for the handshake
  1325. // Events:
  1326. ev_timer timeout_watcher; ///< Connection timeout watcher
  1327. // The TCP transport:
  1328. int server_fd; ///< Socket FD of the server
  1329. ev_io read_watcher; ///< Server FD read watcher
  1330. SSL_CTX *ssl_ctx; ///< SSL context
  1331. SSL *ssl; ///< SSL connection
  1332. // WebSocket protocol handling:
  1333. enum ws_handler_state state; ///< State
  1334. char *key; ///< Key for the current handshake
  1335. struct http_parserpp http; ///< HTTP parser
  1336. struct ws_parser parser; ///< Protocol frame parser
  1337. bool expecting_continuation; ///< For non-control traffic
  1338. enum ws_opcode message_opcode; ///< Opcode for the current message
  1339. struct str message_data; ///< Concatenated message data
  1340. };
  1341. static void
  1342. backend_ws_add_header (struct backend *backend, const char *header)
  1343. {
  1344. struct ws_context *self = (struct ws_context *) backend;
  1345. strv_append (&self->extra_headers, header);
  1346. }
  1347. enum ws_read_result
  1348. {
  1349. WS_READ_OK, ///< Some data were read successfully
  1350. WS_READ_EOF, ///< The server has closed connection
  1351. WS_READ_AGAIN, ///< No more data at the moment
  1352. WS_READ_ERROR ///< General connection failure
  1353. };
  1354. static enum ws_read_result
  1355. backend_ws_fill_read_buffer_tls
  1356. (struct ws_context *self, void *buf, size_t *len)
  1357. {
  1358. int n_read;
  1359. start:
  1360. n_read = SSL_read (self->ssl, buf, *len);
  1361. const char *error_info = NULL;
  1362. switch (xssl_get_error (self->ssl, n_read, &error_info))
  1363. {
  1364. case SSL_ERROR_NONE:
  1365. *len = n_read;
  1366. return WS_READ_OK;
  1367. case SSL_ERROR_ZERO_RETURN:
  1368. return WS_READ_EOF;
  1369. case SSL_ERROR_WANT_READ:
  1370. return WS_READ_AGAIN;
  1371. case SSL_ERROR_WANT_WRITE:
  1372. {
  1373. // Let it finish the handshake as we don't poll for writability;
  1374. // any errors are to be collected by SSL_read() in the next iteration
  1375. struct pollfd pfd = { .fd = self->server_fd, .events = POLLOUT };
  1376. soft_assert (poll (&pfd, 1, 0) > 0);
  1377. goto start;
  1378. }
  1379. case XSSL_ERROR_TRY_AGAIN:
  1380. goto start;
  1381. default:
  1382. print_debug ("%s: %s: %s", __func__, "SSL_read", error_info);
  1383. return WS_READ_ERROR;
  1384. }
  1385. }
  1386. static enum ws_read_result
  1387. backend_ws_fill_read_buffer (struct ws_context *self, void *buf, size_t *len)
  1388. {
  1389. ssize_t n_read;
  1390. start:
  1391. n_read = recv (self->server_fd, buf, *len, 0);
  1392. if (n_read > 0)
  1393. {
  1394. *len = n_read;
  1395. return WS_READ_OK;
  1396. }
  1397. if (n_read == 0)
  1398. return WS_READ_EOF;
  1399. if (errno == EAGAIN)
  1400. return WS_READ_AGAIN;
  1401. if (errno == EINTR)
  1402. goto start;
  1403. print_debug ("%s: %s: %s", __func__, "recv", strerror (errno));
  1404. return WS_READ_ERROR;
  1405. }
  1406. static bool
  1407. backend_ws_finish_handshake (struct ws_context *self, struct error **e)
  1408. {
  1409. if (self->http.parser.http_major != 1 || self->http.parser.http_minor < 1)
  1410. FAIL ("incompatible HTTP version: %d.%d",
  1411. self->http.parser.http_major, self->http.parser.http_minor);
  1412. const char *upgrade = str_map_find (&self->http.headers, "Upgrade");
  1413. if (!upgrade || strcasecmp_ascii (upgrade, "websocket"))
  1414. FAIL ("cannot upgrade connection to WebSocket");
  1415. const char *accept = str_map_find (&self->http.headers, SEC_WS_ACCEPT);
  1416. char *accept_expected = ws_encode_response_key (self->key);
  1417. bool accept_ok = accept && !strcmp (accept, accept_expected);
  1418. free (accept_expected);
  1419. if (!accept_ok)
  1420. FAIL ("missing or invalid " SEC_WS_ACCEPT " header");
  1421. if (str_map_find (&self->http.headers, SEC_WS_EXTENSIONS)
  1422. || str_map_find (&self->http.headers, SEC_WS_PROTOCOL))
  1423. // TODO: actually parse these fields
  1424. FAIL ("unexpected WebSocket extension or protocol");
  1425. return true;
  1426. }
  1427. static int
  1428. backend_ws_on_headers_complete (http_parser *parser)
  1429. {
  1430. // We require a protocol upgrade. 1 is for "skip body", 2 is the same
  1431. // + "stop processing", return another number to indicate a problem here.
  1432. http_parserpp_on_headers_complete (parser);
  1433. if (!parser->upgrade)
  1434. return 3;
  1435. return 0;
  1436. }
  1437. static bool
  1438. backend_ws_on_data (struct ws_context *self, const void *data, size_t len)
  1439. {
  1440. if (self->state != WS_HANDLER_CONNECTING)
  1441. return ws_parser_push (&self->parser, data, len);
  1442. // The handshake hasn't been done yet, process HTTP headers
  1443. static const http_parser_settings http_settings =
  1444. {
  1445. .on_header_field = http_parserpp_on_header_field,
  1446. .on_header_value = http_parserpp_on_header_value,
  1447. .on_headers_complete = backend_ws_on_headers_complete,
  1448. };
  1449. size_t n_parsed = http_parser_execute (&self->http.parser,
  1450. &http_settings, data, len);
  1451. if (self->http.parser.upgrade)
  1452. {
  1453. struct error *e = NULL;
  1454. if (!backend_ws_finish_handshake (self, &e))
  1455. {
  1456. print_error ("WS handshake failed: %s", e->message);
  1457. error_free (e);
  1458. return false;
  1459. }
  1460. // Finished the handshake, try to return to caller
  1461. // (we run a separate loop to wait for the handshake to finish).
  1462. self->state = WS_HANDLER_OPEN;
  1463. await_try_finish (self->ctx, NULL, 0);
  1464. if ((len -= n_parsed))
  1465. return ws_parser_push (&self->parser,
  1466. (const uint8_t *) data + n_parsed, len);
  1467. return true;
  1468. }
  1469. enum http_errno err = HTTP_PARSER_ERRNO (&self->http.parser);
  1470. if (n_parsed != len || err != HPE_OK)
  1471. {
  1472. if (err == HPE_CB_headers_complete)
  1473. print_error ("WS handshake failed: %s (status code %d)",
  1474. "connection cannot be upgraded", self->http.parser.status_code);
  1475. else
  1476. print_error ("WS handshake failed: %s",
  1477. http_errno_description (err));
  1478. return false;
  1479. }
  1480. return true;
  1481. }
  1482. static void
  1483. backend_ws_close_connection (struct ws_context *self)
  1484. {
  1485. if (self->server_fd == -1)
  1486. return;
  1487. ev_io_stop (EV_DEFAULT_ &self->read_watcher);
  1488. if (self->ssl)
  1489. {
  1490. (void) SSL_shutdown (self->ssl);
  1491. SSL_free (self->ssl);
  1492. self->ssl = NULL;
  1493. }
  1494. xclose (self->server_fd);
  1495. self->server_fd = -1;
  1496. self->state = WS_HANDLER_CLOSED;
  1497. // That would have no way of succeeding
  1498. // XXX: what if we're waiting for the close?
  1499. await_try_cancel (self->ctx);
  1500. }
  1501. static void
  1502. backend_ws_on_fd_ready (EV_P_ ev_io *handle, int revents)
  1503. {
  1504. (void) loop;
  1505. (void) revents;
  1506. struct ws_context *self = handle->data;
  1507. uint8_t buf[BUFSIZ];
  1508. size_t n_read;
  1509. restart:
  1510. n_read = sizeof buf;
  1511. // Try to read some data in a non-blocking manner
  1512. (void) set_blocking (self->server_fd, false);
  1513. enum ws_read_result result = self->ssl
  1514. ? backend_ws_fill_read_buffer_tls (self, buf, &n_read)
  1515. : backend_ws_fill_read_buffer (self, buf, &n_read);
  1516. (void) set_blocking (self->server_fd, true);
  1517. switch (result)
  1518. {
  1519. case WS_READ_AGAIN:
  1520. return;
  1521. case WS_READ_ERROR:
  1522. print_error ("reading from the server failed");
  1523. break;
  1524. case WS_READ_EOF:
  1525. print_status ("the server closed the connection");
  1526. break;
  1527. case WS_READ_OK:
  1528. if (backend_ws_on_data (self, buf, n_read))
  1529. goto restart;
  1530. // XXX: maybe we should wait until we receive an EOF
  1531. }
  1532. backend_ws_close_connection (self);
  1533. }
  1534. static bool
  1535. backend_ws_write (struct ws_context *self, const void *data, size_t len)
  1536. {
  1537. if (!soft_assert (self->server_fd != -1))
  1538. return false;
  1539. if (self->ssl)
  1540. {
  1541. // TODO: call SSL_get_error() to detect if a clean shutdown has occured
  1542. if (SSL_write (self->ssl, data, len) != (int) len)
  1543. {
  1544. print_debug ("%s: %s: %s", __func__, "SSL_write",
  1545. ERR_error_string (ERR_get_error (), NULL));
  1546. return false;
  1547. }
  1548. }
  1549. else if (write (self->server_fd, data, len) != (ssize_t) len)
  1550. {
  1551. print_debug ("%s: %s: %s", __func__, "write", strerror (errno));
  1552. return false;
  1553. }
  1554. return true;
  1555. }
  1556. static bool
  1557. backend_ws_establish_connection (struct ws_context *self,
  1558. const char *host, const char *port, struct error **e)
  1559. {
  1560. struct addrinfo gai_hints, *gai_result, *gai_iter;
  1561. memset (&gai_hints, 0, sizeof gai_hints);
  1562. gai_hints.ai_socktype = SOCK_STREAM;
  1563. int err = getaddrinfo (host, port, &gai_hints, &gai_result);
  1564. if (err)
  1565. FAIL ("%s: %s: %s",
  1566. "connection failed", "getaddrinfo", gai_strerror (err));
  1567. int sockfd;
  1568. for (gai_iter = gai_result; gai_iter; gai_iter = gai_iter->ai_next)
  1569. {
  1570. sockfd = socket (gai_iter->ai_family,
  1571. gai_iter->ai_socktype, gai_iter->ai_protocol);
  1572. if (sockfd == -1)
  1573. continue;
  1574. set_cloexec (sockfd);
  1575. int yes = 1;
  1576. soft_assert (setsockopt (sockfd, SOL_SOCKET, SO_KEEPALIVE,
  1577. &yes, sizeof yes) != -1);
  1578. const char *real_host = host;
  1579. // Let's try to resolve the address back into a real hostname;
  1580. // we don't really need this, so we can let it quietly fail
  1581. char buf[NI_MAXHOST];
  1582. err = getnameinfo (gai_iter->ai_addr, gai_iter->ai_addrlen,
  1583. buf, sizeof buf, NULL, 0, NI_NUMERICHOST);
  1584. if (err)
  1585. print_debug ("%s: %s", "getnameinfo", gai_strerror (err));
  1586. else
  1587. real_host = buf;
  1588. if (g_debug_mode)
  1589. {
  1590. char *address = format_host_port_pair (real_host, port);
  1591. print_status ("connecting to %s...", address);
  1592. free (address);
  1593. }
  1594. if (!connect (sockfd, gai_iter->ai_addr, gai_iter->ai_addrlen))
  1595. break;
  1596. xclose (sockfd);
  1597. }
  1598. freeaddrinfo (gai_result);
  1599. if (!gai_iter)
  1600. FAIL ("connection failed");
  1601. self->server_fd = sockfd;
  1602. return true;
  1603. }
  1604. static bool
  1605. backend_ws_set_up_ssl_ctx (struct ws_context *self)
  1606. {
  1607. if (self->ctx->trust_all)
  1608. {
  1609. SSL_CTX_set_verify (self->ssl_ctx, SSL_VERIFY_NONE, NULL);
  1610. return true;
  1611. }
  1612. // TODO: try to resolve filenames relative to configuration directories
  1613. const char *ca_file = get_config_string
  1614. (self->ctx->config.root, "connection.tls_ca_file");
  1615. const char *ca_path = get_config_string
  1616. (self->ctx->config.root, "connection.tls_ca_path");
  1617. if (ca_file || ca_path)
  1618. {
  1619. if (SSL_CTX_load_verify_locations (self->ssl_ctx, ca_file, ca_path))
  1620. return true;
  1621. print_warning ("%s: %s",
  1622. "failed to set locations for trusted CA certificates",
  1623. ERR_reason_error_string (ERR_get_error ()));
  1624. }
  1625. return SSL_CTX_set_default_verify_paths (self->ssl_ctx);
  1626. }
  1627. static bool
  1628. backend_ws_initialize_tls (struct ws_context *self,
  1629. const char *server_name, struct error **e)
  1630. {
  1631. const char *error_info = NULL;
  1632. if (!self->ssl_ctx)
  1633. {
  1634. if (!(self->ssl_ctx = SSL_CTX_new (SSLv23_client_method ())))
  1635. goto error_ssl_1;
  1636. if (!backend_ws_set_up_ssl_ctx (self))
  1637. goto error_ssl_2;
  1638. }
  1639. self->ssl = SSL_new (self->ssl_ctx);
  1640. if (!self->ssl)
  1641. goto error_ssl_2;
  1642. SSL_set_connect_state (self->ssl);
  1643. if (!SSL_set_fd (self->ssl, self->server_fd))
  1644. goto error_ssl_3;
  1645. // Avoid SSL_write() returning SSL_ERROR_WANT_READ
  1646. SSL_set_mode (self->ssl, SSL_MODE_AUTO_RETRY);
  1647. // Literal IP addresses aren't allowed in the SNI
  1648. struct in6_addr dummy;
  1649. if (!inet_pton (AF_INET, server_name, &dummy)
  1650. && !inet_pton (AF_INET6, server_name, &dummy))
  1651. SSL_set_tlsext_host_name (self->ssl, server_name);
  1652. switch (xssl_get_error (self->ssl, SSL_connect (self->ssl), &error_info))
  1653. {
  1654. case SSL_ERROR_NONE:
  1655. return true;
  1656. case SSL_ERROR_ZERO_RETURN:
  1657. error_info = "server closed the connection";
  1658. default:
  1659. break;
  1660. }
  1661. error_ssl_3:
  1662. SSL_free (self->ssl);
  1663. self->ssl = NULL;
  1664. error_ssl_2:
  1665. SSL_CTX_free (self->ssl_ctx);
  1666. self->ssl_ctx = NULL;
  1667. error_ssl_1:
  1668. // XXX: these error strings are really nasty; also there could be
  1669. // multiple errors on the OpenSSL stack.
  1670. if (!error_info)
  1671. error_info = ERR_error_string (ERR_get_error (), NULL);
  1672. FAIL ("%s: %s", "could not initialize SSL", error_info);
  1673. }
  1674. static bool
  1675. backend_ws_send_message (struct ws_context *self,
  1676. enum ws_opcode opcode, const void *data, size_t len)
  1677. {
  1678. struct str header = str_make ();
  1679. str_pack_u8 (&header, 0x80 | (opcode & 0x0F));
  1680. if (len > UINT16_MAX)
  1681. {
  1682. str_pack_u8 (&header, 0x80 | 127);
  1683. str_pack_u64 (&header, len);
  1684. }
  1685. else if (len > 125)
  1686. {
  1687. str_pack_u8 (&header, 0x80 | 126);
  1688. str_pack_u16 (&header, len);
  1689. }
  1690. else
  1691. str_pack_u8 (&header, 0x80 | len);
  1692. uint32_t mask;
  1693. if (!RAND_bytes ((unsigned char *) &mask, sizeof mask))
  1694. return false;
  1695. str_pack_u32 (&header, mask);
  1696. bool result = backend_ws_write (self, header.str, header.len);
  1697. str_free (&header);
  1698. while (result && len)
  1699. {
  1700. size_t block_size = MIN (len, 1 << 16);
  1701. char masked[block_size];
  1702. memcpy (masked, data, block_size);
  1703. ws_parser_unmask (masked, block_size, mask);
  1704. result = backend_ws_write (self, masked, block_size);
  1705. len -= block_size;
  1706. data = (const uint8_t *) data + block_size;
  1707. }
  1708. return result;
  1709. }
  1710. static bool
  1711. backend_ws_send_control (struct ws_context *self,
  1712. enum ws_opcode opcode, const void *data, size_t len)
  1713. {
  1714. if (len > WS_MAX_CONTROL_PAYLOAD_LEN)
  1715. {
  1716. print_debug ("truncating output control frame payload"
  1717. " from %zu to %zu bytes", len, (size_t) WS_MAX_CONTROL_PAYLOAD_LEN);
  1718. len = WS_MAX_CONTROL_PAYLOAD_LEN;
  1719. }
  1720. return backend_ws_send_message (self, opcode, data, len);
  1721. }
  1722. static bool
  1723. backend_ws_fail (struct ws_context *self, enum ws_status reason)
  1724. {
  1725. uint8_t payload[2] = { reason >> 8, reason };
  1726. (void) backend_ws_send_control (self, WS_OPCODE_CLOSE,
  1727. payload, sizeof payload);
  1728. // The caller should immediately proceed to close the TCP connection,
  1729. // e.g. by returning false from a handler
  1730. self->state = WS_HANDLER_CLOSING;
  1731. return false;
  1732. }
  1733. static bool
  1734. backend_ws_on_frame_header (void *user_data, const struct ws_parser *parser)
  1735. {
  1736. struct ws_context *self = user_data;
  1737. // Note that we aren't expected to send any close frame before closing the
  1738. // connection when the frame is unmasked
  1739. if (parser->reserved_1 || parser->reserved_2 || parser->reserved_3
  1740. || parser->is_masked // server -> client payload must not be masked
  1741. || (ws_is_control_frame (parser->opcode) &&
  1742. (!parser->is_fin || parser->payload_len > WS_MAX_CONTROL_PAYLOAD_LEN))
  1743. || (!ws_is_control_frame (parser->opcode) &&
  1744. (self->expecting_continuation && parser->opcode != WS_OPCODE_CONT))
  1745. || parser->payload_len >= 0x8000000000000000ULL)
  1746. return backend_ws_fail (self, WS_STATUS_PROTOCOL_ERROR);
  1747. else if (parser->payload_len > BACKEND_WS_MAX_PAYLOAD_LEN)
  1748. return backend_ws_fail (self, WS_STATUS_MESSAGE_TOO_BIG);
  1749. return true;
  1750. }
  1751. static bool
  1752. backend_ws_finish_closing_handshake
  1753. (struct ws_context *self, const struct ws_parser *parser)
  1754. {
  1755. struct str reason = str_make ();
  1756. if (parser->payload_len >= 2)
  1757. {
  1758. struct msg_unpacker unpacker =
  1759. msg_unpacker_make (parser->input.str, parser->payload_len);
  1760. uint16_t status_code;
  1761. msg_unpacker_u16 (&unpacker, &status_code);
  1762. print_debug ("close status code: %d", status_code);
  1763. str_append_data (&reason,
  1764. parser->input.str + 2, parser->payload_len - 2);
  1765. }
  1766. char *s = iconv_xstrdup (self->ctx->term_from_utf8,
  1767. reason.str, reason.len + 1 /* null byte */, NULL);
  1768. print_status ("server closed the connection (%s)", s);
  1769. str_free (&reason);
  1770. free (s);
  1771. return backend_ws_send_control (self, WS_OPCODE_CLOSE,
  1772. parser->input.str, parser->payload_len);
  1773. }
  1774. static bool
  1775. backend_ws_on_control_frame
  1776. (struct ws_context *self, const struct ws_parser *parser)
  1777. {
  1778. switch (parser->opcode)
  1779. {
  1780. case WS_OPCODE_CLOSE:
  1781. // We've received an unsolicited server close
  1782. if (self->state != WS_HANDLER_CLOSING)
  1783. (void) backend_ws_finish_closing_handshake (self, parser);
  1784. return false;
  1785. case WS_OPCODE_PING:
  1786. if (!backend_ws_send_control (self, WS_OPCODE_PONG,
  1787. parser->input.str, parser->payload_len))
  1788. return false;
  1789. break;
  1790. case WS_OPCODE_PONG:
  1791. // Not sending any pings but w/e
  1792. break;
  1793. default:
  1794. // Unknown control frame
  1795. return backend_ws_fail (self, WS_STATUS_PROTOCOL_ERROR);
  1796. }
  1797. return true;
  1798. }
  1799. /// Caller guarantees that data[len] is a NUL byte (because of iconv_xstrdup())
  1800. static bool
  1801. backend_ws_on_message (struct ws_context *self,
  1802. enum ws_opcode type, const void *data, size_t len)
  1803. {
  1804. if (type != WS_OPCODE_TEXT)
  1805. return backend_ws_fail (self, WS_STATUS_UNSUPPORTED_DATA);
  1806. await_try_finish (self->ctx, data, len);
  1807. return true;
  1808. }
  1809. static bool
  1810. backend_ws_on_frame (void *user_data, const struct ws_parser *parser)
  1811. {
  1812. struct ws_context *self = user_data;
  1813. if (ws_is_control_frame (parser->opcode))
  1814. return backend_ws_on_control_frame (self, parser);
  1815. // TODO: do this rather in "on_frame_header"
  1816. if (self->message_data.len + parser->payload_len
  1817. > BACKEND_WS_MAX_PAYLOAD_LEN)
  1818. return backend_ws_fail (self, WS_STATUS_MESSAGE_TOO_BIG);
  1819. if (!self->expecting_continuation)
  1820. self->message_opcode = parser->opcode;
  1821. str_append_data (&self->message_data,
  1822. parser->input.str, parser->payload_len);
  1823. self->expecting_continuation = !parser->is_fin;
  1824. if (!parser->is_fin)
  1825. return true;
  1826. if (self->message_opcode == WS_OPCODE_TEXT
  1827. && !utf8_validate (self->message_data.str, self->message_data.len))
  1828. return backend_ws_fail (self, WS_STATUS_INVALID_PAYLOAD_DATA);
  1829. bool result = backend_ws_on_message (self, self->message_opcode,
  1830. self->message_data.str, self->message_data.len);
  1831. str_reset (&self->message_data);
  1832. return result;
  1833. }
  1834. static void
  1835. backend_ws_on_connection_timeout (EV_P_ ev_timer *handle, int revents)
  1836. {
  1837. (void) loop;
  1838. (void) revents;
  1839. struct ws_context *self = handle->data;
  1840. hard_assert (self->ctx->awaiting && !self->ctx->await_response);
  1841. error_set (&self->ctx->await_error, "connection timeout");
  1842. backend_ws_close_connection (self);
  1843. }
  1844. static bool
  1845. backend_ws_connect (struct ws_context *self, struct error **e)
  1846. {
  1847. bool result = false;
  1848. char *url_schema = xstrndup (self->endpoint +
  1849. self->url.field_data[UF_SCHEMA].off,
  1850. self->url.field_data[UF_SCHEMA].len);
  1851. bool use_tls = !strcasecmp_ascii (url_schema, "wss");
  1852. free (url_schema);
  1853. char *url_host = xstrndup (self->endpoint +
  1854. self->url.field_data[UF_HOST].off,
  1855. self->url.field_data[UF_HOST].len);
  1856. char *url_port = (self->url.field_set & (1 << UF_PORT))
  1857. ? xstrndup (self->endpoint +
  1858. self->url.field_data[UF_PORT].off,
  1859. self->url.field_data[UF_PORT].len)
  1860. : xstrdup (use_tls ? "443" : "80");
  1861. struct str url_path = str_make ();
  1862. if (self->url.field_set & (1 << UF_PATH))
  1863. str_append_data (&url_path, self->endpoint +
  1864. self->url.field_data[UF_PATH].off,
  1865. self->url.field_data[UF_PATH].len);
  1866. else
  1867. str_append_c (&url_path, '/');
  1868. if (self->url.field_set & (1 << UF_QUERY))
  1869. {
  1870. str_append_c (&url_path, '?');
  1871. str_append_data (&url_path, self->endpoint +
  1872. self->url.field_data[UF_QUERY].off,
  1873. self->url.field_data[UF_QUERY].len);
  1874. }
  1875. // TODO: I guess we should also reset it on error
  1876. self->state = WS_HANDLER_CONNECTING;
  1877. if (!backend_ws_establish_connection (self, url_host, url_port, e))
  1878. goto fail_1;
  1879. if (use_tls && !backend_ws_initialize_tls (self, url_host, e))
  1880. goto fail_2;
  1881. unsigned char key[16];
  1882. if (!RAND_bytes (key, sizeof key))
  1883. {
  1884. error_set (e, "failed to get random bytes");
  1885. goto fail_2;
  1886. }
  1887. struct str key_b64 = str_make ();
  1888. base64_encode (key, sizeof key, &key_b64);
  1889. free (self->key);
  1890. char *key_b64_string = self->key = str_steal (&key_b64);
  1891. struct str request = str_make ();
  1892. str_append_printf (&request, "GET %s HTTP/1.1\r\n", url_path.str);
  1893. // TODO: omit the port if it's the default (check RFC for "SHOULD" or ...)
  1894. str_append_printf (&request, "Host: %s:%s\r\n", url_host, url_port);
  1895. str_append_printf (&request, "User-Agent: %s/%s\r\n",
  1896. PROGRAM_NAME, PROGRAM_VERSION);
  1897. str_append_printf (&request, "Upgrade: websocket\r\n");
  1898. str_append_printf (&request, "Connection: upgrade\r\n");
  1899. str_append_printf (&request, SEC_WS_KEY ": %s\r\n", key_b64_string);
  1900. str_append_printf (&request, SEC_WS_VERSION ": %s\r\n", "13");
  1901. for (size_t i = 0; i < self->extra_headers.len; i++)
  1902. str_append_printf (&request, "%s\r\n", self->extra_headers.vector[i]);
  1903. str_append_printf (&request, "\r\n");
  1904. bool written = backend_ws_write (self, request.str, request.len);
  1905. str_free (&request);
  1906. if (!written)
  1907. {
  1908. error_set (e, "connection failed");
  1909. goto fail_2;
  1910. }
  1911. http_parserpp_free (&self->http);
  1912. http_parserpp_init (&self->http, HTTP_RESPONSE);
  1913. ws_parser_free (&self->parser);
  1914. self->parser = ws_parser_make ();
  1915. self->parser.on_frame_header = backend_ws_on_frame_header;
  1916. self->parser.on_frame = backend_ws_on_frame;
  1917. self->parser.user_data = self;
  1918. ev_io_init (&self->read_watcher,
  1919. backend_ws_on_fd_ready, self->server_fd, EV_READ);
  1920. self->read_watcher.data = self;
  1921. ev_io_start (EV_DEFAULT_ &self->read_watcher);
  1922. // XXX: we should do everything non-blocking and include establishing
  1923. // the TCP connection in the timeout, but that requires a rewrite.
  1924. // As it is, this isn't really too useful.
  1925. ev_timer_init (&self->timeout_watcher,
  1926. backend_ws_on_connection_timeout, 30, 0);
  1927. self->timeout_watcher.data = self;
  1928. // Run an event loop to process the handshake
  1929. ev_timer_start (EV_DEFAULT_ &self->timeout_watcher);
  1930. result = await (self->ctx, NULL /* response_buffer */, e);
  1931. ev_timer_stop (EV_DEFAULT_ &self->timeout_watcher);
  1932. fail_2:
  1933. if (!result && self->server_fd != -1)
  1934. {
  1935. xclose (self->server_fd);
  1936. self->server_fd = -1;
  1937. }
  1938. fail_1:
  1939. free (url_host);
  1940. free (url_port);
  1941. str_free (&url_path);
  1942. return result;
  1943. }
  1944. static bool
  1945. backend_ws_make_call (struct backend *backend,
  1946. const char *request, bool expect_content, struct str *buf, struct error **e)
  1947. {
  1948. struct ws_context *self = (struct ws_context *) backend;
  1949. if (self->server_fd == -1)
  1950. if (!backend_ws_connect (self, e))
  1951. return false;
  1952. while (true)
  1953. {
  1954. if (backend_ws_send_message (self,
  1955. WS_OPCODE_TEXT, request, strlen (request)))
  1956. break;
  1957. print_status ("connection failed, reconnecting");
  1958. if (!backend_ws_connect (self, e))
  1959. return false;
  1960. }
  1961. return !expect_content || await (self->ctx, buf, e);
  1962. }
  1963. static void
  1964. backend_ws_destroy (struct backend *backend)
  1965. {
  1966. struct ws_context *self = (struct ws_context *) backend;
  1967. // TODO: maybe attempt a graceful shutdown, but for that there should
  1968. // probably be another backend method that runs an event loop
  1969. if (self->server_fd != -1)
  1970. backend_ws_close_connection (self);
  1971. free (self->endpoint);
  1972. strv_free (&self->extra_headers);
  1973. ev_timer_stop (EV_DEFAULT_ &self->timeout_watcher);
  1974. if (self->ssl_ctx)
  1975. SSL_CTX_free (self->ssl_ctx);
  1976. free (self->key);
  1977. http_parserpp_free (&self->http);
  1978. ws_parser_free (&self->parser);
  1979. str_free (&self->message_data);
  1980. }
  1981. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1982. static struct backend_vtable backend_ws_vtable =
  1983. {
  1984. .add_header = backend_ws_add_header,
  1985. .make_call = backend_ws_make_call,
  1986. .destroy = backend_ws_destroy,
  1987. };
  1988. static struct backend *
  1989. backend_ws_new (struct app_context *ctx,
  1990. const char *endpoint, struct http_parser_url *url)
  1991. {
  1992. struct ws_context *self = xcalloc (1, sizeof *self);
  1993. self->super.vtable = &backend_ws_vtable;
  1994. self->ctx = ctx;
  1995. ev_timer_init (&self->timeout_watcher, NULL, 0, 0);
  1996. self->server_fd = -1;
  1997. ev_io_init (&self->read_watcher, NULL, 0, 0);
  1998. http_parserpp_init (&self->http, HTTP_RESPONSE);
  1999. self->parser = ws_parser_make ();
  2000. self->message_data = str_make ();
  2001. self->extra_headers = strv_make ();
  2002. self->endpoint = xstrdup (endpoint);
  2003. self->url = *url;
  2004. #if OPENSSL_VERSION_NUMBER < 0x10100000L || LIBRESSL_VERSION_NUMBER
  2005. SSL_library_init ();
  2006. atexit (EVP_cleanup);
  2007. SSL_load_error_strings ();
  2008. atexit (ERR_free_strings);
  2009. #else
  2010. // Cleanup is done automatically via atexit()
  2011. OPENSSL_init_ssl (0, NULL);
  2012. #endif
  2013. return &self->super;
  2014. }
  2015. // --- cURL backend ------------------------------------------------------------
  2016. struct curl_context
  2017. {
  2018. struct backend super; ///< Parent class
  2019. struct app_context *ctx; ///< Application context
  2020. CURL *curl; ///< cURL handle
  2021. char curl_error[CURL_ERROR_SIZE]; ///< cURL error info buffer
  2022. struct curl_slist *headers; ///< Headers
  2023. };
  2024. static size_t
  2025. write_callback (char *ptr, size_t size, size_t nmemb, void *user_data)
  2026. {
  2027. struct str *buf = user_data;
  2028. str_append_data (buf, ptr, size * nmemb);
  2029. return size * nmemb;
  2030. }
  2031. static bool
  2032. validate_json_rpc_content_type (const char *content_type)
  2033. {
  2034. char *type = NULL;
  2035. char *subtype = NULL;
  2036. struct str_map parameters = str_map_make (free);
  2037. parameters.key_xfrm = tolower_ascii_strxfrm;
  2038. bool result = http_parse_media_type
  2039. (content_type, &type, &subtype, &parameters);
  2040. if (!result)
  2041. goto end;
  2042. if (strcasecmp_ascii (type, "application")
  2043. || (strcasecmp_ascii (subtype, "json") &&
  2044. strcasecmp_ascii (subtype, "json-rpc" /* obsolete */)))
  2045. result = false;
  2046. const char *charset = str_map_find (&parameters, "charset");
  2047. if (charset && strcasecmp_ascii (charset, "UTF-8"))
  2048. result = false;
  2049. // Currently ignoring all unknown parametrs
  2050. end:
  2051. free (type);
  2052. free (subtype);
  2053. str_map_free (&parameters);
  2054. return result;
  2055. }
  2056. static void
  2057. backend_curl_add_header (struct backend *backend, const char *header)
  2058. {
  2059. struct curl_context *self = (struct curl_context *) backend;
  2060. self->headers = curl_slist_append (self->headers, header);
  2061. if (curl_easy_setopt (self->curl, CURLOPT_HTTPHEADER, self->headers))
  2062. exit_fatal ("cURL setup failed");
  2063. }
  2064. static bool
  2065. backend_curl_make_call (struct backend *backend,
  2066. const char *request, bool expect_content, struct str *buf, struct error **e)
  2067. {
  2068. struct curl_context *self = (struct curl_context *) backend;
  2069. if (curl_easy_setopt (self->curl, CURLOPT_POSTFIELDS, request)
  2070. || curl_easy_setopt (self->curl, CURLOPT_POSTFIELDSIZE_LARGE,
  2071. (curl_off_t) -1)
  2072. || curl_easy_setopt (self->curl, CURLOPT_WRITEDATA, buf)
  2073. || curl_easy_setopt (self->curl, CURLOPT_WRITEFUNCTION, write_callback))
  2074. FAIL ("cURL setup failed");
  2075. CURLcode ret;
  2076. if ((ret = curl_easy_perform (self->curl)))
  2077. FAIL ("HTTP request failed: %s", self->curl_error);
  2078. long code;
  2079. char *type;
  2080. if (curl_easy_getinfo (self->curl, CURLINFO_RESPONSE_CODE, &code)
  2081. || curl_easy_getinfo (self->curl, CURLINFO_CONTENT_TYPE, &type))
  2082. FAIL ("cURL info retrieval failed");
  2083. if (code != 200)
  2084. FAIL ("unexpected HTTP response code: %ld", code);
  2085. if (!expect_content)
  2086. ; // Let there be anything
  2087. else if (!type)
  2088. print_warning ("missing `Content-Type' header");
  2089. else if (!validate_json_rpc_content_type (type))
  2090. print_warning ("unexpected `Content-Type' header: %s", type);
  2091. return true;
  2092. }
  2093. static void
  2094. backend_curl_destroy (struct backend *backend)
  2095. {
  2096. struct curl_context *self = (struct curl_context *) backend;
  2097. curl_slist_free_all (self->headers);
  2098. curl_easy_cleanup (self->curl);
  2099. }
  2100. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  2101. static struct backend_vtable backend_curl_vtable =
  2102. {
  2103. .add_header = backend_curl_add_header,
  2104. .make_call = backend_curl_make_call,
  2105. .destroy = backend_curl_destroy,
  2106. };
  2107. static struct backend *
  2108. backend_curl_new (struct app_context *ctx, const char *endpoint)
  2109. {
  2110. struct curl_context *self = xcalloc (1, sizeof *self);
  2111. self->super.vtable = &backend_curl_vtable;
  2112. self->ctx = ctx;
  2113. CURL *curl;
  2114. if (!(self->curl = curl = curl_easy_init ()))
  2115. exit_fatal ("cURL initialization failed");
  2116. self->headers = NULL;
  2117. self->headers = curl_slist_append
  2118. (self->headers, "Content-Type: application/json");
  2119. if (curl_easy_setopt (curl, CURLOPT_POST, 1L)
  2120. || curl_easy_setopt (curl, CURLOPT_NOPROGRESS, 1L)
  2121. || curl_easy_setopt (curl, CURLOPT_ERRORBUFFER, self->curl_error)
  2122. || curl_easy_setopt (curl, CURLOPT_HTTPHEADER, self->headers)
  2123. || curl_easy_setopt (curl, CURLOPT_SSL_VERIFYPEER,
  2124. self->ctx->trust_all ? 0L : 1L)
  2125. || curl_easy_setopt (curl, CURLOPT_SSL_VERIFYHOST,
  2126. self->ctx->trust_all ? 0L : 2L)
  2127. || curl_easy_setopt (curl, CURLOPT_URL, endpoint))
  2128. exit_fatal ("cURL setup failed");
  2129. if (!self->ctx->trust_all)
  2130. {
  2131. // TODO: try to resolve filenames relative to configuration directories
  2132. const char *ca_file = get_config_string
  2133. (self->ctx->config.root, "connection.tls_ca_file");
  2134. const char *ca_path = get_config_string
  2135. (self->ctx->config.root, "connection.tls_ca_path");
  2136. if ((ca_file && curl_easy_setopt (curl, CURLOPT_CAINFO, ca_file))
  2137. || (ca_path && curl_easy_setopt (curl, CURLOPT_CAPATH, ca_path)))
  2138. exit_fatal ("cURL setup failed");
  2139. }
  2140. return &self->super;
  2141. }
  2142. // --- Co-process backend ------------------------------------------------------
  2143. struct co_context
  2144. {
  2145. struct backend super; ///< Parent class
  2146. struct app_context *ctx; ///< Application context
  2147. pid_t child; ///< The co-process or -1
  2148. int socket; ///< Our end of the socketpair
  2149. int stderr_fd; ///< stderr read end
  2150. struct str stderr_buffer; ///< stderr buffer
  2151. ev_io stderr_watcher; ///< stderr watcher
  2152. ev_io socket_watcher; ///< Socketpair watcher
  2153. struct http_parserpp http; ///< HTTP parser
  2154. bool pending_fake_starter; ///< Start of message?
  2155. };
  2156. static int
  2157. backend_co_on_message_complete (http_parser *parser)
  2158. {
  2159. struct http_parserpp *self = parser->data;
  2160. http_parser_pause (&self->parser, true);
  2161. return 0;
  2162. }
  2163. // The LSP incorporates a very thin subset of RFC 822, and it so happens
  2164. // that we may simply reuse the full HTTP parser here, with a small hack.
  2165. static const http_parser_settings backend_co_http_settings =
  2166. {
  2167. .on_header_field = http_parserpp_on_header_field,
  2168. .on_header_value = http_parserpp_on_header_value,
  2169. .on_headers_complete = http_parserpp_on_headers_complete,
  2170. // TODO: check Content-Type early?
  2171. .on_message_begin = http_parserpp_on_message_begin,
  2172. .on_body = http_parserpp_on_body,
  2173. .on_message_complete = backend_co_on_message_complete,
  2174. };
  2175. static bool
  2176. backend_co_inject_starter (struct co_context *self, struct error **e)
  2177. {
  2178. // The default "Connection: keep-alive" maps well here.
  2179. // We cannot feed this line into the parser from within callbacks.
  2180. static const char starter[] = "POST / HTTP/1.1\r\n";
  2181. http_parser_pause (&self->http.parser, false);
  2182. size_t n_parsed = http_parser_execute (&self->http.parser,
  2183. &backend_co_http_settings, starter, sizeof starter - 1);
  2184. enum http_errno err = HTTP_PARSER_ERRNO (&self->http.parser);
  2185. if (n_parsed != sizeof starter - 1 || err != HPE_OK)
  2186. FAIL ("protocol failure: %s", http_errno_description (err));
  2187. return true;
  2188. }
  2189. static void
  2190. backend_co_process (struct co_context *self)
  2191. {
  2192. // TODO: verify Content-Type in the headers, though tricky and optional
  2193. struct str *message = &self->http.message;
  2194. await_try_finish (self->ctx, message->str, message->len);
  2195. }
  2196. static bool
  2197. backend_co_parse (struct co_context *self, const char *data, size_t len,
  2198. size_t *n_parsed, struct error **e)
  2199. {
  2200. if (self->pending_fake_starter)
  2201. {
  2202. self->pending_fake_starter = false;
  2203. if (!backend_co_inject_starter (self, e))
  2204. return false;
  2205. }
  2206. *n_parsed = http_parser_execute
  2207. (&self->http.parser, &backend_co_http_settings, data, len);
  2208. if (self->http.parser.upgrade)
  2209. FAIL ("protocol failure: %s", "unsupported upgrade attempt");
  2210. enum http_errno err = HTTP_PARSER_ERRNO (&self->http.parser);
  2211. if (err == HPE_PAUSED)
  2212. {
  2213. self->pending_fake_starter = true;
  2214. backend_co_process (self);
  2215. }
  2216. else if (err != HPE_OK)
  2217. FAIL ("protocol failure: %s", http_errno_description (err));
  2218. return true;
  2219. }
  2220. static bool
  2221. backend_co_on_data (struct co_context *self, const char *data, size_t len,
  2222. struct error **e)
  2223. {
  2224. size_t n_parsed = 0;
  2225. while (backend_co_parse (self, data, len, &n_parsed, e))
  2226. {
  2227. data += n_parsed;
  2228. if (!(len -= n_parsed))
  2229. return true;
  2230. }
  2231. return false;
  2232. }
  2233. static void
  2234. backend_co_on_socket_ready (EV_P_ ev_io *handle, int revents)
  2235. {
  2236. (void) loop;
  2237. (void) revents;
  2238. struct co_context *self = handle->data;
  2239. char buf[BUFSIZ];
  2240. restart:
  2241. // Try to read some data in a non-blocking manner
  2242. (void) set_blocking (handle->fd, false);
  2243. ssize_t n_read = read (handle->fd, buf, sizeof buf);
  2244. int errno_saved = errno;
  2245. (void) set_blocking (handle->fd, true);
  2246. errno = errno_saved;
  2247. struct error *e = NULL;
  2248. if (n_read < 0)
  2249. {
  2250. if (errno == EAGAIN)
  2251. return;
  2252. if (errno == EINTR)
  2253. goto restart;
  2254. print_error ("reading from the command failed: %s", strerror (errno));
  2255. }
  2256. else if (!backend_co_on_data (self, buf, n_read, &e))
  2257. {
  2258. print_error ("%s", e->message);
  2259. error_free (e);
  2260. }
  2261. else if (!n_read)
  2262. print_status ("the command has closed the connection");
  2263. else
  2264. goto restart;
  2265. ev_io_stop (EV_A_ handle);
  2266. // That would have no way of succeeding
  2267. await_try_cancel (self->ctx);
  2268. }
  2269. static void
  2270. backend_co_on_err_ready (EV_P_ ev_io *handle, int revents)
  2271. {
  2272. (void) revents;
  2273. struct co_context *self = handle->data;
  2274. struct str *buf = &self->stderr_buffer;
  2275. enum socket_io_result result = socket_io_try_read (handle->fd, buf);
  2276. char *p;
  2277. while ((p = strchr (buf->str, '\n')))
  2278. {
  2279. *p = 0;
  2280. print_status ("stderr: %s", buf->str);
  2281. str_remove_slice (buf, 0, p - buf->str + 1);
  2282. }
  2283. switch (result)
  2284. {
  2285. case SOCKET_IO_EOF:
  2286. print_debug ("the command has closed its stderr");
  2287. break;
  2288. case SOCKET_IO_OK:
  2289. return;
  2290. case SOCKET_IO_ERROR:
  2291. print_warning ("cannot read stderr: %s", strerror (errno));
  2292. }
  2293. ev_io_stop (EV_A_ handle);
  2294. }
  2295. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  2296. // TODO: do we want to go for synchronous writes, as with the WebSocket backend?
  2297. // We can postpone it for later.
  2298. static bool
  2299. backend_co_make_call (struct backend *backend,
  2300. const char *request, bool expect_content, struct str *buf, struct error **e)
  2301. {
  2302. struct co_context *self = (struct co_context *) backend;
  2303. struct str wrapped = str_make();
  2304. str_append_printf (&wrapped,
  2305. "Content-Length: %zu\r\n"
  2306. "Content-Type: application/json; charset=utf-8\r\n"
  2307. "\r\n%s", strlen (request), request);
  2308. enum socket_io_result result = socket_io_try_write (self->socket, &wrapped);
  2309. if (result == SOCKET_IO_ERROR)
  2310. {
  2311. str_free (&wrapped);
  2312. ev_io_stop (EV_DEFAULT_ &self->socket_watcher);
  2313. FAIL ("writing to the command failed: %s", strerror (errno));
  2314. }
  2315. else if (wrapped.len)
  2316. print_error ("internal error, partial write to command");
  2317. str_free (&wrapped);
  2318. return !expect_content || await (self->ctx, buf, e);
  2319. }
  2320. static bool
  2321. backend_co_on_child (struct backend *backend, pid_t pid, int status)
  2322. {
  2323. struct co_context *self = (struct co_context *) backend;
  2324. if (pid != self->child)
  2325. return false;
  2326. if (WIFSTOPPED (status))
  2327. print_warning ("the command has been stopped");
  2328. else if (WIFCONTINUED (status))
  2329. print_warning ("the command has been resumed");
  2330. else
  2331. {
  2332. if (WIFEXITED (status))
  2333. print_error ("the command has exited with status %d",
  2334. WEXITSTATUS (status));
  2335. else
  2336. print_error ("the command has died from signal %d",
  2337. WTERMSIG (status));
  2338. self->child = -1;
  2339. // Wait for the file descriptor to close, it may still contain data
  2340. }
  2341. return true;
  2342. }
  2343. static void
  2344. backend_co_destroy (struct backend *backend)
  2345. {
  2346. struct co_context *self = (struct co_context *) backend;
  2347. str_free (&self->stderr_buffer);
  2348. http_parserpp_free (&self->http);
  2349. if (self->socket != -1)
  2350. xclose (self->socket);
  2351. if (self->stderr_fd != -1)
  2352. xclose (self->stderr_fd);
  2353. if (self->child != -1)
  2354. (void) kill (self->child, SIGKILL);
  2355. }
  2356. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  2357. static struct backend_vtable backend_co_vtable =
  2358. {
  2359. .add_header = NULL,
  2360. .make_call = backend_co_make_call,
  2361. .on_child = backend_co_on_child,
  2362. .destroy = backend_co_destroy,
  2363. };
  2364. static struct backend *
  2365. backend_co_new (struct app_context *ctx, char **argv)
  2366. {
  2367. struct co_context *self = xcalloc (1, sizeof *self);
  2368. self->super.vtable = &backend_co_vtable;
  2369. self->ctx = ctx;
  2370. enum { OURS, THEIRS };
  2371. int pair[2] = { -1, -1 }, err[2] = { -1, -1 };
  2372. if (socketpair (AF_UNIX, SOCK_STREAM, 0, pair))
  2373. exit_fatal ("socketpair: %s", strerror (errno));
  2374. if (pipe (err))
  2375. exit_fatal ("pipe: %s", strerror (errno));
  2376. set_cloexec ((self->socket = pair[OURS]));
  2377. set_cloexec (pair[THEIRS]);
  2378. set_cloexec ((self->stderr_fd = err[OURS]));
  2379. set_cloexec (err[THEIRS]);
  2380. // It runs in our own progress group, so it gets SIGINTed with us
  2381. switch ((self->child = fork ()))
  2382. {
  2383. case -1:
  2384. exit_fatal ("fork: %s", strerror (errno));
  2385. case 0:
  2386. dup2 (pair[THEIRS], STDIN_FILENO);
  2387. dup2 (pair[THEIRS], STDOUT_FILENO);
  2388. dup2 (err[THEIRS], STDERR_FILENO);
  2389. // Undo what we've done in init_watchers()
  2390. signal (SIGPIPE, SIG_DFL);
  2391. signal (SIGTTOU, SIG_DFL);
  2392. execvp (argv[0], argv);
  2393. // stderr has been redirected, this won't cause a SIGTTOU
  2394. print_error ("execv: %s", strerror (errno));
  2395. _exit (EXIT_FAILURE);
  2396. default:
  2397. xclose (pair[THEIRS]);
  2398. xclose (err[THEIRS]);
  2399. }
  2400. ev_io_init (&self->socket_watcher,
  2401. backend_co_on_socket_ready, self->socket, EV_READ);
  2402. self->socket_watcher.data = self;
  2403. ev_io_start (EV_DEFAULT_ &self->socket_watcher);
  2404. set_blocking (self->stderr_fd, false);
  2405. self->stderr_buffer = str_make ();
  2406. ev_io_init (&self->stderr_watcher,
  2407. backend_co_on_err_ready, self->stderr_fd, EV_READ);
  2408. self->stderr_watcher.data = self;
  2409. ev_io_start (EV_DEFAULT_ &self->stderr_watcher);
  2410. http_parserpp_init (&self->http, HTTP_REQUEST);
  2411. self->pending_fake_starter = true;
  2412. return &self->super;
  2413. }
  2414. // --- JSON tokenizer ----------------------------------------------------------
  2415. // A dumb JSON tokenizer intended strictly just for syntax highlighting
  2416. //
  2417. // TODO: return also escape squences as a special token class (-> state)
  2418. enum jtoken
  2419. {
  2420. JTOKEN_EOF, ///< End of input
  2421. JTOKEN_ERROR, ///< EOF or error
  2422. JTOKEN_WHITESPACE, ///< Whitespace
  2423. JTOKEN_LBRACKET, ///< Left bracket
  2424. JTOKEN_RBRACKET, ///< Right bracket
  2425. JTOKEN_LBRACE, ///< Left curly bracket
  2426. JTOKEN_RBRACE, ///< Right curly bracket
  2427. JTOKEN_COLON, ///< Colon
  2428. JTOKEN_COMMA, ///< Comma
  2429. JTOKEN_NULL, ///< null
  2430. JTOKEN_BOOLEAN, ///< true, false
  2431. JTOKEN_NUMBER, ///< Number
  2432. JTOKEN_STRING ///< String
  2433. };
  2434. struct jtokenizer
  2435. {
  2436. const char *p; ///< Current position in input
  2437. size_t len; ///< How many bytes of input are left
  2438. struct str chunk; ///< Parsed chunk
  2439. };
  2440. static void
  2441. jtokenizer_init (struct jtokenizer *self, const char *p, size_t len)
  2442. {
  2443. self->p = p;
  2444. self->len = len;
  2445. self->chunk = str_make ();
  2446. }
  2447. static void
  2448. jtokenizer_free (struct jtokenizer *self)
  2449. {
  2450. str_free (&self->chunk);
  2451. }
  2452. static void
  2453. jtokenizer_advance (struct jtokenizer *self, size_t n)
  2454. {
  2455. str_append_data (&self->chunk, self->p, n);
  2456. self->p += n;
  2457. self->len -= n;
  2458. }
  2459. static int
  2460. jtokenizer_accept (struct jtokenizer *self, const char *chars)
  2461. {
  2462. if (!self->len || !strchr (chars, *self->p))
  2463. return false;
  2464. jtokenizer_advance (self, 1);
  2465. return true;
  2466. }
  2467. static bool
  2468. jtokenizer_ws (struct jtokenizer *self)
  2469. {
  2470. size_t len = 0;
  2471. while (jtokenizer_accept (self, "\t\r\n "))
  2472. len++;
  2473. return len != 0;
  2474. }
  2475. static bool
  2476. jtokenizer_word (struct jtokenizer *self, const char *word)
  2477. {
  2478. size_t len = strlen (word);
  2479. if (self->len < len || memcmp (self->p, word, len))
  2480. return false;
  2481. jtokenizer_advance (self, len);
  2482. return true;
  2483. }
  2484. static bool
  2485. jtokenizer_escape_sequence (struct jtokenizer *self)
  2486. {
  2487. if (!self->len)
  2488. return false;
  2489. if (jtokenizer_accept (self, "u"))
  2490. {
  2491. for (int i = 0; i < 4; i++)
  2492. if (!jtokenizer_accept (self, "0123456789abcdefABCDEF"))
  2493. return false;
  2494. return true;
  2495. }
  2496. return jtokenizer_accept (self, "\"\\/bfnrt");
  2497. }
  2498. static bool
  2499. jtokenizer_string (struct jtokenizer *self)
  2500. {
  2501. while (self->len)
  2502. {
  2503. unsigned char c = *self->p;
  2504. jtokenizer_advance (self, 1);
  2505. if (c == '"')
  2506. return true;
  2507. if (c == '\\' && !jtokenizer_escape_sequence (self))
  2508. return false;
  2509. }
  2510. return false;
  2511. }
  2512. static bool
  2513. jtokenizer_integer (struct jtokenizer *self)
  2514. {
  2515. size_t len = 0;
  2516. while (jtokenizer_accept (self, "0123456789"))
  2517. len++;
  2518. return len != 0;
  2519. }
  2520. static bool
  2521. jtokenizer_number (struct jtokenizer *self)
  2522. {
  2523. (void) jtokenizer_accept (self, "-");
  2524. if (!self->len)
  2525. return false;
  2526. if (!jtokenizer_accept (self, "0")
  2527. && !jtokenizer_integer (self))
  2528. return false;
  2529. if (jtokenizer_accept (self, ".")
  2530. && !jtokenizer_integer (self))
  2531. return false;
  2532. if (jtokenizer_accept (self, "eE"))
  2533. {
  2534. (void) jtokenizer_accept (self, "+-");
  2535. if (!jtokenizer_integer (self))
  2536. return false;
  2537. }
  2538. return true;
  2539. }
  2540. static enum jtoken
  2541. jtokenizer_next (struct jtokenizer *self)
  2542. {
  2543. str_reset (&self->chunk);
  2544. if (!self->len) return JTOKEN_EOF;
  2545. if (jtokenizer_ws (self)) return JTOKEN_WHITESPACE;
  2546. if (jtokenizer_accept (self, "[")) return JTOKEN_LBRACKET;
  2547. if (jtokenizer_accept (self, "]")) return JTOKEN_RBRACKET;
  2548. if (jtokenizer_accept (self, "{")) return JTOKEN_LBRACE;
  2549. if (jtokenizer_accept (self, "}")) return JTOKEN_RBRACE;
  2550. if (jtokenizer_accept (self, ":")) return JTOKEN_COLON;
  2551. if (jtokenizer_accept (self, ",")) return JTOKEN_COMMA;
  2552. if (jtokenizer_word (self, "null")) return JTOKEN_NULL;
  2553. if (jtokenizer_word (self, "true")
  2554. || jtokenizer_word (self, "false")) return JTOKEN_BOOLEAN;
  2555. if (jtokenizer_accept (self, "\""))
  2556. {
  2557. if (jtokenizer_string (self)) return JTOKEN_STRING;
  2558. }
  2559. else if (jtokenizer_number (self)) return JTOKEN_NUMBER;
  2560. jtokenizer_advance (self, self->len);
  2561. return JTOKEN_ERROR;
  2562. }
  2563. // --- JSON highlighter --------------------------------------------------------
  2564. // Currently errors in parsing only mean that the rest doesn't get highlighted
  2565. struct json_highlight
  2566. {
  2567. struct app_context *ctx; ///< Application context
  2568. struct jtokenizer tokenizer; ///< Tokenizer
  2569. FILE *output; ///< Output handle
  2570. };
  2571. static void
  2572. json_highlight_print (struct json_highlight *self, int attr)
  2573. {
  2574. print_attributed (self->ctx, self->output, attr,
  2575. "%s", self->tokenizer.chunk.str);
  2576. }
  2577. static void json_highlight_value
  2578. (struct json_highlight *self, enum jtoken token);
  2579. static void
  2580. json_highlight_object (struct json_highlight *self)
  2581. {
  2582. // Distinguishing field names from regular string values in objects
  2583. bool in_field_name = true;
  2584. enum jtoken token;
  2585. while ((token = jtokenizer_next (&self->tokenizer)))
  2586. switch (token)
  2587. {
  2588. case JTOKEN_COLON:
  2589. in_field_name = false;
  2590. json_highlight_value (self, token);
  2591. break;
  2592. case JTOKEN_COMMA:
  2593. in_field_name = true;
  2594. json_highlight_value (self, token);
  2595. break;
  2596. case JTOKEN_STRING:
  2597. if (in_field_name)
  2598. json_highlight_print (self, ATTR_JSON_FIELD);
  2599. else
  2600. json_highlight_print (self, ATTR_JSON_STRING);
  2601. break;
  2602. case JTOKEN_RBRACE:
  2603. json_highlight_value (self, token);
  2604. return;
  2605. default:
  2606. json_highlight_value (self, token);
  2607. }
  2608. }
  2609. static void
  2610. json_highlight_array (struct json_highlight *self)
  2611. {
  2612. enum jtoken token;
  2613. while ((token = jtokenizer_next (&self->tokenizer)))
  2614. switch (token)
  2615. {
  2616. case JTOKEN_RBRACKET:
  2617. json_highlight_value (self, token);
  2618. return;
  2619. default:
  2620. json_highlight_value (self, token);
  2621. }
  2622. }
  2623. static void
  2624. json_highlight_value (struct json_highlight *self, enum jtoken token)
  2625. {
  2626. switch (token)
  2627. {
  2628. case JTOKEN_LBRACE:
  2629. json_highlight_print (self, ATTR_INCOMING);
  2630. json_highlight_object (self);
  2631. break;
  2632. case JTOKEN_LBRACKET:
  2633. json_highlight_print (self, ATTR_INCOMING);
  2634. json_highlight_array (self);
  2635. break;
  2636. case JTOKEN_NULL:
  2637. json_highlight_print (self, ATTR_JSON_NULL);
  2638. break;
  2639. case JTOKEN_BOOLEAN:
  2640. json_highlight_print (self, ATTR_JSON_BOOL);
  2641. break;
  2642. case JTOKEN_NUMBER:
  2643. json_highlight_print (self, ATTR_JSON_NUMBER);
  2644. break;
  2645. case JTOKEN_STRING:
  2646. json_highlight_print (self, ATTR_JSON_STRING);
  2647. break;
  2648. default:
  2649. json_highlight_print (self, ATTR_INCOMING);
  2650. }
  2651. }
  2652. static void
  2653. json_highlight (struct app_context *ctx, const char *s, FILE *output)
  2654. {
  2655. struct json_highlight self = { .ctx = ctx, .output = output };
  2656. jtokenizer_init (&self.tokenizer, s, strlen (s));
  2657. // There should be at maximum one value in the input however,
  2658. // but let's just keep on going and process it all
  2659. enum jtoken token;
  2660. while ((token = jtokenizer_next (&self.tokenizer)))
  2661. json_highlight_value (&self, token);
  2662. fflush (output);
  2663. jtokenizer_free (&self.tokenizer);
  2664. }
  2665. // --- Main program ------------------------------------------------------------
  2666. static void
  2667. quit (struct app_context *ctx)
  2668. {
  2669. if (ctx->awaiting && !ctx->await_error)
  2670. error_set (&ctx->await_error, "aborted by user");
  2671. ev_break (EV_DEFAULT_ EVBREAK_ALL);
  2672. ctx->input->vtable->hide (ctx->input);
  2673. }
  2674. static void
  2675. suspend_terminal (struct app_context *ctx)
  2676. {
  2677. ctx->input->vtable->hide (ctx->input);
  2678. ev_io_stop (EV_DEFAULT_ &ctx->tty_watcher);
  2679. ctx->input->vtable->prepare (ctx->input, false);
  2680. }
  2681. static void
  2682. resume_terminal (struct app_context *ctx)
  2683. {
  2684. ctx->input->vtable->prepare (ctx->input, true);
  2685. ctx->input->vtable->on_terminal_resized (ctx->input);
  2686. ev_io_start (EV_DEFAULT_ &ctx->tty_watcher);
  2687. ctx->input->vtable->show (ctx->input);
  2688. }
  2689. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  2690. #define PARSE_FAIL(...) \
  2691. BLOCK_START \
  2692. print_error (__VA_ARGS__); \
  2693. goto fail; \
  2694. BLOCK_END
  2695. // XXX: should probably rather defer this action and use spawn_helper_child()
  2696. static void
  2697. display_via_pipeline (struct app_context *ctx,
  2698. const char *s, const char *pipeline)
  2699. {
  2700. suspend_terminal (ctx);
  2701. errno = 0;
  2702. FILE *fp = popen (pipeline, "w");
  2703. if (fp)
  2704. {
  2705. fputs (s, fp);
  2706. pclose (fp);
  2707. }
  2708. if (errno)
  2709. print_error ("pipeline failed: %s", strerror (errno));
  2710. resume_terminal (ctx);
  2711. }
  2712. static bool
  2713. process_response (struct app_context *ctx, const json_t *id, struct str *buf,
  2714. const char *pipeline)
  2715. {
  2716. if (!id)
  2717. {
  2718. printf ("[Notification]\n");
  2719. if (!buf->len)
  2720. return true;
  2721. print_warning ("we have been sent data back for a notification");
  2722. return false;
  2723. }
  2724. json_error_t e;
  2725. json_t *response;
  2726. if (!(response = json_loadb (buf->str, buf->len, JSON_DECODE_ANY, &e)))
  2727. {
  2728. print_error ("failed to parse the response: %s", e.text);
  2729. return false;
  2730. }
  2731. bool success = false;
  2732. if (!json_is_object (response))
  2733. PARSE_FAIL ("the response is not a JSON object");
  2734. json_t *v;
  2735. if (!(v = json_object_get (response, "jsonrpc")))
  2736. print_warning ("`%s' field not present in response", "jsonrpc");
  2737. else if (!json_is_string (v) || strcmp (json_string_value (v), "2.0"))
  2738. print_warning ("invalid `%s' field in response", "jsonrpc");
  2739. json_t *returned_id = json_object_get (response, "id");
  2740. json_t *result = json_object_get (response, "result");
  2741. json_t *error = json_object_get (response, "error");
  2742. json_t *data = NULL;
  2743. if (!returned_id)
  2744. print_warning ("`%s' field not present in response", "id");
  2745. if (!json_equal (id, returned_id))
  2746. print_warning ("mismatching `%s' field in response", "id");
  2747. if (!result && !error)
  2748. PARSE_FAIL ("neither `result' nor `error' present in response");
  2749. if (result && error)
  2750. // Prohibited by the specification but happens in real life (null)
  2751. print_warning ("both `result' and `error' present in response");
  2752. if (error)
  2753. {
  2754. if (!json_is_object (error))
  2755. PARSE_FAIL ("invalid `%s' field in response", "error");
  2756. json_t *code = json_object_get (error, "code");
  2757. json_t *message = json_object_get (error, "message");
  2758. if (!code)
  2759. PARSE_FAIL ("missing `%s' field in error response", "code");
  2760. if (!message)
  2761. PARSE_FAIL ("missing `%s' field in error response", "message");
  2762. if (!json_is_integer (code))
  2763. PARSE_FAIL ("invalid `%s' field in error response", "code");
  2764. if (!json_is_string (message))
  2765. PARSE_FAIL ("invalid `%s' field in error response", "message");
  2766. json_int_t code_val = json_integer_value (code);
  2767. char *utf8 = xstrdup_printf ("error response: %" JSON_INTEGER_FORMAT
  2768. " (%s)", code_val, json_string_value (message));
  2769. char *s = iconv_xstrdup (ctx->term_from_utf8, utf8, -1, NULL);
  2770. free (utf8);
  2771. if (!s)
  2772. print_error ("character conversion failed for `%s'", "error");
  2773. else
  2774. printf ("%s\n", s);
  2775. free (s);
  2776. data = json_object_get (error, "data");
  2777. }
  2778. if (data)
  2779. {
  2780. char *utf8 = json_dumps (data, JSON_ENCODE_ANY);
  2781. char *s = iconv_xstrdup (ctx->term_from_utf8, utf8, -1, NULL);
  2782. free (utf8);
  2783. if (!s)
  2784. print_error ("character conversion failed for `%s'", "error data");
  2785. else
  2786. printf ("error data: %s\n", s);
  2787. free (s);
  2788. }
  2789. if (result)
  2790. {
  2791. int flags = JSON_ENCODE_ANY;
  2792. if (!ctx->compact)
  2793. flags |= JSON_INDENT (2);
  2794. char *utf8 = json_dumps (result, flags);
  2795. char *s = iconv_xstrdup (ctx->term_from_utf8, utf8, -1, NULL);
  2796. free (utf8);
  2797. if (!s)
  2798. print_error ("character conversion failed for `%s'", "result");
  2799. else if (pipeline)
  2800. display_via_pipeline (ctx, s, pipeline);
  2801. else
  2802. {
  2803. json_highlight (ctx, s, stdout);
  2804. fputc ('\n', stdout);
  2805. }
  2806. free (s);
  2807. }
  2808. success = true;
  2809. fail:
  2810. json_decref (response);
  2811. return success;
  2812. }
  2813. static void
  2814. maybe_print_verbose (struct app_context *ctx, intptr_t attribute,
  2815. char *utf8, size_t len)
  2816. {
  2817. if (!ctx->verbose)
  2818. return;
  2819. char *term = iconv_xstrdup (ctx->term_from_utf8, utf8, len, NULL);
  2820. if (!term)
  2821. {
  2822. print_error ("%s: %s", "verbose", "character conversion failed");
  2823. return;
  2824. }
  2825. ctx->input->vtable->hide (ctx->input);
  2826. print_attributed (ctx, stdout, attribute, "%s", term);
  2827. fputs ("\n", stdout);
  2828. free (term);
  2829. ctx->input->vtable->show (ctx->input);
  2830. }
  2831. static struct error *
  2832. json_rpc_call_raw (struct app_context *ctx,
  2833. const char *method, json_t *id, json_t *params, struct str *buf)
  2834. {
  2835. struct error *error = NULL;
  2836. if (ctx->awaiting)
  2837. {
  2838. // Only allow recursing once below, awaiting is not re-entrant
  2839. error_set (&error, "busy");
  2840. return error;
  2841. }
  2842. json_t *request = json_object ();
  2843. json_object_set_new (request, "jsonrpc", json_string ("2.0"));
  2844. json_object_set_new (request, "method", json_string (method));
  2845. if (id) json_object_set (request, "id", id);
  2846. if (params) json_object_set (request, "params", params);
  2847. char *req_utf8 = json_dumps (request, 0);
  2848. json_decref (request);
  2849. maybe_print_verbose (ctx, ATTR_OUTGOING, req_utf8, -1);
  2850. ctx->backend->vtable->make_call (ctx->backend, req_utf8,
  2851. id != NULL /* expect_content */, buf, &error);
  2852. free (req_utf8);
  2853. if (error)
  2854. return error;
  2855. maybe_print_verbose (ctx, ATTR_INCOMING, buf->str, buf->len + 1);
  2856. return NULL;
  2857. }
  2858. static void
  2859. make_json_rpc_call (struct app_context *ctx,
  2860. const char *method, json_t *id, json_t *params, const char *pipeline)
  2861. {
  2862. struct str buf = str_make ();
  2863. struct error *e = json_rpc_call_raw (ctx, method, id, params, &buf);
  2864. if (e)
  2865. {
  2866. print_error ("%s", e->message);
  2867. error_free (e);
  2868. }
  2869. else if (!process_response (ctx, id, &buf, pipeline))
  2870. {
  2871. char *s = iconv_xstrdup (ctx->term_from_utf8,
  2872. buf.str, buf.len + 1 /* null byte */, NULL);
  2873. if (!s)
  2874. print_error ("character conversion failed for `%s'",
  2875. "raw response data");
  2876. else if (!ctx->verbose /* already printed */)
  2877. printf ("%s: %s\n", "raw response data", s);
  2878. free (s);
  2879. }
  2880. str_free (&buf);
  2881. }
  2882. static bool
  2883. is_valid_json_rpc_id (json_t *v)
  2884. {
  2885. return json_is_string (v) || json_is_integer (v)
  2886. || json_is_real (v) || json_is_null (v); // These two shouldn't be used
  2887. }
  2888. static bool
  2889. is_valid_json_rpc_params (json_t *v)
  2890. {
  2891. return json_is_array (v) || json_is_object (v);
  2892. }
  2893. static void
  2894. process_input (char *user_input, void *user_data)
  2895. {
  2896. struct app_context *ctx = user_data;
  2897. if (!user_input)
  2898. {
  2899. quit (ctx);
  2900. return;
  2901. }
  2902. char *input;
  2903. size_t len;
  2904. if (!(input = iconv_xstrdup (ctx->term_to_utf8, user_input, -1, &len)))
  2905. {
  2906. print_error ("character conversion failed for `%s'", "user input");
  2907. goto fail;
  2908. }
  2909. // Cut out the method name first
  2910. char *p = input;
  2911. while (*p && isspace_ascii (*p))
  2912. p++;
  2913. // No input
  2914. if (!*p)
  2915. goto fail;
  2916. char *method = p;
  2917. while (*p && !isspace_ascii (*p))
  2918. p++;
  2919. if (*p)
  2920. *p++ = '\0';
  2921. // Now we go through this madness, just so that the order can be arbitrary
  2922. json_error_t e;
  2923. size_t args_len = 0;
  2924. json_t *args[2] = { NULL, NULL }, *id = NULL, *params = NULL;
  2925. char *pipeline = NULL;
  2926. while (true)
  2927. {
  2928. // Jansson is too stupid to just tell us that there was nothing;
  2929. // still genius compared to the clusterfuck of json-c
  2930. while (*p && isspace_ascii (*p))
  2931. p++;
  2932. if (!*p)
  2933. break;
  2934. if (*p == '|')
  2935. {
  2936. pipeline = xstrdup (++p);
  2937. break;
  2938. }
  2939. if (args_len == N_ELEMENTS (args))
  2940. {
  2941. print_error ("too many arguments");
  2942. goto fail_parse;
  2943. }
  2944. if (!(args[args_len] = json_loadb (p, len - (p - input),
  2945. JSON_DECODE_ANY | JSON_DISABLE_EOF_CHECK, &e)))
  2946. {
  2947. print_error ("failed to parse JSON value: %s", e.text);
  2948. goto fail_parse;
  2949. }
  2950. p += e.position;
  2951. args_len++;
  2952. }
  2953. for (size_t i = 0; i < args_len; i++)
  2954. {
  2955. json_t **target;
  2956. if (is_valid_json_rpc_id (args[i]))
  2957. target = &id;
  2958. else if (is_valid_json_rpc_params (args[i]))
  2959. target = &params;
  2960. else
  2961. {
  2962. print_error ("unexpected value at index %zu", i);
  2963. goto fail_parse;
  2964. }
  2965. if (*target)
  2966. {
  2967. print_error ("cannot specify multiple `id' or `params'");
  2968. goto fail_parse;
  2969. }
  2970. *target = json_incref (args[i]);
  2971. }
  2972. if (!id)
  2973. id = json_integer (ctx->next_id++);
  2974. // Use nulls to send notifications, unless a special switch is used
  2975. if (!ctx->null_as_id && json_is_null (id))
  2976. {
  2977. json_decref (id);
  2978. id = NULL;
  2979. }
  2980. make_json_rpc_call (ctx, method, id, params, pipeline);
  2981. fail_parse:
  2982. free (pipeline);
  2983. if (id) json_decref (id);
  2984. if (params) json_decref (params);
  2985. for (size_t i = 0; i < args_len; i++)
  2986. json_decref (args[i]);
  2987. fail:
  2988. free (input);
  2989. }
  2990. // --- OpenRPC information extraction ------------------------------------------
  2991. static void
  2992. parse_rpc_discover (struct app_context *ctx, struct str *buf, struct error **e)
  2993. {
  2994. // Just optimistically punch through, I don't have time for this shit
  2995. json_error_t error;
  2996. json_t *response = NULL, *methods = NULL, *value = NULL;
  2997. if (!(response = json_loadb (buf->str, buf->len, 0, &error)))
  2998. error_set (e, "parse failure: %s", error.text);
  2999. else if ((!(methods = json_object_get (response, "result"))
  3000. || !(methods = json_object_get (methods, "methods")))
  3001. && !(methods = json_object_get (response, "methods")))
  3002. error_set (e, "unsupported");
  3003. else
  3004. {
  3005. const char *name = NULL;
  3006. for (size_t i = 0; (value = json_array_get (methods, i)); i++)
  3007. if ((value = json_object_get (value, "name"))
  3008. && (name = json_string_value (value)))
  3009. str_map_set (&ctx->methods, name, (void *) 1);
  3010. }
  3011. json_decref (response);
  3012. }
  3013. static void
  3014. init_openrpc (struct app_context *ctx, const char *openrpc)
  3015. {
  3016. // Three possibilities: NULL for not requested, "" for rpc.discover,
  3017. // and anything else has to be a path to a JSON file
  3018. if (!openrpc)
  3019. return;
  3020. struct str buf = str_make ();
  3021. struct error *error;
  3022. if (*openrpc)
  3023. // This may or may not have a protocol envelope
  3024. read_file (openrpc, &buf, &error);
  3025. else
  3026. {
  3027. json_t *id = json_integer (ctx->next_id++);
  3028. error = json_rpc_call_raw (ctx, "rpc.discover", id, NULL, &buf);
  3029. json_decref (id);
  3030. }
  3031. if (!error)
  3032. parse_rpc_discover (ctx, &buf, &error);
  3033. if (error)
  3034. {
  3035. print_error ("OpenRPC: %s", error->message);
  3036. error_free (error);
  3037. }
  3038. str_free (&buf);
  3039. }
  3040. static char *
  3041. complete_method_name (const char *text, int state)
  3042. {
  3043. static struct str_map_iter iter;
  3044. if (!state)
  3045. iter = str_map_iter_make (&g_ctx.methods);
  3046. char *input;
  3047. size_t len;
  3048. if (!(input = iconv_xstrdup (g_ctx.term_to_utf8, (char *) text, -1, &len)))
  3049. {
  3050. print_error ("character conversion failed for `%s'", "user input");
  3051. return NULL;
  3052. }
  3053. char *match = NULL;
  3054. while (str_map_iter_next (&iter)
  3055. && (strncasecmp_ascii (input, iter.link->key, len - 1 /* XXX */)
  3056. || !(match = iconv_xstrdup (g_ctx.term_from_utf8,
  3057. iter.link->key, iter.link->key_length + 1, NULL))))
  3058. ;
  3059. free (input);
  3060. return match;
  3061. }
  3062. // --- Main program ------------------------------------------------------------
  3063. // The ability to use an external editor on the input line has been shamelessly
  3064. // copypasted from degesch with minor changes only.
  3065. static bool
  3066. dump_line_to_file (const char *line, char *template, struct error **e)
  3067. {
  3068. int fd = mkstemp (template);
  3069. if (fd < 0)
  3070. FAIL ("%s", strerror (errno));
  3071. bool success = xwrite (fd, line, strlen (line), e);
  3072. if (!success)
  3073. (void) unlink (template);
  3074. xclose (fd);
  3075. return success;
  3076. }
  3077. static char *
  3078. try_dump_line_to_file (const char *line)
  3079. {
  3080. char *template = resolve_filename
  3081. ("input.XXXXXX", resolve_relative_runtime_template);
  3082. struct error *e = NULL;
  3083. if (dump_line_to_file (line, template, &e))
  3084. return template;
  3085. print_error ("%s: %s",
  3086. "failed to create a temporary file for editing", e->message);
  3087. error_free (e);
  3088. free (template);
  3089. return NULL;
  3090. }
  3091. static pid_t
  3092. spawn_helper_child (struct app_context *ctx)
  3093. {
  3094. suspend_terminal (ctx);
  3095. pid_t child = fork ();
  3096. switch (child)
  3097. {
  3098. case -1:
  3099. {
  3100. int saved_errno = errno;
  3101. resume_terminal (ctx);
  3102. errno = saved_errno;
  3103. break;
  3104. }
  3105. case 0:
  3106. // Put the child in a new foreground process group
  3107. hard_assert (setpgid (0, 0) != -1);
  3108. hard_assert (tcsetpgrp (STDOUT_FILENO, getpgid (0)) != -1);
  3109. break;
  3110. default:
  3111. // Make sure of it in the parent as well before continuing
  3112. (void) setpgid (child, child);
  3113. }
  3114. return child;
  3115. }
  3116. static void
  3117. run_editor (const char *line, void *user_data)
  3118. {
  3119. struct app_context *ctx = user_data;
  3120. hard_assert (!ctx->editor_filename);
  3121. char *filename;
  3122. if (!(filename = try_dump_line_to_file (line)))
  3123. return;
  3124. const char *command;
  3125. if (!(command = getenv ("VISUAL"))
  3126. && !(command = getenv ("EDITOR")))
  3127. command = "vi";
  3128. switch (spawn_helper_child (ctx))
  3129. {
  3130. case 0:
  3131. execlp (command, command, filename, NULL);
  3132. print_error ("%s: %s", "failed to launch editor", strerror (errno));
  3133. _exit (EXIT_FAILURE);
  3134. case -1:
  3135. print_error ("%s: %s", "failed to launch editor", strerror (errno));
  3136. free (filename);
  3137. break;
  3138. default:
  3139. ctx->editor_filename = filename;
  3140. }
  3141. }
  3142. static void
  3143. process_edited_input (struct app_context *ctx)
  3144. {
  3145. struct str input = str_make ();
  3146. struct error *e = NULL;
  3147. if (!read_file (ctx->editor_filename, &input, &e))
  3148. {
  3149. print_error ("%s: %s", "input editing failed", e->message);
  3150. error_free (e);
  3151. }
  3152. else
  3153. {
  3154. // Strip trailing newlines, added automatically by editors
  3155. while (input.len && strchr ("\r\n", input.str[input.len - 1]))
  3156. input.str[--input.len] = 0;
  3157. if (!ctx->input->vtable->replace_line (ctx->input, input.str))
  3158. print_error ("%s: %s", "input editing failed",
  3159. "could not re-insert modified text");
  3160. }
  3161. if (unlink (ctx->editor_filename))
  3162. print_error ("could not unlink `%s': %s",
  3163. ctx->editor_filename, strerror (errno));
  3164. str_free (&input);
  3165. }
  3166. static void
  3167. on_child (EV_P_ ev_child *handle, int revents)
  3168. {
  3169. (void) revents;
  3170. struct app_context *ctx = ev_userdata (loop);
  3171. if (ctx->backend->vtable->on_child
  3172. && ctx->backend->vtable->on_child (ctx->backend,
  3173. handle->rpid, handle->rstatus))
  3174. return;
  3175. // I am not a shell, stopping not allowed
  3176. int status = handle->rstatus;
  3177. if (WIFSTOPPED (status)
  3178. || WIFCONTINUED (status))
  3179. {
  3180. kill (-handle->rpid, SIGKILL);
  3181. return;
  3182. }
  3183. // I don't recognize this child (we should also check its PID)
  3184. if (!ctx->editor_filename)
  3185. return;
  3186. hard_assert (tcsetpgrp (STDOUT_FILENO, getpgid (0)) != -1);
  3187. resume_terminal (ctx);
  3188. if (WIFSIGNALED (status))
  3189. print_error ("editor died from signal %d", WTERMSIG (status));
  3190. else if (WIFEXITED (status) && WEXITSTATUS (status) != 0)
  3191. print_error ("editor returned status %d", WEXITSTATUS (status));
  3192. else
  3193. process_edited_input (ctx);
  3194. cstr_set (&ctx->editor_filename, NULL);
  3195. }
  3196. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  3197. static void
  3198. on_winch (EV_P_ ev_signal *handle, int revents)
  3199. {
  3200. (void) handle;
  3201. (void) revents;
  3202. struct app_context *ctx = ev_userdata (loop);
  3203. ctx->input->vtable->on_terminal_resized (ctx->input);
  3204. }
  3205. static void
  3206. on_terminated (EV_P_ ev_signal *handle, int revents)
  3207. {
  3208. (void) handle;
  3209. (void) revents;
  3210. struct app_context *ctx = ev_userdata (loop);
  3211. quit (ctx);
  3212. }
  3213. static void
  3214. on_tty_readable (EV_P_ ev_io *handle, int revents)
  3215. {
  3216. (void) handle;
  3217. struct app_context *ctx = ev_userdata (loop);
  3218. if (revents & EV_READ)
  3219. {
  3220. // rl_callback_read_char() is not reentrant, may happen on EOF
  3221. ev_io_stop (EV_DEFAULT_ &ctx->tty_watcher);
  3222. ctx->input->vtable->on_tty_readable (ctx->input);
  3223. // Don't make ourselves receive a SIGTTIN. Ideally we'd prevent
  3224. // reentrancy without inciting conflicts with
  3225. // {suspend,resume}_terminal() but I can't figure anything out.
  3226. if (!ctx->editor_filename)
  3227. ev_io_start (EV_DEFAULT_ &ctx->tty_watcher);
  3228. }
  3229. }
  3230. static void
  3231. init_watchers (struct app_context *ctx)
  3232. {
  3233. if (!EV_DEFAULT)
  3234. exit_fatal ("libev initialization failed");
  3235. // So that if the remote end closes the connection, attempts to write to
  3236. // the socket don't terminate the program
  3237. (void) signal (SIGPIPE, SIG_IGN);
  3238. // So that we can write to the terminal while we're running a backlog
  3239. // helper. This is also inherited by the child so that it doesn't stop
  3240. // when it calls tcsetpgrp().
  3241. (void) signal (SIGTTOU, SIG_IGN);
  3242. ev_child_init (&ctx->child_watcher, on_child, 0, true);
  3243. ev_child_start (EV_DEFAULT_ &ctx->child_watcher);
  3244. ev_signal_init (&ctx->winch_watcher, on_winch, SIGWINCH);
  3245. ev_signal_start (EV_DEFAULT_ &ctx->winch_watcher);
  3246. ev_signal_init (&ctx->term_watcher, on_terminated, SIGTERM);
  3247. ev_signal_start (EV_DEFAULT_ &ctx->term_watcher);
  3248. ev_signal_init (&ctx->int_watcher, on_terminated, SIGINT);
  3249. ev_signal_start (EV_DEFAULT_ &ctx->int_watcher);
  3250. ev_io_init (&ctx->tty_watcher, on_tty_readable, STDIN_FILENO, EV_READ);
  3251. ev_io_start (EV_DEFAULT_ &ctx->tty_watcher);
  3252. }
  3253. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  3254. static void
  3255. parse_program_arguments (struct app_context *ctx, int argc, char **argv,
  3256. const char **origin, const char **endpoint, const char **openrpc)
  3257. {
  3258. static const struct opt opts[] =
  3259. {
  3260. { 'c', "compact-output", NULL, 0, "do not pretty-print responses" },
  3261. { 'C', "color", "WHEN", OPT_LONG_ONLY,
  3262. "colorize output: never, always, or auto" },
  3263. { 'e', "execute", NULL, 0, "launch a command to act as a server" },
  3264. { 'n', "null-as-id", NULL, 0, "JSON null is used as an `id'" },
  3265. { 'o', "origin", "O", 0, "set the HTTP Origin header" },
  3266. // So far you have to explicitly enable this rather than disable
  3267. { 'O', "openrpc", "PATH", OPT_OPTIONAL_ARG,
  3268. "method name completion using OpenRPC" },
  3269. { 't', "trust-all", NULL, 0, "don't care about SSL/TLS certificates" },
  3270. { 'v', "verbose", NULL, 0, "print raw requests and responses" },
  3271. { 'w', "write-default-cfg", "PATH",
  3272. OPT_OPTIONAL_ARG | OPT_LONG_ONLY,
  3273. "write a default configuration file and exit" },
  3274. { 'd', "debug", NULL, 0, "run in debug mode" },
  3275. { 'h', "help", NULL, 0, "display this help message and exit" },
  3276. { 'V', "version", NULL, 0, "output version information and exit" },
  3277. { 0, NULL, NULL, 0, NULL }
  3278. };
  3279. struct opt_handler oh = opt_handler_make (argc, argv, opts,
  3280. "{ ENDPOINT | COMMAND [ARG]... }", "A shell for JSON-RPC 2.0.");
  3281. int c;
  3282. bool run_command = false;
  3283. while ((c = opt_handler_get (&oh)) != -1)
  3284. switch (c)
  3285. {
  3286. case 'd':
  3287. g_debug_mode = true;
  3288. break;
  3289. case 'h':
  3290. opt_handler_usage (&oh, stdout);
  3291. exit (EXIT_SUCCESS);
  3292. case 'V':
  3293. printf (PROGRAM_NAME " " PROGRAM_VERSION "\n");
  3294. exit (EXIT_SUCCESS);
  3295. case 'o': *origin = optarg; break;
  3296. case 'O': *openrpc = optarg ? optarg : ""; break;
  3297. case 'e': run_command = true; break;
  3298. case 'n': ctx->null_as_id = true; break;
  3299. case 'c': ctx->compact = true; break;
  3300. case 't': ctx->trust_all = true; break;
  3301. case 'v': ctx->verbose = true; break;
  3302. case 'C':
  3303. if (!strcasecmp (optarg, "never"))
  3304. ctx->color_mode = COLOR_NEVER;
  3305. else if (!strcasecmp (optarg, "always"))
  3306. ctx->color_mode = COLOR_ALWAYS;
  3307. else if (!strcasecmp (optarg, "auto"))
  3308. ctx->color_mode = COLOR_AUTO;
  3309. else
  3310. {
  3311. print_error ("`%s' is not a valid value for `%s'", optarg, "color");
  3312. exit (EXIT_FAILURE);
  3313. }
  3314. break;
  3315. case 'w':
  3316. save_configuration (ctx->config.root, optarg);
  3317. exit (EXIT_SUCCESS);
  3318. default:
  3319. print_error ("wrong options");
  3320. opt_handler_usage (&oh, stderr);
  3321. exit (EXIT_FAILURE);
  3322. }
  3323. argc -= optind;
  3324. argv += optind;
  3325. if (run_command && argc >= 1)
  3326. *endpoint = NULL;
  3327. else if (argc == 1)
  3328. *endpoint = argv[0];
  3329. else
  3330. {
  3331. opt_handler_usage (&oh, stderr);
  3332. exit (EXIT_FAILURE);
  3333. }
  3334. opt_handler_free (&oh);
  3335. }
  3336. static void
  3337. init_backend (struct app_context *ctx, const char *origin, const char *endpoint,
  3338. char **argv)
  3339. {
  3340. if (!endpoint)
  3341. {
  3342. // There is no point in passing the Origin to a co-process
  3343. ctx->backend = backend_co_new (ctx, argv);
  3344. return;
  3345. }
  3346. struct http_parser_url url;
  3347. if (http_parser_parse_url (endpoint, strlen (endpoint), false, &url))
  3348. exit_fatal ("invalid endpoint address");
  3349. if (!(url.field_set & (1 << UF_SCHEMA)))
  3350. exit_fatal ("invalid endpoint address, must contain the schema");
  3351. char *url_schema = xstrndup (endpoint +
  3352. url.field_data[UF_SCHEMA].off,
  3353. url.field_data[UF_SCHEMA].len);
  3354. // TODO: try to avoid the need to pass the application context to backends
  3355. if (!strcasecmp_ascii (url_schema, "http")
  3356. || !strcasecmp_ascii (url_schema, "https"))
  3357. ctx->backend = backend_curl_new (ctx, endpoint);
  3358. else if (!strcasecmp_ascii (url_schema, "ws")
  3359. || !strcasecmp_ascii (url_schema, "wss"))
  3360. ctx->backend = backend_ws_new (ctx, endpoint, &url);
  3361. else
  3362. exit_fatal ("unsupported protocol");
  3363. free (url_schema);
  3364. if (origin)
  3365. {
  3366. char *header = xstrdup_printf ("Origin: %s", origin);
  3367. g_ctx.backend->vtable->add_header (g_ctx.backend, header);
  3368. free (header);
  3369. }
  3370. }
  3371. int
  3372. main (int argc, char *argv[])
  3373. {
  3374. g_ctx.config = config_make ();
  3375. register_config_modules (&g_ctx);
  3376. config_load (&g_ctx.config, config_item_object ());
  3377. const char *origin = NULL, *endpoint = NULL, *openrpc = NULL;
  3378. parse_program_arguments (&g_ctx, argc, argv, &origin, &endpoint, &openrpc);
  3379. argc -= optind;
  3380. argv += optind;
  3381. g_ctx.input = input_new ();
  3382. g_ctx.input->user_data = &g_ctx;
  3383. g_ctx.input->on_input = process_input;
  3384. g_ctx.input->on_run_editor = run_editor;
  3385. g_ctx.input->complete_start_word = complete_method_name;
  3386. g_ctx.methods = str_map_make (NULL);
  3387. init_colors (&g_ctx);
  3388. load_configuration (&g_ctx);
  3389. init_backend (&g_ctx, origin, endpoint, argv);
  3390. // We only need to convert to and from the terminal encoding
  3391. setlocale (LC_CTYPE, "");
  3392. char *encoding = nl_langinfo (CODESET);
  3393. #ifdef __linux__
  3394. // XXX: not quite sure if this is actually desirable
  3395. // TODO: instead retry with JSON_ENSURE_ASCII
  3396. encoding = xstrdup_printf ("%s//TRANSLIT", encoding);
  3397. #endif // __linux__
  3398. if ((g_ctx.term_from_utf8 = iconv_open (encoding, "UTF-8"))
  3399. == (iconv_t) -1
  3400. || (g_ctx.term_to_utf8 = iconv_open ("UTF-8", nl_langinfo (CODESET)))
  3401. == (iconv_t) -1)
  3402. exit_fatal ("creating the UTF-8 conversion object failed: %s",
  3403. strerror (errno));
  3404. char *data_home = getenv ("XDG_DATA_HOME"), *home = getenv ("HOME");
  3405. if (!data_home || *data_home != '/')
  3406. {
  3407. if (!home)
  3408. exit_fatal ("where is your $HOME, kid?");
  3409. data_home = xstrdup_printf ("%s/.local/share", home);
  3410. }
  3411. char *history_path =
  3412. xstrdup_printf ("%s/" PROGRAM_NAME "/history", data_home);
  3413. (void) g_ctx.input->vtable->load_history (g_ctx.input, history_path, NULL);
  3414. if (!get_attribute_printer (stdout))
  3415. g_ctx.input->vtable->set_prompt (g_ctx.input,
  3416. xstrdup_printf ("json-rpc> "));
  3417. else
  3418. {
  3419. // XXX: to be completely correct, we should use tputs, but we cannot
  3420. g_ctx.input->vtable->set_prompt (g_ctx.input,
  3421. xstrdup_printf ("%c%s%cjson-rpc>%c%s%c ",
  3422. INPUT_START_IGNORE, g_ctx.attrs[ATTR_PROMPT],
  3423. INPUT_END_IGNORE,
  3424. INPUT_START_IGNORE, g_ctx.attrs[ATTR_RESET],
  3425. INPUT_END_IGNORE));
  3426. }
  3427. init_watchers (&g_ctx);
  3428. g_ctx.input->vtable->start (g_ctx.input, PROGRAM_NAME);
  3429. ev_set_userdata (EV_DEFAULT_ &g_ctx);
  3430. init_openrpc (&g_ctx, openrpc);
  3431. ev_run (EV_DEFAULT_ 0);
  3432. // User has terminated the program, let's save the history and clean up
  3433. struct error *e = NULL;
  3434. char *dir = xstrdup (history_path);
  3435. if (!mkdir_with_parents (dirname (dir), &e)
  3436. || !g_ctx.input->vtable->save_history (g_ctx.input, history_path, &e))
  3437. {
  3438. print_error ("writing the history file `%s' failed: %s",
  3439. history_path, e->message);
  3440. error_free (e);
  3441. }
  3442. free (dir);
  3443. free (history_path);
  3444. g_ctx.backend->vtable->destroy (g_ctx.backend);
  3445. g_ctx.input->vtable->destroy (g_ctx.input);
  3446. iconv_close (g_ctx.term_from_utf8);
  3447. iconv_close (g_ctx.term_to_utf8);
  3448. str_map_free (&g_ctx.methods);
  3449. config_free (&g_ctx.config);
  3450. free_terminal ();
  3451. ev_loop_destroy (EV_DEFAULT);
  3452. return EXIT_SUCCESS;
  3453. }