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 RequestRange {
|
||||
off_t start;
|
||||
off_t length;
|
||||
};
|
||||
|
||||
char *shareRoot;
|
||||
struct MHD_Response *error403Response;
|
||||
struct MHD_Response *error404Response;
|
||||
|
@ -54,12 +59,97 @@ void request_completed(void *cls,
|
|||
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) {
|
||||
struct MHD_Response *response;
|
||||
struct RequestRange range;
|
||||
const char *rangestr;
|
||||
char buf[256];
|
||||
int ret;
|
||||
|
||||
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
|
||||
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
|
||||
response = MHD_create_response_from_fd(
|
||||
connstate->targetStat.st_size,
|
||||
fd);
|
||||
response = MHD_create_response_from_fd_at_offset(
|
||||
range.length,
|
||||
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
|
||||
// if libmagic is available, determine the correct MIME type for the file
|
||||
|
|
Loading…
Reference in a new issue