src/server/safs/cgi.c

changeset 516
ec22d4ccd081
parent 503
aeaf7db26fac
child 517
be62c9604377
equal deleted inserted replaced
515:2c3fe06a9210 516:ec22d4ccd081
182 ZERO(writeev, sizeof(Event)); 182 ZERO(writeev, sizeof(Event));
183 writeev->cookie = handler; 183 writeev->cookie = handler;
184 writeev->fn = cgi_writeevent; 184 writeev->fn = cgi_writeevent;
185 writeev->finish = cgi_event_finish; 185 writeev->finish = cgi_event_finish;
186 186
187 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
261 } 261 }
262 memcpy(handler->writebuf, buf+pos, remaining); 262 memcpy(handler->writebuf, buf+pos, remaining);
263 handler->writebuf_size = remaining; 263 handler->writebuf_size = remaining;
264 handler->writebuf_pos = 0; 264 handler->writebuf_pos = 0;
265 265
266 /*
266 // initialize poll, if it isn't already active 267 // initialize poll, if it isn't already active
267 if(!handler->poll_out) { 268 if(!handler->poll_out) {
268 if(event_pollout(ev, sn->csd, handler->writeev)) { 269 if(event_pollout(ev, sn->csd, handler->writeev)) {
269 handler->result = REQ_ABORTED; 270 handler->result = REQ_ABORTED;
270 return 0; 271 return 0;
271 } 272 }
272 handler->events++; 273 handler->events++;
273 handler->poll_out = TRUE; 274 handler->poll_out = TRUE;
274 } 275 }
276 */
275 } else { 277 } else {
276 handler->result = REQ_ABORTED; 278 handler->result = REQ_ABORTED;
277 log_ereport(LOG_FAILURE, "cgi_try_write: %s", strerror(net_errno(sn->csd))); 279 log_ereport(LOG_FAILURE, "cgi_try_write: %s", strerror(net_errno(sn->csd)));
278 } 280 }
279 return 1; 281 return 1;
283 } 285 }
284 286
285 int cgi_stdout_readevent(EventHandler *ev, Event *event) { 287 int cgi_stdout_readevent(EventHandler *ev, Event *event) {
286 CGIHandler *handler = event->cookie; 288 CGIHandler *handler = event->cookie;
287 289
288 int ret = cgi_read_output(handler, ev); 290 CgiIOResult ret = cgi_read_output(handler, ev);
289 if(ret == 0) { 291 switch(ret) {
290 handler->wait_read = FALSE; 292 case CGI_IO_COMPLETE: {
291 } 293 break;
292 return ret; 294 }
295 case CGI_IO_NEED_READ: {
296 return 1;
297 }
298 case CGI_IO_NEED_WRITE: {
299 if(event_pollout(ev, handler->parser->sn->csd, handler->readev)) {
300 handler->result = REQ_ABORTED;
301 } else {
302 handler->poll_out = TRUE;
303 }
304 break;
305 }
306 case CGI_IO_ERROR: {
307 break;
308 }
309 }
310
311 handler->wait_read = FALSE;
312 return 0;
293 } 313 }
294 314
295 int cgi_writeevent(EventHandler *ev, Event *event) { 315 int cgi_writeevent(EventHandler *ev, Event *event) {
296 CGIHandler *handler = event->cookie; 316 CGIHandler *handler = event->cookie;
297 317
298 // cgi_read_output will try to flush the buffer 318 // cgi_read_output will try to flush the buffer
299 int ret = cgi_read_output(handler, ev); 319 CgiIOResult ret = cgi_read_output(handler, ev);
300 if(ret == 0) { 320 switch(ret) {
301 handler->poll_out = FALSE; 321 case CGI_IO_COMPLETE: {
302 } 322 break;
303 return ret; 323 }
304 } 324 case CGI_IO_NEED_READ: {
305 325 if(ev_pollin(ev, handler->process.out[0], event)) {
306 326 handler->result = REQ_ABORTED;
307 327 } else {
308 int cgi_read_output(CGIHandler *handler, EventHandler *ev) { 328 handler->wait_read = TRUE;
329 }
330 }
331 case CGI_IO_NEED_WRITE: {
332 return 1;
333 }
334 case CGI_IO_ERROR: {
335 break;
336 }
337 }
338
339 handler->poll_out = FALSE;
340 return 0;
341 }
342
343
344
345 CgiIOResult cgi_read_output(CGIHandler *handler, EventHandler *ev) {
309 CGIResponseParser *parser = handler->parser; 346 CGIResponseParser *parser = handler->parser;
310 Session *sn = parser->sn; 347 Session *sn = parser->sn;
311 Request *rq = parser->rq; 348 Request *rq = parser->rq;
312 349
313 // try to flush handler->writebuf 350 // try to flush handler->writebuf
314 // if writebuf is empty, this does nothing and returns 0 351 // if writebuf is empty, this does nothing and returns 0
315 if(cgi_try_write_flush(handler, sn)) { 352 if(cgi_try_write_flush(handler, sn)) {
316 if(handler->result == REQ_ABORTED) { 353 if(handler->result == REQ_ABORTED) {
317 log_ereport(LOG_DEBUG, "cgi-send: req: %p write failed: %s: abort", handler->parser->rq, strerror(net_errno(sn->csd)), rq); 354 log_ereport(LOG_DEBUG, "cgi-send: req: %p write failed: %s: abort", handler->parser->rq, strerror(net_errno(sn->csd)), rq);
318 return 0; 355 return CGI_IO_ERROR;
319 } else { 356 } else {
320 return 1; 357 return CGI_IO_NEED_WRITE;
321 } 358 }
322 } 359 }
323 360
324 char buf[4096]; // I/O buffer 361 char buf[4096]; // I/O buffer
325 ssize_t r; 362 ssize_t r;
326 363
364 int ret = CGI_IO_COMPLETE;
327 handler->result = REQ_PROCEED; 365 handler->result = REQ_PROCEED;
328 while((r = read(handler->process.out[0], buf, 4096)) > 0) { 366 while((r = read(handler->process.out[0], buf, 4096)) > 0) {
329 if(parser->cgiheader) { 367 if(parser->cgiheader) {
330 size_t pos; 368 size_t pos;
331 int ret = cgi_parse_response(parser, buf, r, &pos); 369 int ret = cgi_parse_response(parser, buf, r, &pos);
333 log_ereport( 371 log_ereport(
334 LOG_FAILURE, 372 LOG_FAILURE,
335 "broken cgi script response: path: %s", handler->path); 373 "broken cgi script response: path: %s", handler->path);
336 protocol_status(sn, rq, 500, NULL); 374 protocol_status(sn, rq, 500, NULL);
337 handler->result = REQ_ABORTED; 375 handler->result = REQ_ABORTED;
338 return 0; 376 return CGI_IO_ERROR;
339 } else if(ret == 1) { 377 } else if(ret == 1) {
340 WS_ASSERT(pos <= r); 378 WS_ASSERT(pos <= r);
341 379
342 parser->response_length += r-pos; 380 parser->response_length += r-pos;
343 381
347 } 385 }
348 386
349 handler->response = http_create_response(sn, rq); 387 handler->response = http_create_response(sn, rq);
350 if(!handler->response) { 388 if(!handler->response) {
351 handler->result = REQ_ABORTED; 389 handler->result = REQ_ABORTED;
352 return 0; 390 return CGI_IO_ERROR;
353 } 391 }
354 392
355 int send_response = http_send_response(handler->response); 393 int send_response = http_send_response(handler->response);
356 if(send_response < 0) { 394 if(send_response < 0) {
357 handler->result = REQ_ABORTED; 395 handler->result = REQ_ABORTED;
396 ret = CGI_IO_ERROR;
358 break; 397 break;
359 } else if(send_response == 1) { 398 } else if(send_response == 1) {
360 // EWOULDBLOCK 399 // EWOULDBLOCK
361 if(!handler->poll_out) { 400 if(!handler->poll_out) {
362 if(event_pollout(ev, sn->csd, handler->writeev)) { 401 if(event_pollout(ev, sn->csd, handler->writeev)) {
363 handler->result = REQ_ABORTED; 402 handler->result = REQ_ABORTED;
364 return 0; 403 return CGI_IO_ERROR;
365 } 404 }
366 handler->poll_out = TRUE; 405 handler->poll_out = TRUE;
367 return 1; 406 return CGI_IO_NEED_WRITE;
368 } 407 }
369 } else { 408 } else {
370 handler->response = NULL; 409 handler->response = NULL;
371 } 410 }
372 411
373 if(pos < r) { 412 if(pos < r) {
374 if(cgi_try_write(handler, ev, sn, &buf[pos], r-pos)) { 413 if(cgi_try_write(handler, ev, sn, &buf[pos], r-pos)) {
375 return handler->result == REQ_ABORTED ? 0 : 1; 414 return handler->result == REQ_ABORTED ? CGI_IO_ERROR : CGI_IO_NEED_WRITE;
376 } 415 }
377 } 416 }
378 } 417 }
379 } else { 418 } else {
380 parser->response_length += r; 419 parser->response_length += r;
381 if(cgi_try_write(handler, ev, sn, buf, r)) { 420 if(cgi_try_write(handler, ev, sn, buf, r)) {
382 return handler->result == REQ_ABORTED ? 0 : 1; 421 return handler->result == REQ_ABORTED ? CGI_IO_ERROR : CGI_IO_NEED_WRITE;
383 } 422 }
384 } 423 }
385 } 424 }
386 if(r < 0 && errno == EWOULDBLOCK) { 425 if(r < 0 && errno == EWOULDBLOCK) {
387 return 1; 426 return CGI_IO_NEED_READ;
388 } 427 }
389 handler->cgi_eof = TRUE; 428 handler->cgi_eof = TRUE;
390 return 0; 429 return ret;
391 } 430 }
392 431
393 int cgi_stderr_readevent(EventHandler *ev, Event *event) { 432 int cgi_stderr_readevent(EventHandler *ev, Event *event) {
394 CGIHandler *handler = event->cookie; 433 CGIHandler *handler = event->cookie;
395 pool_handle_t *pool = handler->parser->sn->pool; 434 pool_handle_t *pool = handler->parser->sn->pool;

mercurial