src/server/safs/cgi.c

changeset 517
be62c9604377
parent 516
ec22d4ccd081
child 518
538a8a22f622
equal deleted inserted replaced
516:ec22d4ccd081 517:be62c9604377
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);

mercurial