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.cc
30  */
31 
32 #include "config.h"
33 
34 #ifdef HAVE_LIBCURL
35 #include <curl/curl.h>
36 
37 #include "papertrail_proc.hh"
38 #include "yajlpp/yajlpp_def.hh"
39 #include "yajl/api/yajl_parse.h"
40 
41 const char *papertrail_proc::PT_SEARCH_URL =
42         "https://papertrailapp.com/api/v1/events/search.json?min_id=%s&";
43 
read_max_id(yajlpp_parse_context * ypc,const unsigned char * str,size_t len)44 static int read_max_id(yajlpp_parse_context *ypc, const unsigned char *str, size_t len)
45 {
46     papertrail_proc *ptp = (papertrail_proc *) ypc->ypc_userdata;
47 
48     ptp->ptp_last_max_id = std::string((const char *) str, len);
49 
50     return 1;
51 }
52 
read_partial(yajlpp_parse_context * ypc,int val)53 static int read_partial(yajlpp_parse_context *ypc, int val)
54 {
55     papertrail_proc *ptp = (papertrail_proc *) ypc->ypc_userdata;
56 
57     if (val) {
58         ptp->ptp_partial_read = true;
59     }
60 
61     return 1;
62 }
63 
read_limit(yajlpp_parse_context * ypc,int val)64 static int read_limit(yajlpp_parse_context *ypc, int val)
65 {
66     papertrail_proc *ptp = (papertrail_proc *) ypc->ypc_userdata;
67 
68     if (val) {
69         ptp->ptp_partial_read = true;
70     }
71 
72     return 1;
73 }
74 
ignore_bool(yajlpp_parse_context * ypc,int val)75 static int ignore_bool(yajlpp_parse_context *ypc, int val)
76 {
77     return 1;
78 }
79 
ignore_str(yajlpp_parse_context * ypc,const unsigned char * str,size_t len)80 static int ignore_str(yajlpp_parse_context *ypc, const unsigned char *str, size_t len)
81 {
82     return 1;
83 }
84 
read_event_int(yajlpp_parse_context * ypc,long long val)85 static int read_event_int(yajlpp_parse_context *ypc, long long val)
86 {
87     papertrail_proc *ptp = (papertrail_proc *) ypc->ypc_userdata;
88 
89     yajl_gen_string(ptp->ptp_gen, ypc->get_path_fragment(2));
90     yajl_gen_integer(ptp->ptp_gen, val);
91 
92     return 1;
93 }
94 
read_event_field(yajlpp_parse_context * ypc,const unsigned char * str,size_t len)95 static int read_event_field(yajlpp_parse_context *ypc, const unsigned char *str, size_t len)
96 {
97     papertrail_proc *ptp = (papertrail_proc *) ypc->ypc_userdata;
98 
99     yajl_gen_string(ptp->ptp_gen, ypc->get_path_fragment(2));
100     yajl_gen_string(ptp->ptp_gen, str, len);
101 
102     return 1;
103 }
104 
json_map_start(void * ctx)105 int papertrail_proc::json_map_start(void *ctx)
106 {
107     yajlpp_parse_context *ypc = (yajlpp_parse_context *)ctx;
108     papertrail_proc *ptp = (papertrail_proc *) ypc->ypc_userdata;
109 
110     if (ypc->ypc_path_index_stack.size() == 3) {
111         yajl_gen_map_open(ptp->ptp_gen);
112     }
113 
114     return 1;
115 }
116 
json_map_end(void * ctx)117 int papertrail_proc::json_map_end(void *ctx)
118 {
119     yajlpp_parse_context *ypc = (yajlpp_parse_context *)ctx;
120     papertrail_proc *ptp = (papertrail_proc *) ypc->ypc_userdata;
121 
122     if (ypc->ypc_path_index_stack.size() == 2) {
123         yajl_gen_map_close(ptp->ptp_gen);
124         yajl_gen_reset(ptp->ptp_gen, "\n");
125     }
126 
127     return 1;
128 }
129 
130 struct json_path_container papertrail_proc::FORMAT_HANDLERS = json_path_container {
131         json_path_handler("/max_id", read_max_id),
132         json_path_handler("/(partial_results)", read_partial),
133         json_path_handler("/(reached_record_limit|reached_time_limit)", read_limit),
134         json_path_handler("/(min_id|min_time_at|max_time_at|"
135                                   "reached_beginning|reached_end|tail|no_events)")
136                 .add_cb(ignore_bool)
137                 .add_cb(ignore_str),
138         json_path_handler("/events#/\\w+")
139                 .add_cb(read_event_field)
140                 .add_cb(read_event_int)
141 };
142 
write_cb(void * contents,size_t size,size_t nmemb,void * userp)143 size_t papertrail_proc::write_cb(void *contents, size_t size, size_t nmemb, void *userp)
144 {
145     yajl_handle handle = (yajl_handle) userp;
146     size_t realsize = size * nmemb;
147 
148     if (yajl_parse(handle, (const unsigned char *)contents, realsize) != yajl_status_ok) {
149         return -1;
150     }
151 
152     return realsize;
153 }
154 
yajl_writer(void * context,const char * str,size_t len)155 void papertrail_proc::yajl_writer(void *context, const char *str, size_t len)
156 {
157     papertrail_proc *ptp = (papertrail_proc *) context;
158 
159     write(ptp->ptp_fd, str, len);
160 }
161 
complete(CURLcode result)162 long papertrail_proc::complete(CURLcode result)
163 {
164     curl_request::complete(result);
165 
166     yajl_reset(this->ptp_jhandle.in());
167 
168     if (result != CURLE_OK) {
169         static const char *err_msg = "Unable to execute papertrail search -- ";
170 
171         write(this->ptp_fd, err_msg, strlen(err_msg));
172         write(this->ptp_fd, this->cr_error_buffer, strlen(this->cr_error_buffer));
173         return -1;
174     }
175 
176     if (this->ptp_max_time) {
177         return -1;
178     }
179 
180     this->set_url();
181     if (this->ptp_partial_read) {
182         this->ptp_partial_read = false;
183         return 1;
184     }
185 
186     return 3000;
187 }
188 
189 #endif
190