src/worker/wkr_static.c in webroar-0.4.0 vs src/worker/wkr_static.c in webroar-0.5.0
- old
+ new
@@ -32,23 +32,35 @@
#endif
extern config_t *Config;
#define DEFAULT_EXPIRES "Headers/expires"
-#define EXPIRES_BY_TYPE "Headers/expires_by_type"
-#define EXPIRES_BY_TYPE_EXT "expires_by_type/ext"
-#define EXPIRES_BY_TYPE_EXPIRES "expires_by_type/expires"
+#define EXPIRES_BY_TYPE "Headers/expires_by_type/*"
+#define EXPIRES_BY_TYPE_EXT "ext"
+#define EXPIRES_BY_TYPE_EXPIRES "expires"
#define HTTP_HEADER_IF_MODIFIED_SINCE "HTTP_IF_MODIFIED_SINCE"
#define HTTP_HEADER_CONNECTION "HTTP_CONNECTION"
+#define WR_NO_ENCODING 0
+#define WR_DEFLATE_ENCODING 1
+#define WR_GZIP_ENCODING 2
#define CONNECTION_CLOSE "Close"
#define CONNECTION_KEEP_ALIVE "Keep-Alive"
#define WR_MSG_QUEUE_SERVER_HOST "starling/host"
#define WR_MSG_QUEUE_SERVER_PORT "starling/port"
#define WR_PID_MSG_QUEUE_NAME "starling/pid_queue_name"
+/* from zutil.h */
+#ifndef DEF_MEM_LEVEL
+#if MAX_MEM_LEVEL >= 8
+#define DEF_MEM_LEVEL 8
+#else
+#define DEF_MEM_LEVEL MAX_MEM_LEVEL
+#endif
+#endif
+
typedef enum {
HTTP_STATUS_200 = 0,
HTTP_STATUS_304,
HTTP_STATUS_403,
HTTP_STATUS_404
@@ -211,11 +223,11 @@
}
return HTTP_STATUS_200;
}
long int get_default_expires(node_t *root) {
- char *node_value = get_node_value(root, DEFAULT_EXPIRES);
+ char *node_value = yaml_get_value(root, DEFAULT_EXPIRES);
if (node_value == NULL) {
//return EXPIRES_DURATION;
return 0;
}else if (strcmp(node_value, "off") == 0) {
@@ -239,22 +251,22 @@
if (root == NULL) {
LOG_ERROR(SEVERE, "Could not read the file %s", mapping_file);
return -1;
}
- node = get_nodes(root, "File Extensions");
+ node = yaml_get_node(root, "File Extensions");
if (root == NULL || node->child == NULL) {
LOG_ERROR(SEVERE, "Could not read 'File Extensions' from the file %s", mapping_file);
return -1;
}
node = node->child;
while (node) {
ext = wr_malloc(static_file_t);
- strcpy(ext->ext, node->name);
+ strcpy(ext->ext, node->key);
strcpy(ext->mime_type, node->value);
ext->expires = expires;
int index;
if(ext->ext[0] >= '0' && ext->ext[0] <= '9'){
index = ext->ext[0] - '0';
@@ -271,11 +283,11 @@
LOG_ERROR(WARN, "Mapping index out of bound for extension = %s", ext->ext);
free(ext);
}
node = node->next;
}
- node_free(root);
+ yaml_node_free(root);
// Set default mime type
ext = wr_malloc(static_file_t);
strcpy(ext->ext, "txt");
strcpy(ext->mime_type, "text/plain");
@@ -285,42 +297,150 @@
return 0;
}
void set_expires_by_type(static_server_t *s, node_t *root) {
- node_t *node = get_nodes(root, EXPIRES_BY_TYPE);
+ node_t *node = yaml_get_node(root, EXPIRES_BY_TYPE);
long int expires;
char *types, *expires_str, *type;
while (node) {
- types = get_node_value(node, EXPIRES_BY_TYPE_EXT);
- expires_str = get_node_value(node, EXPIRES_BY_TYPE_EXPIRES);
+ types = yaml_get_value(node->child, EXPIRES_BY_TYPE_EXT);
+ expires_str = yaml_get_value(node->child, EXPIRES_BY_TYPE_EXPIRES);
expires = atol(expires_str);
type = strtok(types, " ,");
while (type != NULL) {
set_expires_time(s, type, expires);
type = strtok(NULL, " ,");
}
- node = NODE_NEXT(node);
+ node = node->next;
}
}
#ifdef W_ZLIB
+int deflate_file_compression(http_t *h) {
+ if(compress2((Bytef*)h->resp->resp_body->str, (uLongf*)&h->resp->resp_body->size,
+ (const Bytef*)h->stat->buffer->str, (uLongf)h->stat->buffer->len, Z_DEFAULT_COMPRESSION) != Z_OK){
+ wr_buffer_null(h->stat->buffer);
+ wr_buffer_null(h->resp->resp_body);
+ return FALSE;
+ } else {
+ h->resp->resp_body->len = h->resp->resp_body->size;
+ return TRUE;
+ }
+}
+
+int gzip_file_compression(http_t *h) {
+ z_stream c_stream;
+ int err;
+
+ c_stream.zalloc = NULL;
+ c_stream.zfree = NULL;
+ c_stream.opaque = NULL;
+ c_stream.total_out = 0;
+
+ err = deflateInit2(&c_stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
+ 15+16, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
+
+ if (err != Z_OK) {
+ LOG_ERROR(WARN,"Deflate Init error");
+ return FALSE;
+ }
+
+ c_stream.next_in = (Bytef*) h->stat->buffer->str;
+ c_stream.avail_in = h->stat->buffer->len;
+ c_stream.next_out = (Bytef*) h->resp->resp_body->str;
+ c_stream.avail_out = h->resp->resp_body->size;
+
+ do {
+ c_stream.next_out = (Bytef*) (h->resp->resp_body->str + c_stream.total_out);
+
+ // Calculate the amount of remaining free space in the output buffer
+ // by subtracting the number of bytes that have been written so far
+ // from the buffer's total capacity
+ c_stream.avail_out = h->resp->resp_body->size - c_stream.total_out;
+ err = deflate(&c_stream, Z_FINISH);
+ } while (err == Z_OK);
+
+ if (err = Z_STREAM_END) {
+ err = deflateEnd(&c_stream);
+ if ( err != Z_OK) {
+ LOG_ERROR(WARN, "Deflate End error");
+ return FALSE;
+ } else {
+ h->resp->resp_body->len = c_stream.total_out;
+ return TRUE;
+ }
+ } else {
+ switch (err) {
+ case Z_ERRNO:
+ LOG_ERROR(WARN, "Error occured while reading file.");
+ break;
+ case Z_STREAM_ERROR:
+ LOG_ERROR(WARN, "The stream state was inconsistent (e.g., next_in or next_out was NULL).");
+ break;
+ case Z_DATA_ERROR:
+ LOG_ERROR(WARN, "The deflate data was invalid or incomplete.");
+ break;
+ case Z_MEM_ERROR:
+ LOG_ERROR(WARN, "Memory could not be allocated for processing.");
+ break;
+ case Z_BUF_ERROR:
+ LOG_ERROR(WARN, "Ran out of output buffer for writing compressed bytes.");
+ break;
+ case Z_VERSION_ERROR:
+ LOG_ERROR(WARN, "The version of zlib.h and the version of the library linked do not match.");
+ break;
+ default:
+ LOG_ERROR(WARN, "Unknown error code.");
+ break;
+ }
+ return FALSE;
+ }
+}
/** Compress file */
/* Compress file if its size is >10kb and < 1mb and its mime-type has either
* text or xml */
-int file_compress(http_t *h, static_file_t *ext){
- LOG_FUNCTION
+int file_compress(http_t *h, static_file_t *ext) {
+ LOG_FUNCTION
+ int rv=0;
+ char *cache_control=NULL;
+
+ cache_control = scgi_header_value_get(h->req->scgi, "Cache-Control");
+ if(cache_control && strstr(cache_control, "no-transform")) {
+ return FALSE;
+ }
+
h->stat->encoding = scgi_header_value_get(h->req->scgi, "HTTP_ACCEPT_ENCODING");
h->stat->user_agent = scgi_header_value_get(h->req->scgi, "HTTP_USER_AGENT");
-
- if(h->stat->buf.st_size >= Config->Worker.Compress.lower_limit
- && h->stat->buf.st_size <= Config->Worker.Compress.upper_limit
- && h->stat->encoding && strstr(h->stat->encoding,"deflate")){
+ /* Skip compressing entity body if user agent is IE6
+ refer http://schroepl.net/projekte/mod_gzip/browser.htm and
+ http://support.microsoft.com/default.aspx?scid=kb;en-us;Q313712
+ for problem details
+ */
+ if(h->stat->user_agent && strstr(h->stat->user_agent, "MSIE 6.0")) {
+ return FALSE;
+ }
+ if(h->stat->buf.st_size >= Config->Worker.Compress.lower_limit
+ && h->stat->buf.st_size <= Config->Worker.Compress.upper_limit
+ && h->stat->encoding) {
+ //TODO: look into Cache-Control request header and q value of Accept-Encoding request header
+ // to decide correct encoding
+ if (strstr(h->stat->encoding, "gzip")) {
+ h->resp->content_encoding = WR_GZIP_ENCODING;
+ }
+ else if (strstr(h->stat->encoding, "deflate")) {
+ h->resp->content_encoding = WR_DEFLATE_ENCODING;
+ }
+ else {
+ h->resp->content_encoding = WR_NO_ENCODING;
+ return FALSE;
+ }
+
#ifdef W_REGEX
if(h->stat->r_content_type){
if(regexec(h->stat->r_content_type, ext->mime_type, 0, NULL, 0) !=0 ) return FALSE;
}
@@ -336,10 +456,15 @@
#endif
wr_u_int read;
FILE *file;
wr_buffer_create(h->stat->buffer, h->stat->buf.st_size);
+
+ if(h->stat->buffer->str == NULL) {
+ return FALSE;
+ }
+
file = fopen(h->stat->path, "r");
if(file == NULL) return FALSE;
while(h->stat->buffer->len < h->stat->buf.st_size){
@@ -355,33 +480,41 @@
fclose(file);
//zlib states that the source buffer must be at least 0.1 times larger than
//the source buffer plus 12 bytes to cope with the overhead of zlib data streams
- wr_buffer_create(h->resp->resp_body, h->stat->buf.st_size + h->stat->buf.st_size*0.1 + 12);
- h->resp->resp_body->len = h->resp->resp_body->size;
- //now compress the data
- if(compress2((Bytef*)h->resp->resp_body->str, (uLongf*)&h->resp->resp_body->len,
- (const Bytef*)h->stat->buffer->str, (uLongf)h->stat->buffer->len, Z_DEFAULT_COMPRESSION) != Z_OK){
- wr_buffer_null(h->stat->buffer);
- wr_buffer_null(h->resp->resp_body);
- return FALSE;
+ wr_buffer_create(h->resp->resp_body, h->stat->buf.st_size * 1.01 + 12);
+
+ switch(h->resp->content_encoding) {
+ case WR_GZIP_ENCODING:
+ rv = gzip_file_compression(h);
+ LOG_DEBUG(DEBUG, "Done gzip encoding rv = %d", rv);
+ break;
+ case WR_DEFLATE_ENCODING:
+ rv = deflate_file_compression(h);
+ LOG_DEBUG(DEBUG, "Done deflate encoding rv = %d", rv);
+ break;
}
+
wr_buffer_null(h->stat->buffer);
-
- return TRUE;
+
+ if(rv == FALSE) {
+ wr_buffer_null(h->resp->resp_body);
+ }
+
+ return rv;
}
return FALSE;
}
#endif
void http_resp_200(http_t *h) {
LOG_FUNCTION
char str[STR_SIZE512], expire_date[STR_SIZE64] = "", current_date[STR_SIZE64] = "", modify_date[STR_SIZE64] = "";
int len;
- int ret_val;
+ int ret_val = FALSE;
time_t t;
static_file_t *ext = get_mime_type(h->stat);
LOG_DEBUG(DEBUG,"File extension = %s, mimetype = %s, expires = %d ", ext->ext, ext->mime_type, ext->expires);
const char *conn_header = scgi_header_value_get(h->req->scgi, HTTP_HEADER_CONNECTION);
@@ -405,20 +538,20 @@
if (ext->expires > 0) {
t += ext->expires;
time_to_httpdate(t, expire_date, STR_SIZE64);
len = sprintf(str, "HTTP/1.1 200 OK\r\nDate: %s\r\nServer: %s-%s\r\nLast-Modified: %s\r\nExpires: %s\r\nConnection: %s\r\n%sContent-Type: %s\r\nContent-Length: %d\r\n\r\n",
- current_date, Config->Worker.Server.name.str, Config->Worker.Server.version.str, modify_date, expire_date,
- (conn_header ? conn_header : CONNECTION_CLOSE),
- (ret_val == TRUE ? "Content-Encoding: deflate\r\n" : ""),
- ext->mime_type, h->resp->resp_body->len);
- }else {
+ current_date, Config->Worker.Server.name.str, Config->Worker.Server.version.str, modify_date, expire_date,
+ (conn_header ? conn_header : CONNECTION_CLOSE),
+ (ret_val == TRUE ? (h->resp->content_encoding == WR_GZIP_ENCODING ? "Content-Encoding: gzip\r\n" : "Content-Encoding: deflate\r\n") : ""),
+ ext->mime_type, h->resp->resp_body->len);
+ } else {
len = sprintf(str, "HTTP/1.1 200 OK\r\nDate: %s\r\nServer: %s-%s\r\nLast-Modified: %s\r\nConnection: %s\r\n%sContent-Type: %s\r\nContent-Length: %d\r\n\r\n",
- current_date, Config->Worker.Server.name.str, Config->Worker.Server.version.str, modify_date,
- (conn_header ? conn_header : CONNECTION_CLOSE),
- (ret_val == TRUE ? "Content-Encoding: deflate\r\n" : ""),
- ext->mime_type, h->resp->resp_body->len);
+ current_date, Config->Worker.Server.name.str, Config->Worker.Server.version.str, modify_date,
+ (conn_header ? conn_header : CONNECTION_CLOSE),
+ (ret_val == TRUE ? (h->resp->content_encoding == WR_GZIP_ENCODING ? "Content-Encoding: gzip\r\n" : "Content-Encoding: deflate\r\n") : ""),
+ ext->mime_type, h->resp->resp_body->len);
}
wr_string_new(h->resp->header, str, len);
h->resp->resp_code = http_status[HTTP_STATUS_200].code;
}
@@ -505,13 +638,13 @@
wr_msg_queue_server_t *msg_queue_server = NULL;
wr_msg_queue_conn_t *msg_queue_conn = NULL;
char msg_value[STR_SIZE32];
int rv;
- host = get_node_value(root, WR_MSG_QUEUE_SERVER_HOST);
- port = get_node_value(root, WR_MSG_QUEUE_SERVER_PORT);
- queue_name = get_node_value(root, WR_PID_MSG_QUEUE_NAME);
+ host = yaml_get_value(root, WR_MSG_QUEUE_SERVER_HOST);
+ port = yaml_get_value(root, WR_MSG_QUEUE_SERVER_PORT);
+ queue_name = yaml_get_value(root, WR_PID_MSG_QUEUE_NAME);
if (!host || !port || !queue_name) {
LOG_ERROR(SEVERE, "Error getting message queue configuration");
goto err;
}
msg_queue_server = wr_msg_queue_server_new(host, atoi(port));
@@ -535,11 +668,11 @@
LOG_ERROR(SEVERE, "Failed to send PID to message queue");
} else {
LOG_INFO("PID sent to queue successfully.");
}
err:
- node_free(root);
+ yaml_node_free(root);
wr_msg_queue_conn_free(msg_queue_conn);
wr_msg_queue_server_free(msg_queue_server);
return;
}
}
@@ -557,16 +690,16 @@
return FALSE;
}
expires = get_default_expires(root);
if (create_dictionary(s, Config->Worker.File.mime_type.str, expires) != 0) {
- node_free(root);
+ yaml_node_free(root);
return FALSE;
}
set_expires_by_type(s, root);
- node_free(root);
+ yaml_node_free(root);
send_static_worker_pid();
return TRUE;
}