1 /** 2 * Copyright (c) 2015, Timothy Stack 3 * 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * * Redistributions of source code must retain the above copyright notice, this 10 * list of conditions and the following disclaimer. 11 * * Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * * Neither the name of Timothy Stack nor the names of its contributors 15 * may be used to endorse or promote products derived from this software 16 * without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY 19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY 22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 25 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * 29 * @file papertrail_proc.hh 30 */ 31 32 #ifndef LNAV_PAPERTRAIL_PROC_HH 33 #define LNAV_PAPERTRAIL_PROC_HH 34 35 #ifdef HAVE_LIBCURL 36 37 #include <fcntl.h> 38 #include <paths.h> 39 #include <signal.h> 40 #include <unistd.h> 41 #include <sys/wait.h> 42 43 #include <memory> 44 #include <string> 45 46 #include "auto_fd.hh" 47 #include "auto_mem.hh" 48 #include "yajlpp/yajlpp.hh" 49 #include "curl_looper.hh" 50 #include "line_buffer.hh" 51 52 class papertrail_proc : public curl_request { 53 54 public: papertrail_proc(const std::string & search,time_t min_time,time_t max_time)55 papertrail_proc(const std::string &search, 56 time_t min_time, 57 time_t max_time) 58 : curl_request("papertrailapp.com"), 59 ptp_jcontext(this->cr_name, &FORMAT_HANDLERS), 60 ptp_jhandle(yajl_free), 61 ptp_gen(yajl_gen_free), 62 ptp_search(search), 63 ptp_quoted_search(curl_free), 64 ptp_header_list(curl_slist_free_all), 65 ptp_partial_read(false), 66 ptp_min_time(min_time), 67 ptp_max_time(max_time) { 68 char piper_tmpname[PATH_MAX]; 69 const char *tmpdir; 70 71 if ((tmpdir = getenv("TMPDIR")) == NULL) { 72 tmpdir = _PATH_VARTMP; 73 } 74 snprintf(piper_tmpname, sizeof(piper_tmpname), 75 "%s/lnav.pt.XXXXXX", 76 tmpdir); 77 if ((this->ptp_fd = mkstemp(piper_tmpname)) == -1) { 78 return; 79 } 80 81 unlink(piper_tmpname); 82 83 this->ptp_jcontext.ypc_alt_callbacks.yajl_start_map = json_map_start; 84 this->ptp_jcontext.ypc_alt_callbacks.yajl_end_map = json_map_end; 85 this->ptp_jcontext.ypc_userdata = this; 86 this->ptp_jhandle = yajl_alloc(&this->ptp_jcontext.ypc_callbacks, NULL, &this->ptp_jcontext); 87 88 this->ptp_gen = yajl_gen_alloc(NULL); 89 yajl_gen_config(this->ptp_gen, yajl_gen_print_callback, yajl_writer, this); 90 91 curl_easy_setopt(this->cr_handle, CURLOPT_WRITEFUNCTION, write_cb); 92 curl_easy_setopt(this->cr_handle, CURLOPT_WRITEDATA, this->ptp_jhandle.in()); 93 curl_easy_setopt(this->cr_handle, CURLOPT_FAILONERROR, 1L); 94 95 this->ptp_api_key = getenv("PAPERTRAIL_API_TOKEN"); 96 97 if (this->ptp_api_key == NULL) { 98 this->ptp_error = "papertrail search requested, but PAPERTRAIL_API_TOKEN is not set"; 99 } 100 101 this->ptp_quoted_search = curl_easy_escape(this->cr_handle, 102 this->ptp_search.c_str(), 103 this->ptp_search.size()); 104 105 log_perror(asprintf(this->ptp_token_header.out(), 106 "X-Papertrail-Token: %s", 107 this->ptp_api_key)); 108 this->ptp_header_list = curl_slist_append(this->ptp_header_list, 109 this->ptp_token_header.in()); 110 111 curl_easy_setopt(this->cr_handle, CURLOPT_HTTPHEADER, this->ptp_header_list.in()); 112 113 this->set_url(); 114 }; 115 ~papertrail_proc()116 ~papertrail_proc() { 117 } 118 copy_fd() const119 auto_fd copy_fd() const { 120 return this->ptp_fd; 121 }; 122 123 long complete(CURLcode result); 124 set_url()125 void set_url() { 126 char base_url[1024]; 127 128 snprintf(base_url, sizeof(base_url), 129 PT_SEARCH_URL, 130 this->ptp_last_max_id.c_str()); 131 if (this->ptp_min_time) { 132 size_t base_len = strlen(base_url); 133 snprintf(&base_url[base_len], sizeof(base_url) - base_len, 134 "min_time=%ld&", 135 this->ptp_min_time); 136 } 137 if (this->ptp_max_time) { 138 size_t base_len = strlen(base_url); 139 snprintf(&base_url[base_len], sizeof(base_url) - base_len, 140 "max_time=%ld&", 141 this->ptp_max_time); 142 } 143 log_perror(asprintf(this->ptp_url.out(), 144 "%sq=%s", 145 base_url, 146 this->ptp_quoted_search.in())); 147 curl_easy_setopt(this->cr_handle, CURLOPT_URL, this->ptp_url.in()); 148 }; 149 150 static size_t write_cb(void *contents, size_t size, size_t nmemb, void *userp); 151 152 static int json_map_start(void *ctx); 153 static int json_map_end(void *ctx); 154 155 static void yajl_writer(void *context, const char *str, size_t len); 156 static struct json_path_container FORMAT_HANDLERS; 157 static const char *PT_SEARCH_URL; 158 159 yajlpp_parse_context ptp_jcontext; 160 auto_mem<yajl_handle_t> ptp_jhandle; 161 auto_mem<yajl_gen_t> ptp_gen; 162 const char *ptp_api_key; 163 const std::string ptp_search; 164 auto_mem<const char> ptp_quoted_search; 165 auto_mem<char> ptp_url; 166 auto_mem<char> ptp_token_header; 167 auto_mem<struct curl_slist> ptp_header_list; 168 auto_fd ptp_fd; 169 std::string ptp_last_max_id; 170 bool ptp_partial_read; 171 std::string ptp_error; 172 time_t ptp_min_time; 173 time_t ptp_max_time; 174 }; 175 176 #endif 177 178 #endif //LNAV_PAPERTRAIL_PROC_HH 179