141 system_close(handler->process.in[1]); |
141 system_close(handler->process.in[1]); |
142 handler->process.in[1] = -1; |
142 handler->process.in[1] = -1; |
143 |
143 |
144 handler->parser = cgi_parser_new(sn, rq); |
144 handler->parser = cgi_parser_new(sn, rq); |
145 |
145 |
|
146 // set pipes non-blocking |
|
147 int flags; |
|
148 if ((flags = fcntl(handler->process.err[0], F_GETFL, 0)) == -1) { |
|
149 flags = 0; |
|
150 } |
|
151 if (fcntl(handler->process.err[0], F_SETFL, flags | O_NONBLOCK) != 0) { |
|
152 log_ereport(LOG_FAILURE, "cgi-bin: fcntl err[0] failed: %s", strerror(errno)); |
|
153 } |
|
154 if ((flags = fcntl(handler->process.out[0], F_GETFL, 0)) == -1) { |
|
155 flags = 0; |
|
156 } |
|
157 if (fcntl(handler->process.out[0], F_SETFL, flags | O_NONBLOCK) != 0) { |
|
158 log_ereport(LOG_FAILURE, "cgi-bin: fcntl out[0] failed: %s", strerror(errno)); |
|
159 } |
|
160 |
|
161 // create events for reading cgi's stdout/stderr |
146 Event *readev = pool_malloc(sn->pool, sizeof(Event)); |
162 Event *readev = pool_malloc(sn->pool, sizeof(Event)); |
147 ZERO(readev, sizeof(Event)); |
163 ZERO(readev, sizeof(Event)); |
148 readev->cookie = handler; |
164 readev->cookie = handler; |
149 readev->fn = cgi_stdout_readevent; |
165 readev->fn = cgi_stdout_readevent; |
150 readev->finish = cgi_event_finish; |
166 readev->finish = cgi_event_finish; |
159 ZERO(writeev, sizeof(Event)); |
175 ZERO(writeev, sizeof(Event)); |
160 writeev->cookie = handler; |
176 writeev->cookie = handler; |
161 // TODO: fn |
177 // TODO: fn |
162 |
178 |
163 handler->writeev = writeev; |
179 handler->writeev = writeev; |
|
180 handler->stderrev = stderr_readev; |
164 |
181 |
165 // add poll events for cgi stdout/stderr |
182 // add poll events for cgi stdout/stderr |
166 int error = 0; |
183 int error = 0; |
167 if(ev_pollin(sn->ev, handler->process.err[0], stderr_readev)) { |
184 if(ev_pollin(sn->ev, handler->process.err[0], stderr_readev)) { |
168 log_ereport(LOG_FAILURE, "send-cgi: stderr ev_pollin failed"); |
185 log_ereport(LOG_FAILURE, "send-cgi: stderr ev_pollin failed"); |
252 return 0; |
268 return 0; |
253 } |
269 } |
254 |
270 |
255 int cgi_stderr_readevent(EventHandler *ev, Event *event) { |
271 int cgi_stderr_readevent(EventHandler *ev, Event *event) { |
256 CGIHandler *handler = event->cookie; |
272 CGIHandler *handler = event->cookie; |
|
273 pool_handle_t *pool = handler->parser->sn->pool; |
257 |
274 |
258 char buf[4096]; |
275 char buf[4096]; |
259 ssize_t r = read(handler->process.err[0], buf, 4096); |
276 char *line = buf; |
260 log_ereport(LOG_INFORM, "cgi pid %d %s stderr: %.*s", (int)handler->process.pid, handler->path, (int)r, buf); |
277 int line_start = 0; |
261 |
278 ssize_t r; |
|
279 while((r = read(handler->process.err[0], buf, 4096)) > 0) { |
|
280 int pos = 0; |
|
281 // log stderr output lines |
|
282 for(int i=0;i<r;i++) { |
|
283 if(buf[i] == '\n') { |
|
284 log_ereport( |
|
285 LOG_INFORM, |
|
286 "cgi pid %d %s stderr: %.*s%.*s", |
|
287 (int)handler->process.pid, |
|
288 handler->path, |
|
289 (int)handler->stderr_tmplen, |
|
290 handler->stderr_tmp, |
|
291 i - line_start, |
|
292 line + line_start); |
|
293 line_start = i+1; |
|
294 pos = i+1; |
|
295 |
|
296 if(handler->stderr_tmp) { |
|
297 pool_free(pool, handler->stderr_tmp); |
|
298 handler->stderr_tmp = NULL; |
|
299 handler->stderr_tmplen = 0; |
|
300 } |
|
301 } |
|
302 } |
|
303 |
|
304 // check for incomplete line |
|
305 if(pos < r) { |
|
306 int tmplen = r-pos; |
|
307 if(handler->stderr_tmp) { |
|
308 handler->stderr_tmp = pool_realloc(pool, handler->stderr_tmp, handler->stderr_tmplen + tmplen); |
|
309 memcpy(handler->stderr_tmp + handler->stderr_tmplen, line + line_start, tmplen); |
|
310 handler->stderr_tmplen += tmplen; |
|
311 } else { |
|
312 handler->stderr_tmp = pool_malloc(pool, tmplen); |
|
313 memcpy(handler->stderr_tmp, line + line_start, tmplen); |
|
314 handler->stderr_tmplen = tmplen; |
|
315 } |
|
316 } else { |
|
317 pool_free(pool, handler->stderr_tmp); |
|
318 handler->stderr_tmp = NULL; |
|
319 handler->stderr_tmplen = 0; |
|
320 } |
|
321 } |
|
322 |
|
323 |
|
324 if(r < 0 && errno == EWOULDBLOCK) { |
|
325 return 1; |
|
326 } |
|
327 |
|
328 if(handler->stderr_tmp) { |
|
329 pool_free(handler->parser->sn->pool, handler->stderr_tmp); |
|
330 } |
|
331 handler->stderr_finished = TRUE; |
262 return 0; |
332 return 0; |
263 } |
333 } |
264 |
334 |
265 int cgi_event_finish(EventHandler *ev, Event *event) { |
335 int cgi_event_finish(EventHandler *ev, Event *event) { |
266 CGIHandler *handler = event->cookie; |
336 CGIHandler *handler = event->cookie; |
267 CGIResponseParser *parser = handler->parser; |
337 CGIResponseParser *parser = handler->parser; |
268 Session *sn = parser->sn; |
338 Session *sn = parser->sn; |
269 Request *rq = parser->rq; |
339 Request *rq = parser->rq; |
270 |
340 |
271 if(handler->result == REQ_ABORTED) { |
341 if(handler->result == REQ_ABORTED) { |
272 log_ereport(LOG_FAILURE, "cgi-send: kill script: %s", handler->path); |
342 log_ereport(LOG_FAILURE, "cgi-send: kill script: %s", handler->path); |
273 kill(handler->process.pid, SIGKILL); |
343 kill(handler->process.pid, SIGKILL); |
|
344 } |
|
345 |
|
346 if(!handler->stderr_finished) { |
|
347 // stderr handler is still active |
|
348 // set stderr event finish function, to run the finish code later |
|
349 handler->stderrev->finish = cgi_event_finish; |
|
350 return 0; |
274 } |
351 } |
275 |
352 |
276 int exit_code = cgi_close(&handler->process); |
353 int exit_code = cgi_close(&handler->process); |
277 if(exit_code != 0) { |
354 if(exit_code != 0) { |
278 log_ereport(LOG_FAILURE, "send-cgi: script: %s exited with code %d", handler->path, exit_code); |
355 log_ereport(LOG_FAILURE, "send-cgi: script: %s exited with code %d", handler->path, exit_code); |