Posts tagged with: http

Griffin.Networking – Added support for HTTP ranges

Added support for partial file downloads (content ranges)

Someone requested that I should add support for the Range headers in the HTTP protocol. I’ve done that now. But let’s back up a bit first.

In Griffin.Networking you can send files no matter the file size (GB files are no problem). What you do is simply to invoke Send() in your service class. Here is an example:

public class YourService : IServiceService
	public override void HandleReceive(object message)
		var buffer = (byte[])message;
		// check message here
		var fileStream = new FileStream(@"", FileMode.Open,
                                                FileAccess.Read, FileShare.ReadWrite);


That’s it. The framework will take care of the file sending, sending one piece at a time (the size of the piece is determined by the buffer pool size that you defined when creating the server).

Dealing with ranges manually

In a custom tailored server (i.e. you just use the HTTP protocol implementation from Griffin.Networking) you do it like this:

var rangeHeader = request.Headers["Range"];
if (rangeHeader != null && !string.IsNullOrEmpty(rangeHeader.Value))
	var response = request.CreateResponse(HttpStatusCode.PartialContent, "Roger, you'll get partial content");
	response.AddHeader("Accept-Ranges", "bytes");
	var fileStream = new FileStream(@"SomeFilePath", FileMode.Open,	FileAccess.Read, FileShare.ReadWrite);

	// parse requested ranges.
	// we can parse all, but currently do only support one in the ByteRangeStream
	var ranges = new RangeCollection();
	ranges.Parse(rangeHeader.Value, (int)fileStream.Length);
	response.AddHeader("Content-Range", ranges.ToHtmlHeaderValue((int)fileStream.Length));

	// move to the correct position in the inner stream.
	// will also report the correct range size instead of the entire file size
	// will support serving multiple ranges in the same response in the future.
	response.Body = new ByteRangeStream(ranges, fileStream); 

// all other request processing here.

A full example can be found in the HTTP protocol sample folder at github.

Using the webserver

I’ve moved the WebServer implementation from Griffin.Networking repository to a seperate one at Github called Griffin.WebServer. It contains a file module which supports caching, partial file downloads and listing files (if enabled).

You can configure a HTTP server which serves static files like this:

// Module manager handles all modules in the server
var moduleManager = new ModuleManager();

// Let's serve our downloaded files (Windows 7 users)
var fileService = new DiskFileService("/", string.Format(@"C:Users{0}Downloads", Environment.UserName));

// Create the file module and allow files to be listed.
var module = new FileModule(fileService) {ListFiles = true};

// Add the module

// And start the server.
var server = new HttpServer(moduleManager);
server.Start(IPAddress.Any, 8080);

The WebServer is still work in progress. The pieces are however coming together pretty well.