/* WebROaR - Ruby Application Server - http://webroar.in/
* Copyright (C) 2009 Goonj LLC
*
* This file is part of WebROaR.
*
* WebROaR is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* WebROaR is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with WebROaR. If not, see .
*/
#include
#include
extern config_t *Config;
http_resp_t* http_resp_new() {
LOG_FUNCTION
http_resp_t *rsp = wr_malloc(http_resp_t);
if (rsp == NULL) {
return NULL;
}
wr_buffer_new(rsp->resp_body);
wr_string_null(rsp->header);
rsp->bytes_write = 0;
rsp->resp_code = 0;
rsp->scgi = NULL;
#ifdef _POSIX_C_SOURCE
rsp->file = 0;
#else
rsp->file = NULL;
#endif
return rsp;
}
void http_resp_free(http_resp_t **r) {
LOG_FUNCTION
http_resp_t *rsp = *r;
if (rsp) {
wr_buffer_free(rsp->resp_body);
wr_string_free(rsp->header);
if (rsp->scgi)
scgi_free(rsp->scgi);
if (rsp->file) {
#ifdef _POSIX_C_SOURCE
close(rsp->file);
#else
fclose(rsp->file);
rsp->file = NULL;
#endif
}
free(rsp);
}
*r = NULL;
}
void http_resp_set(http_resp_t *rsp) {
LOG_FUNCTION
rsp->bytes_write = 0;
rsp->resp_code = 0;
wr_buffer_null(rsp->resp_body);
wr_string_free(rsp->header);
if (rsp->scgi)
scgi_free(rsp->scgi);
if (rsp->file) {
#ifdef _POSIX_C_SOURCE
close(rsp->file);
#else
fclose(rsp->file);
rsp->file = NULL;
#endif
}
rsp->scgi = NULL;
}
int http_resp_process(http_resp_t *rsp) {
LOG_FUNCTION
rsp->scgi = scgi_new();
if (rsp->scgi == NULL) {
return -1;
}
char str[16];
size_t len;
len = sprintf(str, "%d", rsp->resp_code);
scgi_header_add(rsp->scgi, Config->Worker.Header.resp_code.str, Config->Worker.Header.resp_code.len, str, len);
len = sprintf(str, "%d", rsp->resp_body->len);
scgi_header_add(rsp->scgi, Config->Worker.Header.resp_content_len.str, Config->Worker.Header.resp_content_len.len, str, len);
scgi_content_length_add(rsp->scgi, rsp->resp_body->len + rsp->header.len);
scgi_build(rsp->scgi);
return 0;
}
void http_resp_file_write_cb(struct ev_loop* loop, struct ev_io* watcher, int revent) {
LOG_FUNCTION
wkr_t *w = (wkr_t*) watcher->data;
LOG_DEBUG(DEBUG, "http_resp_file_write_cb() conn id=%d, Request id=%d",
w->http->conn_id, w->http->req_id);
if (revent & EV_WRITE) {
#ifndef _POSIX_C_SOURCE
http_resp_t *rsp = w->http->resp;
ssize_t sent;
if (rsp->file) {
char buffer[Config->Worker.max_body_size];
ssize_t read;
int rv = fseek(rsp->file, rsp->bytes_write, SEEK_SET);
if (rv < 0) {
LOG_ERROR(WARN, "Error reading file:%s", strerror(errno));
return;
}
read = fread(buffer, 1, Config->Worker.max_body_size, rsp->file);
sent = send(watcher->fd, buffer, read, 0);
}
if (sent < 0) {
ev_io_stop(loop, watcher);
LOG_ERROR(WARN, "Error sending response:%s,errno=%d", strerror(errno), errno);
// errno 32 = Broken Pipe.
if (errno == 32)
sigproc();
return;
}
rsp->bytes_write += sent;
LOG_DEBUG(DEBUG, "http_resp_file_write_cb() bytes write = %d, sent = %d", rsp->bytes_write, sent);
if (rsp->bytes_write >= rsp->resp_body->len) {
ev_io_stop(loop, watcher);
http_resp_set(rsp);
LOG_DEBUG(DEBUG, "http_resp_file_write_cb() starting read watcher.");
ev_io_init(watcher, http_req_header_cb, w->req_fd, EV_READ);
ev_io_start(loop, watcher);
}
#endif
}
}
void http_resp_body_write_cb(struct ev_loop* loop, struct ev_io* watcher, int revent) {
LOG_FUNCTION
wkr_t *w = (wkr_t*) watcher->data;
http_resp_t *rsp = w->http->resp;
ssize_t sent;
LOG_DEBUG(DEBUG, "http_resp_body_write_cb() conn id=%d, Request id=%d",
w->http->conn_id, w->http->req_id);
if (revent & EV_WRITE) {
sent = send(watcher->fd,
rsp->resp_body->str + rsp->bytes_write,
rsp->resp_body->len - rsp->bytes_write,
0);
if (sent < 0) {
ev_io_stop(loop, watcher);
LOG_ERROR(WARN, "Error sending response:%s,errno=%d", strerror(errno), errno);
// errno 32 = Broken Pipe.
if (errno == 32)
sigproc();
return;
}
rsp->bytes_write += sent;
LOG_DEBUG(DEBUG, "http_resp_body_write_cb() bytes write = %d, sent = %d", rsp->bytes_write, sent);
if (rsp->bytes_write >= rsp->resp_body->len) {
ev_io_stop(loop, watcher);
http_resp_set(rsp);
LOG_DEBUG(DEBUG, "http_resp_body_write_cb() starting read watcher.");
ev_io_init(watcher, http_req_header_cb, w->req_fd, EV_READ);
ev_io_start(loop, watcher);
}
}
}
void http_resp_file_send_cb(struct ev_loop* loop, struct ev_io* watcher, int revent) {
LOG_FUNCTION
wkr_t *w = (wkr_t*) watcher->data;
http_resp_t *rsp = w->http->resp;
#ifdef _POSIX_C_SOURCE
long int rv = sendfile(watcher->fd, rsp->file, &rsp->bytes_write, rsp->resp_body->len - rsp->bytes_write);
if (rv == -1) {
LOG_ERROR(SEVERE, "error from sendfile: %s\n", strerror(errno));
return;
}
#else
char buffer[Config->Worker.max_body_size];
ssize_t read, sent;
int rv = fseek(rsp->file, rsp->bytes_write, SEEK_SET);
if(rv < 0) {
LOG_ERROR(WARN,"Error reading file:%s",strerror(errno));
return;
}
read = fread(buffer, 1, Config->Worker.max_body_size, rsp->file);
sent = send(watcher->fd, buffer, read, 0);
if (sent < 0) {
LOG_ERROR(SEVERE, "error in file sending: %s\n", strerror(errno));
return;
}
rsp->bytes_write += sent;
#endif
LOG_DEBUG(DEBUG, "http_resp_body_write_cb() bytes wrire = %d, file size = %d",
rsp->bytes_write, rsp->resp_body->len);
if (rsp->bytes_write >= rsp->resp_body->len) {
ev_io_stop(w->loop, &w->w_req);
http_resp_set(rsp);
LOG_DEBUG(DEBUG, "http_resp_body_write_cb() starting read watcher.");
ev_io_init(watcher, http_req_header_cb, w->req_fd, EV_READ);
ev_io_start(loop, watcher);
}
}
void http_resp_header_write_cb(struct ev_loop* loop, struct ev_io* watcher, int revent) {
LOG_FUNCTION;
wkr_t *w = (wkr_t*) watcher->data;
http_resp_t *rsp = w->http->resp;
ssize_t sent;
LOG_DEBUG(DEBUG, "http_resp_header_write_cb() conn id=%d, Request id=%d",
w->http->conn_id, w->http->req_id);
if (revent & EV_WRITE) {
sent = send(watcher->fd,
rsp->header.str + rsp->bytes_write,
rsp->header.len - rsp->bytes_write,
0);
if (sent < 0) {
ev_io_stop(loop, watcher);
LOG_ERROR(WARN, "Error sending response:%s,errno=%d", strerror(errno), errno);
// errno 32 = Broken Pipe.
if (errno == 32)
sigproc();
return;
}
rsp->bytes_write += sent;
LOG_DEBUG(DEBUG, "http_resp_header_write_cb() bytes write = %d, sent = %d", rsp->bytes_write, sent);
if (rsp->bytes_write >= rsp->header.len) {
ev_io_stop(loop, watcher);
LOG_DEBUG(DEBUG, "http_resp_header_write_cb() starting read watcher. bytes write=%d", rsp->bytes_write);
if (rsp->resp_body->len > 0) {
rsp->bytes_write = 0;
if (w->http->stat && w->http->resp->resp_code == 200 &&
rsp->resp_body->str == NULL) {
ev_io_init(watcher, http_resp_file_send_cb, w->req_fd, EV_WRITE);
//send_file(w);
//ev_io_init(watcher, http_resp_file_write_cb, w->req_fd, EV_WRITE);
}else {
ev_io_init(watcher, http_resp_body_write_cb, w->req_fd, EV_WRITE);
}
ev_io_start(loop, watcher);
} else {
http_resp_set(rsp);
LOG_DEBUG(DEBUG, "http_resp_body_write_cb() starting read watcher");
ev_io_init(watcher, http_req_header_cb, w->req_fd, EV_READ);
ev_io_start(loop, watcher);
}
}
}
}
void http_resp_scgi_write_cb(struct ev_loop* loop, struct ev_io* watcher, int revent) {
LOG_FUNCTION
wkr_t *w = (wkr_t*) watcher->data;
http_resp_t *rsp = w->http->resp;
LOG_DEBUG(DEBUG, "http_resp_scgi_write_cb() conn id=%d, Request id=%d",
w->http->conn_id, w->http->req_id);
if (revent & EV_WRITE) {
if (scgi_send(rsp->scgi, watcher->fd) <= 0) {
ev_io_stop(loop, watcher);
LOG_ERROR(WARN, "Error sending response:%s,errno=%d", strerror(errno), errno);
// errno 32 = Broken Pipe.
if (errno == 32)
sigproc();
return;
}
LOG_DEBUG(DEBUG, "http_resp_scgi_write_cb() bytes write = %d, sent = %d", rsp->scgi->length, rsp->scgi->bytes_sent);
if (rsp->scgi->bytes_sent >= rsp->scgi->length) {
ev_io_stop(loop, watcher);
LOG_DEBUG(DEBUG, "http_resp_scgi_write_cb() starting read watcher. bytes write=%d", rsp->bytes_write);
rsp->bytes_write = 0;
ev_io_init(watcher, http_resp_header_write_cb, w->req_fd, EV_WRITE);
ev_io_start(loop, watcher);
}
}
}