mirror of
https://github.com/owntone/owntone-server.git
synced 2025-01-13 16:03:23 -05:00
Add gzip content-encoding from patch by Ciamac Moallemi
This commit is contained in:
parent
a82653e538
commit
1e17bf8c41
4
CREDITS
4
CREDITS
@ -58,3 +58,7 @@ Gavin Shelley
|
|||||||
|
|
||||||
Stephen Rubner
|
Stephen Rubner
|
||||||
* fixes for ulong ino_t
|
* fixes for ulong ino_t
|
||||||
|
|
||||||
|
Ciamac Moallemi
|
||||||
|
* gzip content-encoding
|
||||||
|
|
||||||
|
@ -112,6 +112,7 @@ CONFIGELEMENT config_elements[] = {
|
|||||||
{ 1,0,0,CONFIG_TYPE_INT,"always_scan",(void*)&config.always_scan,config_emit_int },
|
{ 1,0,0,CONFIG_TYPE_INT,"always_scan",(void*)&config.always_scan,config_emit_int },
|
||||||
{ 1,0,0,CONFIG_TYPE_INT,"process_m3u",(void*)&config.process_m3u,config_emit_int },
|
{ 1,0,0,CONFIG_TYPE_INT,"process_m3u",(void*)&config.process_m3u,config_emit_int },
|
||||||
{ 1,0,0,CONFIG_TYPE_INT,"scan_type",(void*)&config.scan_type,config_emit_int },
|
{ 1,0,0,CONFIG_TYPE_INT,"scan_type",(void*)&config.scan_type,config_emit_int },
|
||||||
|
{ 1,0,0,CONFIG_TYPE_INT,"compress",(void*)&config.compress,config_emit_int },
|
||||||
{ 1,0,0,CONFIG_TYPE_STRING,"playlist",(void*)&config.playlist,config_emit_string },
|
{ 1,0,0,CONFIG_TYPE_STRING,"playlist",(void*)&config.playlist,config_emit_string },
|
||||||
{ 1,0,0,CONFIG_TYPE_STRING,"extensions",(void*)&config.extensions,config_emit_string },
|
{ 1,0,0,CONFIG_TYPE_STRING,"extensions",(void*)&config.extensions,config_emit_string },
|
||||||
{ 1,0,0,CONFIG_TYPE_STRING,"password",(void*)&config.readpassword, config_emit_string },
|
{ 1,0,0,CONFIG_TYPE_STRING,"password",(void*)&config.readpassword, config_emit_string },
|
||||||
@ -255,6 +256,7 @@ int config_read(char *file) {
|
|||||||
config.rescan_interval=0;
|
config.rescan_interval=0;
|
||||||
config.process_m3u=0;
|
config.process_m3u=0;
|
||||||
config.scan_type=0;
|
config.scan_type=0;
|
||||||
|
config.compress=0;
|
||||||
|
|
||||||
/* DWB: use alloced space so it can be freed without errors */
|
/* DWB: use alloced space so it can be freed without errors */
|
||||||
config.extensions=strdup(".mp3");
|
config.extensions=strdup(".mp3");
|
||||||
|
145
src/daap-proto.c
145
src/daap-proto.c
@ -37,6 +37,103 @@
|
|||||||
DAAP_BLOCK *daap_get_new(void);
|
DAAP_BLOCK *daap_get_new(void);
|
||||||
DAAP_BLOCK *daap_add_formatted(DAAP_BLOCK *parent, char *tag,
|
DAAP_BLOCK *daap_add_formatted(DAAP_BLOCK *parent, char *tag,
|
||||||
int len, char *value);
|
int len, char *value);
|
||||||
|
|
||||||
|
|
||||||
|
GZIP_STREAM *gzip_alloc(void) {
|
||||||
|
GZIP_STREAM *gz = malloc(sizeof(GZIP_STREAM));
|
||||||
|
gz->in_size = GZIP_CHUNK;
|
||||||
|
gz->in = malloc(gz->in_size);
|
||||||
|
gz->bytes_in = 0;
|
||||||
|
gz->out = NULL;
|
||||||
|
gz->bytes_out = 0;
|
||||||
|
return gz;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t gzip_write(GZIP_STREAM *gz, void *buf, size_t size) {
|
||||||
|
int next_size;
|
||||||
|
char *in2;
|
||||||
|
int new_size;
|
||||||
|
|
||||||
|
if (gz->in == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* make sure input buffer is big enough */
|
||||||
|
while (gz->in_size <= gz->bytes_in + size) {
|
||||||
|
new_size = 2*gz->in_size;
|
||||||
|
in2 = malloc(new_size);
|
||||||
|
if (in2 == NULL) {
|
||||||
|
DPRINTF(E_LOG,L_WS|L_DAAP,"out of memory for input buffer\n");
|
||||||
|
free(gz->in);
|
||||||
|
gz->in = NULL;
|
||||||
|
gz->bytes_in = gz->in_size = 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memcpy(in2, gz->in, gz->in_size);
|
||||||
|
free(gz->in);
|
||||||
|
gz->in = in2;
|
||||||
|
gz->in_size = new_size;
|
||||||
|
}
|
||||||
|
memcpy(gz->in + gz->bytes_in, buf, size);
|
||||||
|
gz->bytes_in += size;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gzip_compress(GZIP_STREAM *gz) {
|
||||||
|
int out_size;
|
||||||
|
int status;
|
||||||
|
z_stream strm;
|
||||||
|
|
||||||
|
if (gz->in == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
out_size = (int)(1.05*gz->in_size) + 20;
|
||||||
|
gz->out = malloc(out_size);
|
||||||
|
if (gz->out == NULL) {
|
||||||
|
DPRINTF(E_INF,L_WS|L_DAAP,"out of memory for output buffer\n");
|
||||||
|
gz->bytes_out = 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
strm.zalloc = Z_NULL;
|
||||||
|
strm.zfree = Z_NULL;
|
||||||
|
strm.opaque = Z_NULL;
|
||||||
|
strm.next_in = gz->in;
|
||||||
|
strm.avail_in = gz->bytes_in;
|
||||||
|
strm.next_out = gz->out;
|
||||||
|
strm.avail_out = out_size;
|
||||||
|
deflateInit2(&strm,GZIP_COMPRESSION_LEVEL,Z_DEFLATED,31,8,Z_DEFAULT_STRATEGY);
|
||||||
|
while ((status = deflate(&strm,Z_FINISH)) == Z_OK)
|
||||||
|
;
|
||||||
|
if (status != Z_STREAM_END) {
|
||||||
|
DPRINTF(E_LOG,L_WS|L_DAAP,"unable to compress data\n");
|
||||||
|
gz->bytes_out = 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
gz->bytes_out = strm.total_out;
|
||||||
|
deflateEnd(&strm);
|
||||||
|
|
||||||
|
return gz->bytes_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gzip_close(GZIP_STREAM *gz, int fd) {
|
||||||
|
int bytes_written = gz->bytes_out;
|
||||||
|
if (r_write(fd,gz->out,gz->bytes_out) != gz->bytes_out) {
|
||||||
|
DPRINTF(E_LOG,L_WS|L_DAAP,"unable to write gzipped data\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (gz->in != NULL)
|
||||||
|
free(gz->in);
|
||||||
|
if (gz->out != NULL)
|
||||||
|
free(gz->out);
|
||||||
|
free(gz);
|
||||||
|
return bytes_written;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* daap_get_new
|
* daap_get_new
|
||||||
*
|
*
|
||||||
@ -237,32 +334,50 @@ DAAP_BLOCK *daap_add_empty(DAAP_BLOCK *parent, char *tag) {
|
|||||||
*
|
*
|
||||||
* Serialize a daap tree to a fd;
|
* Serialize a daap tree to a fd;
|
||||||
*/
|
*/
|
||||||
int daap_serialize(DAAP_BLOCK *root, int fd, int gzip) {
|
int daap_serialize(DAAP_BLOCK *root, int fd, GZIP_STREAM *gz) {
|
||||||
char size[4];
|
char size[4];
|
||||||
|
|
||||||
while(root) {
|
while(root) {
|
||||||
|
if (gz == NULL)
|
||||||
r_write(fd,root->tag,4);
|
r_write(fd,root->tag,4);
|
||||||
|
else
|
||||||
|
gzip_write(gz,root->tag,4);
|
||||||
|
|
||||||
size[0] = (root->reported_size >> 24) & 0xFF;
|
size[0] = (root->reported_size >> 24) & 0xFF;
|
||||||
size[1] = (root->reported_size >> 16) & 0xFF;
|
size[1] = (root->reported_size >> 16) & 0xFF;
|
||||||
size[2] = (root->reported_size >> 8 ) & 0xFF;
|
size[2] = (root->reported_size >> 8 ) & 0xFF;
|
||||||
size[3] = (root->reported_size) & 0xFF;
|
size[3] = (root->reported_size) & 0xFF;
|
||||||
|
|
||||||
|
if (gz == NULL)
|
||||||
r_write(fd,&size,4);
|
r_write(fd,&size,4);
|
||||||
|
else
|
||||||
|
gzip_write(gz,&size,4);
|
||||||
|
|
||||||
if(root->size) {
|
if(root->size) {
|
||||||
if(root->free)
|
if(root->free) {
|
||||||
r_write(fd,root->value,root->size);
|
if (gz == NULL) {
|
||||||
else
|
r_write(fd,root->value,root->size);
|
||||||
r_write(fd,root->svalue,root->size);
|
}
|
||||||
|
else {
|
||||||
|
gzip_write(gz,root->value,root->size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
if(root->children) {
|
if (gz == NULL) {
|
||||||
if(daap_serialize(root->children,fd,gzip))
|
r_write(fd,root->svalue,root->size);
|
||||||
return -1;
|
}
|
||||||
|
else {
|
||||||
|
gzip_write(gz,root->svalue,root->size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
root=root->next;
|
if(root->children) {
|
||||||
|
if(daap_serialize(root->children,fd,gz))
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
root=root->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -23,6 +23,24 @@
|
|||||||
#define _DAAP_PROTO_H_
|
#define _DAAP_PROTO_H_
|
||||||
|
|
||||||
|
|
||||||
|
#include "zlib.h"
|
||||||
|
|
||||||
|
#define GZIP_CHUNK 16384
|
||||||
|
#define GZIP_COMPRESSION_LEVEL Z_DEFAULT_COMPRESSION
|
||||||
|
|
||||||
|
typedef struct gzip_stream_tag {
|
||||||
|
int bytes_in;
|
||||||
|
int bytes_out;
|
||||||
|
int in_size;
|
||||||
|
char *in;
|
||||||
|
char *out;
|
||||||
|
} GZIP_STREAM;
|
||||||
|
|
||||||
|
GZIP_STREAM *gzip_alloc(void);
|
||||||
|
ssize_t gzip_write(GZIP_STREAM *gz, void *buf, size_t size);
|
||||||
|
int gzip_compress(GZIP_STREAM *gz);
|
||||||
|
int gzip_close(GZIP_STREAM *gz, int fd);
|
||||||
|
|
||||||
typedef struct daap_block_tag {
|
typedef struct daap_block_tag {
|
||||||
char tag[4];
|
char tag[4];
|
||||||
int reported_size;
|
int reported_size;
|
||||||
@ -42,7 +60,7 @@ DAAP_BLOCK *daap_add_empty(DAAP_BLOCK *parent, char *tag);
|
|||||||
DAAP_BLOCK *daap_add_char(DAAP_BLOCK *parent, char *tag, char value);
|
DAAP_BLOCK *daap_add_char(DAAP_BLOCK *parent, char *tag, char value);
|
||||||
DAAP_BLOCK *daap_add_short(DAAP_BLOCK *parent, char *tag, short int value);
|
DAAP_BLOCK *daap_add_short(DAAP_BLOCK *parent, char *tag, short int value);
|
||||||
DAAP_BLOCK *daap_add_long(DAAP_BLOCK *parent, char *tag, int v1, int v2);
|
DAAP_BLOCK *daap_add_long(DAAP_BLOCK *parent, char *tag, int v1, int v2);
|
||||||
int daap_serialize(DAAP_BLOCK *root, int fd, int gzip);
|
int daap_serialize(DAAP_BLOCK *root, int fd, GZIP_STREAM *gz);
|
||||||
void daap_free(DAAP_BLOCK *root);
|
void daap_free(DAAP_BLOCK *root);
|
||||||
|
|
||||||
// remove a block from it's parent (and free it)
|
// remove a block from it's parent (and free it)
|
||||||
|
@ -54,6 +54,7 @@ typedef struct tag_config {
|
|||||||
int always_scan; /**< 0 to minimize disk usage (embedded devices) */
|
int always_scan; /**< 0 to minimize disk usage (embedded devices) */
|
||||||
int process_m3u; /**< Should we process m3u files? */
|
int process_m3u; /**< Should we process m3u files? */
|
||||||
int scan_type; /**< How hard to search mp3 files. see scan_get_mp3fileinfo() */
|
int scan_type; /**< How hard to search mp3 files. see scan_get_mp3fileinfo() */
|
||||||
|
int compress; /**< Should we compress? */
|
||||||
char *adminpassword; /**< Password to web management pages */
|
char *adminpassword; /**< Password to web management pages */
|
||||||
char *readpassword; /**< iTunes password */
|
char *readpassword; /**< iTunes password */
|
||||||
char *mp3dir; /**< root directory of the mp3 files */
|
char *mp3dir; /**< root directory of the mp3 files */
|
||||||
|
44
src/main.c
44
src/main.c
@ -171,6 +171,10 @@ void daap_handler(WS_CONNINFO *pwsc) {
|
|||||||
char *first, *last;
|
char *first, *last;
|
||||||
char* index = 0;
|
char* index = 0;
|
||||||
int streaming=0;
|
int streaming=0;
|
||||||
|
int compress =0;
|
||||||
|
int start_time;
|
||||||
|
int end_time;
|
||||||
|
int bytes_written;
|
||||||
|
|
||||||
MP3FILE *pmp3;
|
MP3FILE *pmp3;
|
||||||
int file_fd;
|
int file_fd;
|
||||||
@ -325,21 +329,39 @@ void daap_handler(WS_CONNINFO *pwsc) {
|
|||||||
|
|
||||||
if(!streaming) {
|
if(!streaming) {
|
||||||
DPRINTF(E_DBG,L_WS,"Satisfying request\n");
|
DPRINTF(E_DBG,L_WS,"Satisfying request\n");
|
||||||
ws_addresponseheader(pwsc,"Content-Length","%d",root->reported_size + 8);
|
|
||||||
ws_writefd(pwsc,"HTTP/1.1 200 OK\r\n");
|
|
||||||
|
|
||||||
DPRINTF(E_DBG,L_WS,"Emitting headers\n");
|
if((config.compress) && ws_testrequestheader(pwsc,"Accept-Encoding","gzip") && root->reported_size >= 1000) {
|
||||||
ws_emitheaders(pwsc);
|
|
||||||
|
|
||||||
/*
|
|
||||||
if(ws_testrequestheader(pwsc,"Accept-Encoding","gzip")) {
|
|
||||||
ws_addresponseheader(pwsc,"Content-Encoding","gzip");
|
|
||||||
compress=1;
|
compress=1;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
DPRINTF(E_DBG,L_WS|L_DAAP,"Serializing\n");
|
DPRINTF(E_DBG,L_WS|L_DAAP,"Serializing\n");
|
||||||
daap_serialize(root,pwsc->fd,0);
|
start_time = time(NULL);
|
||||||
|
if (compress) {
|
||||||
|
DPRINTF(E_DBG,L_WS|L_DAAP,"Using compression: %s\n", pwsc->uri);
|
||||||
|
GZIP_STREAM *gz = gzip_alloc();
|
||||||
|
daap_serialize(root,pwsc->fd,gz);
|
||||||
|
gzip_compress(gz);
|
||||||
|
bytes_written = gz->bytes_out;
|
||||||
|
ws_writefd(pwsc,"HTTP/1.1 200 OK\r\n");
|
||||||
|
ws_addresponseheader(pwsc,"Content-Length","%d",bytes_written);
|
||||||
|
ws_addresponseheader(pwsc,"Content-Encoding","gzip");
|
||||||
|
DPRINTF(E_DBG,L_WS,"Emitting headers\n");
|
||||||
|
ws_emitheaders(pwsc);
|
||||||
|
if (gzip_close(gz,pwsc->fd) != bytes_written) {
|
||||||
|
DPRINTF(E_LOG,L_WS|L_DAAP,"Error compressing data\n");
|
||||||
|
}
|
||||||
|
DPRINTF(E_DBG,L_WS|L_DAAP,"Compression ratio: %f\n",((double) bytes_written)/(8.0 + root->reported_size))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bytes_written = root->reported_size + 8;
|
||||||
|
ws_addresponseheader(pwsc,"Content-Length","%d",bytes_written);
|
||||||
|
ws_writefd(pwsc,"HTTP/1.1 200 OK\r\n");
|
||||||
|
DPRINTF(E_DBG,L_WS,"Emitting headers\n");
|
||||||
|
ws_emitheaders(pwsc);
|
||||||
|
daap_serialize(root,pwsc->fd,NULL);
|
||||||
|
}
|
||||||
|
end_time = time(NULL);
|
||||||
|
DPRINTF(E_DBG,L_WS|L_DAAP,"Sent %d bytes in %d seconds\n",bytes_written,end_time-start_time);
|
||||||
DPRINTF(E_DBG,L_WS|L_DAAP,"Done, freeing\n");
|
DPRINTF(E_DBG,L_WS|L_DAAP,"Done, freeing\n");
|
||||||
daap_free(root);
|
daap_free(root);
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user