Added support for ranged requests
This commit is contained in:
parent
cb8c926296
commit
bd21ab6dd7
103
main.c
103
main.c
|
@ -31,6 +31,11 @@ struct ConnectionState {
|
||||||
struct stat targetStat;
|
struct stat targetStat;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct RequestRange {
|
||||||
|
off_t start;
|
||||||
|
off_t length;
|
||||||
|
};
|
||||||
|
|
||||||
char *shareRoot;
|
char *shareRoot;
|
||||||
struct MHD_Response *error403Response;
|
struct MHD_Response *error403Response;
|
||||||
struct MHD_Response *error404Response;
|
struct MHD_Response *error404Response;
|
||||||
|
@ -54,12 +59,97 @@ void request_completed(void *cls,
|
||||||
free(connstate);
|
free(connstate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int parse_range(const char *range, off_t total_len, struct RequestRange *result) {
|
||||||
|
char *numstr;
|
||||||
|
char *dashptr;
|
||||||
|
int dashpos;
|
||||||
|
off_t num;
|
||||||
|
|
||||||
|
LOG(LVL_DEBUG, "Requested Range is %s", range);
|
||||||
|
|
||||||
|
if(range == NULL) {
|
||||||
|
result->start = 0;
|
||||||
|
result->length = total_len;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
numstr = strchr(range, '=');
|
||||||
|
if(numstr == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
numstr += 1;
|
||||||
|
|
||||||
|
LOG(LVL_DUMP, "Numeric part of range: %s", numstr);
|
||||||
|
|
||||||
|
dashptr = strchr(numstr, '-');
|
||||||
|
if(dashptr == NULL) {
|
||||||
|
// no '-' found
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dashpos = dashptr - numstr;
|
||||||
|
LOG(LVL_DUMP, "Dash found at position: %i", dashpos);
|
||||||
|
|
||||||
|
if(dashpos == 0) {
|
||||||
|
// example: bytes=-500
|
||||||
|
// -> letzte 500 bytes ausgeben
|
||||||
|
if(sscanf(dashptr+1, "%li", &num) != 1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// total = 1000, num = 100 -> start=500, length=500
|
||||||
|
result->start = total_len - num - 1;
|
||||||
|
result->length = num;
|
||||||
|
} else {
|
||||||
|
// examples: bytes=100-200; bytes=300-
|
||||||
|
|
||||||
|
// parse the first number
|
||||||
|
if(sscanf(numstr, "%li", &num) != 1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
result->start = num;
|
||||||
|
|
||||||
|
if(numstr[dashpos + 1] == '\0') {
|
||||||
|
// everything from num to the end
|
||||||
|
result->length = total_len - num;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// a complete range was given -> parse the second number
|
||||||
|
if(sscanf(numstr+dashpos+1, "%li", &num) != 1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(num < result->start) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
result->length = num - result->start + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int serv_regular_file(struct MHD_Connection *connection, struct ConnectionState *connstate) {
|
int serv_regular_file(struct MHD_Connection *connection, struct ConnectionState *connstate) {
|
||||||
struct MHD_Response *response;
|
struct MHD_Response *response;
|
||||||
|
struct RequestRange range;
|
||||||
|
const char *rangestr;
|
||||||
|
char buf[256];
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
LOG(LVL_DEBUG, "Serving %s as a regular file.", connstate->localFileName);
|
LOG(LVL_DEBUG, "Serving %s as a regular file.", connstate->localFileName);
|
||||||
|
|
||||||
|
rangestr = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Range");
|
||||||
|
|
||||||
|
if(0 != parse_range(rangestr, connstate->targetStat.st_size, &range)) {
|
||||||
|
LOG(LVL_ERR, "Cannot parse range header.");
|
||||||
|
return MHD_queue_response(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, error500Response);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(LVL_DUMP, "Requested range: start=%lu, length=%lu", range.start, range.length);
|
||||||
|
|
||||||
// open a file descriptor to the file
|
// open a file descriptor to the file
|
||||||
int fd = open(connstate->localFileName, O_RDONLY);
|
int fd = open(connstate->localFileName, O_RDONLY);
|
||||||
|
|
||||||
|
@ -71,9 +161,16 @@ int serv_regular_file(struct MHD_Connection *connection, struct ConnectionState
|
||||||
}
|
}
|
||||||
|
|
||||||
// no error so far -> serve the file
|
// no error so far -> serve the file
|
||||||
response = MHD_create_response_from_fd(
|
response = MHD_create_response_from_fd_at_offset(
|
||||||
connstate->targetStat.st_size,
|
range.length,
|
||||||
fd);
|
fd,
|
||||||
|
range.start);
|
||||||
|
|
||||||
|
// build content range header
|
||||||
|
sprintf(buf, "bytes %li-%li/%li", range.start, range.start+range.length-1, connstate->targetStat.st_size);
|
||||||
|
MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_RANGE, buf);
|
||||||
|
|
||||||
|
LOG(LVL_DUMP, "Content-Range: %s", buf);
|
||||||
|
|
||||||
#ifdef HAVE_MAGIC
|
#ifdef HAVE_MAGIC
|
||||||
// if libmagic is available, determine the correct MIME type for the file
|
// if libmagic is available, determine the correct MIME type for the file
|
||||||
|
|
Loading…
Reference in a new issue