55 int send_cgi(pblock *pb, Session *sn, Request *rq) { |
55 int send_cgi(pblock *pb, Session *sn, Request *rq) { |
56 char *path = pblock_findkeyval(pb_key_path, rq->vars); |
56 char *path = pblock_findkeyval(pb_key_path, rq->vars); |
57 char *ctlen = pblock_findkeyval(pb_key_content_length, rq->headers); |
57 char *ctlen = pblock_findkeyval(pb_key_content_length, rq->headers); |
58 int64_t content_length = 0; |
58 int64_t content_length = 0; |
59 |
59 |
60 log_ereport(LOG_DEBUG, "cgi-send: path: %s content-length: %s", path, ctlen); |
60 log_ereport(LOG_DEBUG, "cgi-send: path: %s req: %p content-length: %s", path, rq, ctlen); |
61 |
61 |
62 if(ctlen) { |
62 if(ctlen) { |
63 if(!util_strtoint(ctlen, &content_length)) { |
63 if(!util_strtoint(ctlen, &content_length)) { |
64 log_ereport( |
64 log_ereport( |
65 LOG_FAILURE, |
65 LOG_FAILURE, |
187 handler->readev = readev; |
187 handler->readev = readev; |
188 handler->writeev = writeev; |
188 handler->writeev = writeev; |
189 |
189 |
190 net_setnonblock(sn->csd, 1); |
190 net_setnonblock(sn->csd, 1); |
191 |
191 |
192 // add poll events for cgi stdout/stderr |
192 // add poll events for cgi stdout/stderr and netout |
193 int error = 0; |
193 int error = 0; |
194 if(ev_pollin(sn->ev, handler->process.err[0], stderr_readev)) { |
194 if(ev_pollin(sn->ev, handler->process.err[0], stderr_readev)) { |
195 log_ereport(LOG_FAILURE, "send-cgi: stderr ev_pollin failed"); |
195 log_ereport(LOG_FAILURE, "send-cgi: stderr ev_pollin failed"); |
196 error = 1; |
196 error = 1; |
197 } |
197 } else { |
198 if(ev_pollin(sn->ev, handler->process.out[0], readev)) { |
198 handler->wait_read = TRUE; |
|
199 handler->events++; |
|
200 } |
|
201 if(!error && ev_pollin(sn->ev, handler->process.out[0], readev)) { |
199 log_ereport(LOG_FAILURE, "send-cgi: stdout ev_pollin failed"); |
202 log_ereport(LOG_FAILURE, "send-cgi: stdout ev_pollin failed"); |
200 error = 1; |
203 error = 1; |
201 } |
204 } else { |
202 |
205 handler->events++; |
203 handler->wait_read = TRUE; |
206 } |
204 handler->events = 2; // 2 events (stdout, stderr) |
207 |
|
208 // don't poll sn->csd yet, we wait until the first net_write fails |
205 |
209 |
206 if(error) { |
210 if(error) { |
207 log_ereport(LOG_FAILURE, "cgi-send: kill script: %s", path); |
211 log_ereport(LOG_FAILURE, "cgi-send: initialization error: kill script: %s", path); |
208 kill(handler->process.pid, SIGKILL); |
212 kill(handler->process.pid, SIGKILL); |
209 cgi_parser_free(handler->parser); |
213 cgi_parser_free(handler->parser); |
210 cgi_close(&handler->process); |
214 cgi_close(&handler->process); |
211 return REQ_ABORTED; |
215 return REQ_ABORTED; |
212 } |
216 } |
213 |
217 |
214 return REQ_PROCESSING; |
218 return REQ_PROCESSING; |
215 } |
219 } |
216 |
220 |
|
221 /* |
|
222 * Try to flush the CGIHandler write buffer |
|
223 * |
|
224 * When successful, cgi_try_write_flush() returns 0. If an error occurs, |
|
225 * 1 is returned. |
|
226 * |
|
227 * If the error is not EWOULDBLOCK, handler->result is set to REQ_ABORTED. |
|
228 */ |
217 static int cgi_try_write_flush(CGIHandler *handler, Session *sn) { |
229 static int cgi_try_write_flush(CGIHandler *handler, Session *sn) { |
218 ssize_t wr = 0; |
230 ssize_t wr = 0; |
219 while( |
231 while( |
220 handler->writebuf_size - handler->writebuf_pos > 0 && |
232 handler->writebuf_size - handler->writebuf_pos > 0 && |
221 (wr = net_write( |
233 (wr = net_write( |
228 handler->count_write += wr; |
240 handler->count_write += wr; |
229 } |
241 } |
230 if(handler->writebuf_size - handler->writebuf_pos > 0) { |
242 if(handler->writebuf_size - handler->writebuf_pos > 0) { |
231 if(net_errno(sn->csd) != EWOULDBLOCK) { |
243 if(net_errno(sn->csd) != EWOULDBLOCK) { |
232 handler->result = REQ_ABORTED; |
244 handler->result = REQ_ABORTED; |
|
245 log_ereport( |
|
246 LOG_FAILURE, |
|
247 "cgi pid %d %s: network error: %s", |
|
248 (int)handler->process.pid, |
|
249 handler->path, |
|
250 strerror(net_errno(sn->csd))); |
233 } |
251 } |
234 |
252 |
235 return 1; |
253 return 1; |
236 } |
254 } |
237 return 0; |
255 return 0; |
238 } |
256 } |
239 |
257 |
|
258 /* |
|
259 * Try to write the buffer to sn->csd |
|
260 * In case the socket is non-blocking and not all bytes could be written, |
|
261 * the remaining bytes are copied to the CGIHandler write buffer. |
|
262 * |
|
263 * If an error occurs that is not EWOULDBLOCK, handler->result is set to |
|
264 * REQ_ABORTED. |
|
265 * |
|
266 * Returns 0 if all bytes are successfully written, otherwise 1 |
|
267 */ |
240 static int cgi_try_write(CGIHandler *handler, EventHandler *ev, Session *sn, char *buf, size_t size) { |
268 static int cgi_try_write(CGIHandler *handler, EventHandler *ev, Session *sn, char *buf, size_t size) { |
241 |
269 |
242 size_t pos = 0; |
270 size_t pos = 0; |
243 ssize_t wr = 0; |
271 ssize_t wr = 0; |
244 while(size - pos > 0 && (wr = net_write(sn->csd, buf + pos, size - pos)) > 0) { |
272 while(size - pos > 0 && (wr = net_write(sn->csd, buf + pos, size - pos)) > 0) { |
260 } |
288 } |
261 } |
289 } |
262 memcpy(handler->writebuf, buf+pos, remaining); |
290 memcpy(handler->writebuf, buf+pos, remaining); |
263 handler->writebuf_size = remaining; |
291 handler->writebuf_size = remaining; |
264 handler->writebuf_pos = 0; |
292 handler->writebuf_pos = 0; |
265 |
|
266 /* |
|
267 // initialize poll, if it isn't already active |
|
268 if(!handler->poll_out) { |
|
269 if(event_pollout(ev, sn->csd, handler->writeev)) { |
|
270 handler->result = REQ_ABORTED; |
|
271 return 0; |
|
272 } |
|
273 handler->events++; |
|
274 handler->poll_out = TRUE; |
|
275 } |
|
276 */ |
|
277 } else { |
293 } else { |
278 handler->result = REQ_ABORTED; |
294 handler->result = REQ_ABORTED; |
279 log_ereport(LOG_FAILURE, "cgi_try_write: %s", strerror(net_errno(sn->csd))); |
295 log_ereport( |
|
296 LOG_FAILURE, |
|
297 "cgi pid %d %s: network error: %s", |
|
298 (int)handler->process.pid, |
|
299 handler->path, |
|
300 strerror(net_errno(sn->csd))); |
280 } |
301 } |
281 return 1; |
302 return 1; |
282 } |
303 } |
283 |
304 |
284 return 0; |
305 return 0; |
285 } |
306 } |
286 |
307 |
287 int cgi_stdout_readevent(EventHandler *ev, Event *event) { |
308 int cgi_stdout_readevent(EventHandler *ev, Event *event) { |
288 CGIHandler *handler = event->cookie; |
309 CGIHandler *handler = event->cookie; |
289 |
310 |
|
311 event->finish = cgi_event_finish; |
|
312 handler->writeev->finish = NULL; |
290 CgiIOResult ret = cgi_read_output(handler, ev); |
313 CgiIOResult ret = cgi_read_output(handler, ev); |
291 switch(ret) { |
314 switch(ret) { |
292 case CGI_IO_COMPLETE: { |
315 case CGI_IO_COMPLETE: { |
293 break; |
316 break; |
294 } |
317 } |
295 case CGI_IO_NEED_READ: { |
318 case CGI_IO_NEED_READ: { |
296 return 1; |
319 return 1; |
297 } |
320 } |
298 case CGI_IO_NEED_WRITE: { |
321 case CGI_IO_NEED_WRITE: { |
299 if(event_pollout(ev, handler->parser->sn->csd, handler->readev)) { |
322 // writeev is only enabled, if needed |
|
323 if(event_pollout(ev, handler->parser->sn->csd, handler->writeev)) { |
300 handler->result = REQ_ABORTED; |
324 handler->result = REQ_ABORTED; |
301 } else { |
325 } else { |
302 handler->poll_out = TRUE; |
326 handler->poll_out = TRUE; |
303 } |
327 log_ereport(LOG_DEBUG, "cgi-send: req: %p enable poll out", handler->parser->rq); |
304 break; |
328 return 1; // keep readevent active |
|
329 } |
305 } |
330 } |
306 case CGI_IO_ERROR: { |
331 case CGI_IO_ERROR: { |
307 break; |
332 break; |
308 } |
333 } |
309 } |
334 } |
313 } |
338 } |
314 |
339 |
315 int cgi_writeevent(EventHandler *ev, Event *event) { |
340 int cgi_writeevent(EventHandler *ev, Event *event) { |
316 CGIHandler *handler = event->cookie; |
341 CGIHandler *handler = event->cookie; |
317 |
342 |
318 // cgi_read_output will try to flush the buffer |
343 event->finish = cgi_event_finish; |
|
344 handler->readev->finish = NULL; |
319 CgiIOResult ret = cgi_read_output(handler, ev); |
345 CgiIOResult ret = cgi_read_output(handler, ev); |
320 switch(ret) { |
346 switch(ret) { |
321 case CGI_IO_COMPLETE: { |
347 case CGI_IO_COMPLETE: { |
322 break; |
348 break; |
323 } |
349 } |
324 case CGI_IO_NEED_READ: { |
350 case CGI_IO_NEED_READ: { |
325 if(ev_pollin(ev, handler->process.out[0], event)) { |
351 return 1; |
326 handler->result = REQ_ABORTED; |
|
327 } else { |
|
328 handler->wait_read = TRUE; |
|
329 } |
|
330 } |
352 } |
331 case CGI_IO_NEED_WRITE: { |
353 case CGI_IO_NEED_WRITE: { |
332 return 1; |
354 return 1; |
333 } |
355 } |
334 case CGI_IO_ERROR: { |
356 case CGI_IO_ERROR: { |
345 CgiIOResult cgi_read_output(CGIHandler *handler, EventHandler *ev) { |
367 CgiIOResult cgi_read_output(CGIHandler *handler, EventHandler *ev) { |
346 CGIResponseParser *parser = handler->parser; |
368 CGIResponseParser *parser = handler->parser; |
347 Session *sn = parser->sn; |
369 Session *sn = parser->sn; |
348 Request *rq = parser->rq; |
370 Request *rq = parser->rq; |
349 |
371 |
|
372 if(handler->result == REQ_ABORTED) { |
|
373 return CGI_IO_ERROR; |
|
374 } |
|
375 |
350 // try to flush handler->writebuf |
376 // try to flush handler->writebuf |
351 // if writebuf is empty, this does nothing and returns 0 |
377 // if writebuf is empty, this does nothing and returns 0 |
352 if(cgi_try_write_flush(handler, sn)) { |
378 if(cgi_try_write_flush(handler, sn)) { |
353 if(handler->result == REQ_ABORTED) { |
379 if(handler->result == REQ_ABORTED) { |
354 log_ereport(LOG_DEBUG, "cgi-send: req: %p write failed: %s: abort", handler->parser->rq, strerror(net_errno(sn->csd)), rq); |
|
355 return CGI_IO_ERROR; |
380 return CGI_IO_ERROR; |
356 } else { |
381 } else { |
357 return CGI_IO_NEED_WRITE; |
382 return CGI_IO_NEED_WRITE; |
358 } |
383 } |
359 } |
384 } |
532 event_fn = "httpout"; |
557 event_fn = "httpout"; |
533 } |
558 } |
534 log_ereport(LOG_DEBUG, "cgi-send: req: %p finish: event: %d pollout: %d cgi_eof: %d fn: %s", rq, handler->events, handler->poll_out, handler->cgi_eof, event_fn); |
559 log_ereport(LOG_DEBUG, "cgi-send: req: %p finish: event: %d pollout: %d cgi_eof: %d fn: %s", rq, handler->events, handler->poll_out, handler->cgi_eof, event_fn); |
535 |
560 |
536 if(--handler->events > 0) { |
561 if(--handler->events > 0) { |
|
562 return 0; |
|
563 } |
|
564 |
|
565 /* |
|
566 if(--handler->events > 0) { |
537 if(handler->events == 1) { |
567 if(handler->events == 1) { |
538 if(handler->poll_out) { |
568 if(handler->poll_out) { |
539 // write event registered, however it will not be activated anymore |
569 // write event registered, however it will not be activated anymore |
540 // we can safely remove the event |
570 // we can safely remove the event |
541 log_ereport(LOG_DEBUG, "cgi-send: req: %p finish: event: 1 remove-poll write", rq); |
571 log_ereport(LOG_DEBUG, "cgi-send: req: %p finish: event: 1 remove-poll write", rq); |
550 } else { |
580 } else { |
551 return 0; |
581 return 0; |
552 } |
582 } |
553 } else { |
583 } else { |
554 return 0; |
584 return 0; |
|
585 } |
|
586 } |
|
587 */ |
|
588 if(handler->poll_out) { |
|
589 // write event registered, however it will not be activated anymore |
|
590 // we can safely remove the event |
|
591 log_ereport(LOG_DEBUG, "cgi-send: req: %p finish: remove-poll write", rq); |
|
592 if(event_removepoll(ev, sn->csd)) { |
|
593 log_ereport(LOG_FAILURE, "cgi_event_finish: event_removepoll: %s", strerror(errno)); |
555 } |
594 } |
556 } |
595 } |
557 |
596 |
558 if(handler->result == REQ_ABORTED && handler->process.pid != 0) { |
597 if(handler->result == REQ_ABORTED && handler->process.pid != 0) { |
559 log_ereport(LOG_FAILURE, "cgi-send: kill script: %s", handler->path); |
598 log_ereport(LOG_FAILURE, "cgi-send: kill script: %s", handler->path); |