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