2
0
Fork 0
lighttpd2/include/lighttpd/chunk.h

250 lines
8.2 KiB
C
Raw Normal View History

2008-06-24 19:19:20 +00:00
#ifndef _LIGHTTPD_CHUNK_H_
#define _LIGHTTPD_CHUNK_H_
#ifndef _LIGHTTPD_BASE_H_
#error Please include <lighttpd/base.h> instead of this file
#endif
2008-06-24 19:19:20 +00:00
/* Open a file only once, so it shouldn't get lost;
* as a file may get split into many chunks, we
* use this struct to keep track of the usage
*/
struct liChunkFile {
2008-06-24 19:19:20 +00:00
gint refcount;
GString *name; /* name of the file */
int fd;
gboolean is_temp; /* file is temporary and will be deleted on cleanup */
};
struct liChunk {
enum { UNUSED_CHUNK, STRING_CHUNK, MEM_CHUNK, FILE_CHUNK, BUFFER_CHUNK } type;
2008-06-24 19:19:20 +00:00
goffset offset;
/* if type == FILE_CHUNK and mem != NULL,
* mem contains the data [file.mmap.offset .. file.mmap.offset + file.mmap.length)
* from the file, and file.mmap.start is NULL as mmap failed and read(...) was used.
*/
GByteArray *mem;
2008-06-24 19:19:20 +00:00
union {
GString *str;
struct {
liChunkFile *file;
off_t start; /* starting offset in the file */
off_t length; /* octets to send from the starting offset */
struct {
char *data; /* the pointer of the mmap'ed area */
size_t length; /* size of the mmap'ed area */
off_t offset; /* start is <n> octets away from the start of the file */
} mmap;
} file;
2008-06-24 19:19:20 +00:00
struct {
liBuffer *buffer;
gsize offset, length;
} buffer;
} data;
/* a chunk can only be in one queue, so we just reserve the memory for the link in it */
GList cq_link;
2008-06-24 19:19:20 +00:00
};
typedef void (*liCQLimitNnotifyCB)(liVRequest *vr, gpointer context, gboolean locked);
struct liCQLimit {
2009-03-01 16:28:01 +00:00
gint refcount;
liVRequest *vr;
2009-03-01 16:28:01 +00:00
goffset limit, current;
gboolean locked;
ev_io *io_watcher;
liCQLimitNnotifyCB notify; /* callback to reactivate input */
2009-03-01 16:28:01 +00:00
gpointer context;
};
struct liChunkQueue {
2008-06-24 19:19:20 +00:00
/* public */
gboolean is_closed;
/* read only */
2009-03-01 16:28:01 +00:00
goffset bytes_in, bytes_out, length, mem_usage;
liCQLimit *limit; /* limit is the sum of all { c->mem->len | c->type == STRING_CHUNK } */
2008-06-24 19:19:20 +00:00
/* private */
GQueue queue;
2008-06-24 19:19:20 +00:00
};
struct liChunkIter {
2008-06-24 19:19:20 +00:00
/* private */
GList *element;
};
/******************
* chunkfile *
******************/
2009-10-07 20:48:57 +00:00
liChunkFile *li_chunkfile_new(GString *name, int fd, gboolean is_temp);
void li_chunkfile_acquire(liChunkFile *cf);
void li_chunkfile_release(liChunkFile *cf);
2008-06-24 19:19:20 +00:00
/* open the file cf->name if it is not already opened for reading
2009-01-04 22:14:08 +00:00
* may return HANDLER_GO_ON, HANDLER_ERROR
2008-06-24 19:19:20 +00:00
*/
2009-07-09 20:17:24 +00:00
LI_API liHandlerResult li_chunkfile_open(liVRequest *vr, liChunkFile *cf);
2008-06-24 19:19:20 +00:00
/******************
* chunk iterator *
******************/
2009-09-26 18:31:52 +00:00
INLINE liChunk* li_chunkiter_chunk(liChunkIter iter);
INLINE gboolean li_chunkiter_next(liChunkIter *iter);
INLINE goffset li_chunkiter_length(liChunkIter iter);
2008-06-24 19:19:20 +00:00
/* get the data from a chunk; easy in case of a STRING_CHUNK,
* but needs to do io in case of FILE_CHUNK; the data is _not_ marked as "done"
2009-01-04 22:14:08 +00:00
* may return HANDLER_GO_ON, HANDLER_ERROR
2008-06-24 19:19:20 +00:00
*/
2009-07-09 20:17:24 +00:00
LI_API liHandlerResult li_chunkiter_read(liVRequest *vr, liChunkIter iter, off_t start, off_t length, char **data_start, off_t *data_len);
2008-06-30 14:24:29 +00:00
2009-07-09 20:17:24 +00:00
/* same as li_chunkiter_read, but tries mmap() first and falls back to read();
* as accessing mmap()-ed areas may result in SIGBUS, you have to handle that signal somehow.
*/
2009-07-09 20:17:24 +00:00
LI_API liHandlerResult li_chunkiter_read_mmap(liVRequest *vr, liChunkIter iter, off_t start, off_t length, char **data_start, off_t *data_len);
2008-06-24 19:19:20 +00:00
/******************
* chunk *
******************/
2009-09-26 18:31:52 +00:00
INLINE goffset li_chunk_length(liChunk *c);
2008-06-24 19:19:20 +00:00
2009-03-01 16:28:01 +00:00
/******************
* cqlimit *
******************/
2009-07-09 20:17:24 +00:00
LI_API liCQLimit* li_cqlimit_new(liVRequest *vr);
LI_API void li_cqlimit_reset(liCQLimit *cql);
LI_API void li_cqlimit_acquire(liCQLimit *cql);
LI_API void li_cqlimit_release(liCQLimit *cql);
LI_API void li_cqlimit_set_limit(liCQLimit *cql, goffset limit);
2009-03-01 16:28:01 +00:00
2008-06-24 19:19:20 +00:00
/******************
* chunkqueue *
******************/
2009-07-09 20:17:24 +00:00
LI_API liChunkQueue* li_chunkqueue_new();
LI_API void li_chunkqueue_reset(liChunkQueue *cq);
LI_API void li_chunkqueue_free(liChunkQueue *cq);
2008-06-24 19:19:20 +00:00
2009-07-09 20:17:24 +00:00
LI_API void li_chunkqueue_use_limit(liChunkQueue *cq, liVRequest *vr);
LI_API void li_chunkqueue_set_limit(liChunkQueue *cq, liCQLimit* cql);
/* return -1 for unlimited, 0 for full and n > 0 for n bytes free */
2009-07-09 20:17:24 +00:00
LI_API goffset li_chunkqueue_limit_available(liChunkQueue *cq);
2008-06-24 19:19:20 +00:00
/* pass ownership of str to chunkqueue, do not free/modify it afterwards
* you may modify the data (not the length) if you are sure it isn't sent before.
* if the length is NULL, str is destroyed immediately
2008-06-24 19:19:20 +00:00
*/
2009-07-09 20:17:24 +00:00
LI_API void li_chunkqueue_append_string(liChunkQueue *cq, GString *str);
2008-06-24 19:19:20 +00:00
/* pass ownership of mem to chunkqueue, do not free/modify it afterwards
* you may modify the data (not the length) if you are sure it isn't sent before.
* if the length is NULL, mem is destroyed immediately
*/
2009-07-09 20:17:24 +00:00
LI_API void li_chunkqueue_append_bytearr(liChunkQueue *cq, GByteArray *mem);
/* pass ownership of buffer to chunkqueue, do not free/modify it afterwards
* you may modify the data (not the length) if you are sure it isn't sent before.
* if the length is NULL, buffer is destroyed immediately
*/
LI_API void li_chunkqueue_append_buffer(liChunkQueue *cq, liBuffer *buffer);
2008-06-24 19:19:20 +00:00
/* memory gets copied */
2009-07-09 20:17:24 +00:00
LI_API void li_chunkqueue_append_mem(liChunkQueue *cq, const void *mem, gssize len);
2008-06-24 19:19:20 +00:00
2009-10-07 20:48:57 +00:00
/* increases reference for cf (if length > 0) */
LI_API void li_chunkqueue_append_chunkfile(liChunkQueue *cq, liChunkFile *cf, off_t start, off_t length);
2008-06-24 19:19:20 +00:00
/* pass ownership of filename, do not free it */
2009-07-09 20:17:24 +00:00
LI_API void li_chunkqueue_append_file(liChunkQueue *cq, GString *filename, off_t start, off_t length);
2008-06-24 19:19:20 +00:00
/* if you already opened the file, you can pass the fd here - do not close it */
2009-07-09 20:17:24 +00:00
LI_API void li_chunkqueue_append_file_fd(liChunkQueue *cq, GString *filename, off_t start, off_t length, int fd);
2008-06-24 19:19:20 +00:00
/* temp files get deleted after usage */
/* pass ownership of filename, do not free it */
2009-07-09 20:17:24 +00:00
LI_API void li_chunkqueue_append_tempfile(liChunkQueue *cq, GString *filename, off_t start, off_t length);
2008-06-24 19:19:20 +00:00
/* if you already opened the file, you can pass the fd here - do not close it */
2009-07-09 20:17:24 +00:00
LI_API void li_chunkqueue_append_tempfile_fd(liChunkQueue *cq, GString *filename, off_t start, off_t length, int fd);
2008-06-24 19:19:20 +00:00
/* steal up to length bytes from in and put them into out, return number of bytes stolen */
2009-07-09 20:17:24 +00:00
LI_API goffset li_chunkqueue_steal_len(liChunkQueue *out, liChunkQueue *in, goffset length);
2008-06-24 19:19:20 +00:00
/* steal all chunks from in and put them into out, return number of bytes stolen */
2009-07-09 20:17:24 +00:00
LI_API goffset li_chunkqueue_steal_all(liChunkQueue *out, liChunkQueue *in);
2008-06-24 19:19:20 +00:00
/* steal the first chunk from in and append it to out, return number of bytes stolen */
2009-07-09 20:17:24 +00:00
LI_API goffset li_chunkqueue_steal_chunk(liChunkQueue *out, liChunkQueue *in);
2008-06-24 19:19:20 +00:00
/* skip up to length bytes in a chunkqueue, return number of bytes skipped */
2009-07-09 20:17:24 +00:00
LI_API goffset li_chunkqueue_skip(liChunkQueue *cq, goffset length);
2008-06-24 19:19:20 +00:00
/* skip all chunks in a queue (similar to reset, but keeps stats) */
2009-07-09 20:17:24 +00:00
LI_API goffset li_chunkqueue_skip_all(liChunkQueue *cq);
2008-06-24 19:19:20 +00:00
/* if the chunk an iterator refers gets stolen/skipped/...,
* the iterator isn't valid anymore
*/
2009-09-26 18:31:52 +00:00
INLINE liChunkIter li_chunkqueue_iter(liChunkQueue *cq);
2008-06-24 19:19:20 +00:00
2009-09-26 18:31:52 +00:00
INLINE liChunk* li_chunkqueue_first_chunk(liChunkQueue *cq);
2008-06-24 19:19:20 +00:00
2009-07-09 20:17:24 +00:00
LI_API gboolean li_chunkqueue_extract_to(liVRequest *vr, liChunkQueue *cq, goffset len, GString *dest);
LI_API gboolean li_chunkqueue_extract_to_bytearr(liVRequest *vr, liChunkQueue *cq, goffset len, GByteArray *dest);
2008-06-24 19:19:20 +00:00
/********************
* Inline functions *
********************/
2009-09-26 18:31:52 +00:00
INLINE liChunk* li_chunkiter_chunk(liChunkIter iter) {
2008-06-24 19:19:20 +00:00
if (!iter.element) return NULL;
return (liChunk*) iter.element->data;
2008-06-24 19:19:20 +00:00
}
2009-09-26 18:31:52 +00:00
INLINE gboolean li_chunkiter_next(liChunkIter *iter) {
2008-06-24 19:19:20 +00:00
if (!iter || !iter->element) return FALSE;
return NULL != (iter->element = g_list_next(iter->element));
}
2009-09-26 18:31:52 +00:00
INLINE goffset li_chunkiter_length(liChunkIter iter) {
return li_chunk_length(li_chunkiter_chunk(iter));
2008-06-24 19:19:20 +00:00
}
2009-09-26 18:31:52 +00:00
INLINE goffset li_chunk_length(liChunk *c) {
2008-06-24 19:19:20 +00:00
if (!c) return 0;
switch (c->type) {
case UNUSED_CHUNK:
return 0;
case STRING_CHUNK:
return c->data.str->len - c->offset;
2008-06-24 19:19:20 +00:00
case MEM_CHUNK:
return c->mem->len - c->offset;
case FILE_CHUNK:
return c->data.file.length - c->offset;
case BUFFER_CHUNK:
return c->data.buffer.length - c->offset;
2008-06-24 19:19:20 +00:00
}
return 0;
}
2009-09-26 18:31:52 +00:00
INLINE liChunkIter li_chunkqueue_iter(liChunkQueue *cq) {
liChunkIter i;
i.element = g_queue_peek_head_link(&cq->queue);
2008-06-24 19:19:20 +00:00
return i;
}
2009-09-26 18:31:52 +00:00
INLINE liChunk* li_chunkqueue_first_chunk(liChunkQueue *cq) {
return (liChunk*) g_queue_peek_head(&cq->queue);
2008-06-24 19:19:20 +00:00
}
#endif