log2journal-pcre2.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "log2journal.h"
  3. #define PCRE2_ERROR_LINE_MAX 1024
  4. #define PCRE2_KEY_MAX 1024
  5. struct pcre2_state {
  6. LOG_JOB *jb;
  7. const char *line;
  8. uint32_t pos;
  9. uint32_t key_start;
  10. pcre2_code *re;
  11. pcre2_match_data *match_data;
  12. char key[PCRE2_KEY_MAX];
  13. char msg[PCRE2_ERROR_LINE_MAX];
  14. };
  15. static inline void copy_and_convert_key(PCRE2_STATE *pcre2, const char *key) {
  16. char *d = &pcre2->key[pcre2->key_start];
  17. size_t remaining = sizeof(pcre2->key) - pcre2->key_start;
  18. while(remaining >= 2 && *key) {
  19. *d = journal_key_characters_map[(unsigned) (*key)];
  20. remaining--;
  21. key++;
  22. d++;
  23. }
  24. *d = '\0';
  25. }
  26. static inline void jb_traverse_pcre2_named_groups_and_send_keys(PCRE2_STATE *pcre2, pcre2_code *re, pcre2_match_data *match_data, char *line) {
  27. PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(match_data);
  28. uint32_t names_count;
  29. pcre2_pattern_info(re, PCRE2_INFO_NAMECOUNT, &names_count);
  30. if (names_count > 0) {
  31. PCRE2_SPTR name_table;
  32. pcre2_pattern_info(re, PCRE2_INFO_NAMETABLE, &name_table);
  33. uint32_t name_entry_size;
  34. pcre2_pattern_info(re, PCRE2_INFO_NAMEENTRYSIZE, &name_entry_size);
  35. const unsigned char *table_ptr = name_table;
  36. for (uint32_t i = 0; i < names_count; i++) {
  37. int n = (table_ptr[0] << 8) | table_ptr[1];
  38. const char *group_name = (const char *)(table_ptr + 2);
  39. PCRE2_SIZE start_offset = ovector[2 * n];
  40. PCRE2_SIZE end_offset = ovector[2 * n + 1];
  41. PCRE2_SIZE group_length = end_offset - start_offset;
  42. copy_and_convert_key(pcre2, group_name);
  43. log_job_send_extracted_key_value(pcre2->jb, pcre2->key, line + start_offset, group_length);
  44. table_ptr += name_entry_size;
  45. }
  46. }
  47. }
  48. void pcre2_get_error_in_buffer(char *msg, size_t msg_len, int rc, int pos) {
  49. int l;
  50. if(pos >= 0)
  51. l = snprintf(msg, msg_len, "PCRE2 error %d at pos %d on: ", rc, pos);
  52. else
  53. l = snprintf(msg, msg_len, "PCRE2 error %d on: ", rc);
  54. pcre2_get_error_message(rc, (PCRE2_UCHAR *)&msg[l], msg_len - l);
  55. }
  56. static void pcre2_error_message(PCRE2_STATE *pcre2, int rc, int pos) {
  57. pcre2_get_error_in_buffer(pcre2->msg, sizeof(pcre2->msg), rc, pos);
  58. }
  59. bool pcre2_has_error(PCRE2_STATE *pcre2) {
  60. return !pcre2->re || pcre2->msg[0];
  61. }
  62. PCRE2_STATE *pcre2_parser_create(LOG_JOB *jb) {
  63. PCRE2_STATE *pcre2 = mallocz(sizeof(PCRE2_STATE));
  64. memset(pcre2, 0, sizeof(PCRE2_STATE));
  65. pcre2->jb = jb;
  66. if(jb->prefix)
  67. pcre2->key_start = copy_to_buffer(pcre2->key, sizeof(pcre2->key), pcre2->jb->prefix, strlen(pcre2->jb->prefix));
  68. int rc;
  69. PCRE2_SIZE pos;
  70. pcre2->re = pcre2_compile((PCRE2_SPTR)jb->pattern, PCRE2_ZERO_TERMINATED, 0, &rc, &pos, NULL);
  71. if (!pcre2->re) {
  72. pcre2_error_message(pcre2, rc, pos);
  73. return pcre2;
  74. }
  75. pcre2->match_data = pcre2_match_data_create_from_pattern(pcre2->re, NULL);
  76. return pcre2;
  77. }
  78. void pcre2_parser_destroy(PCRE2_STATE *pcre2) {
  79. if(pcre2)
  80. freez(pcre2);
  81. }
  82. const char *pcre2_parser_error(PCRE2_STATE *pcre2) {
  83. return pcre2->msg;
  84. }
  85. bool pcre2_parse_document(PCRE2_STATE *pcre2, const char *txt, size_t len) {
  86. pcre2->line = txt;
  87. pcre2->pos = 0;
  88. pcre2->msg[0] = '\0';
  89. if(!len)
  90. len = strlen(txt);
  91. int rc = pcre2_match(pcre2->re, (PCRE2_SPTR)pcre2->line, len, 0, 0, pcre2->match_data, NULL);
  92. if(rc < 0) {
  93. pcre2_error_message(pcre2, rc, -1);
  94. return false;
  95. }
  96. jb_traverse_pcre2_named_groups_and_send_keys(pcre2, pcre2->re, pcre2->match_data, (char *)pcre2->line);
  97. return true;
  98. }
  99. void pcre2_test(void) {
  100. LOG_JOB jb = { .prefix = "NIGNX_" };
  101. PCRE2_STATE *pcre2 = pcre2_parser_create(&jb);
  102. pcre2_parse_document(pcre2, "{\"value\":\"\\u\\u039A\\u03B1\\u03BB\\u03B7\\u03BC\\u03AD\\u03C1\\u03B1\"}", 0);
  103. pcre2_parser_destroy(pcre2);
  104. }