Skip to content

Commit

Permalink
Merge: nitcorn: fix bug with binary files
Browse files Browse the repository at this point in the history
Downloading binary files from a nitcorn server works as expected once again.

The API should be enough for most users but there is a few features lacking. Namely alternating custom text with files and writing custom data. We could merge the `body` and `files` attributes into a sequence of `Bytables` to send, with support for `Bytes`.

You can test the result on xymus.net, either by downloading the latest WBTW at http://xymus.net/pub/wbtw-v0.4-110-g668b261.tar.gz or by playing a clone of Super Hexagon (mostly made by @ablondin) at http://xymus.net/pub/hex/.

Pull-Request: #1817
Reviewed-by: Jean Privat <jean@pryen.org>
  • Loading branch information
privat committed Nov 7, 2015
2 parents 347ca59 + a5de54e commit 84095b1
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 23 deletions.
35 changes: 28 additions & 7 deletions lib/libevent.nit
Expand Up @@ -162,19 +162,34 @@ class Connection

redef fun write_byte(byte) do native_buffer_event.write_byte(byte)

redef fun write_bytes(bytes) do native_buffer_event.write(bytes.items, bytes.length)

# Write a file to the connection
#
# require: `path.file_exists`
# If `not path.file_exists`, the method returns.
fun write_file(path: String)
do
assert path.file_exists

var file = new FileReader.open(path)
var output = native_buffer_event.output_buffer
var fd = file.fd
var length = file.file_stat.size
if file.last_error != null then
var error = new IOError("Failed to open file at '{path}'")
error.cause = file.last_error
self.last_error = error
file.close
return
end

var stat = file.file_stat
if stat == null then
last_error = new IOError("Failed to stat file at '{path}'")
file.close
return
end

output.add_file(fd, 0, length)
var err = native_buffer_event.output_buffer.add_file(file.fd, 0, stat.size)
if err then
last_error = new IOError("Failed to add file at '{path}'")
file.close
end
end
end

Expand Down Expand Up @@ -209,6 +224,12 @@ extern class NativeBufferEvent `{ struct bufferevent * `}

# The input buffer associated to `self`
fun input_buffer: InputNativeEvBuffer `{ return bufferevent_get_input(self); `}

# Read data from this buffer
fun read_buffer(buf: NativeEvBuffer): Int `{ return bufferevent_read_buffer(self, buf); `}

# Write data to this buffer
fun write_buffer(buf: NativeEvBuffer): Int `{ return bufferevent_write_buffer(self, buf); `}
end

# A single buffer
Expand Down
2 changes: 1 addition & 1 deletion lib/nitcorn/examples/Makefile
@@ -1,6 +1,6 @@
all:
mkdir -p bin/
../../../bin/nitc --dir bin src/nitcorn_hello_world.nit src/file_server_on_port_80.nit
../../../bin/nitc --dir bin src/nitcorn_hello_world.nit src/simple_file_server.nit

xymus.net:
mkdir -p bin/
Expand Down
Expand Up @@ -14,22 +14,22 @@
# See the License for the specific language governing permissions and
# limitations under the License.

# Basic file server on port 80, usually requires `root` to execute
# Basic file server on port 80 by default, may require `root` to execute
#
# To be safe, it is recommended to run this program with its own username:
# `sudo file_server -u nitcorn:www`
module file_server_on_port_80
module simple_file_server

import nitcorn
import privileges

# Prepare options
var opts = new OptionContext
var opt_drop = new OptionUserAndGroup.for_dropping_privileges
opt_drop.mandatory = true
var opt_port = new OptionInt("Server port", 80, "--port", "-p")
var opt_help = new OptionBool("Print this message", "--help", "-h")
opts.add_option(opt_drop, opt_help)
opts.parse(args)
opts.add_option(opt_drop, opt_port, opt_help)
opts.parse args

# Check options errors and help
if not opts.errors.is_empty or opt_help.value then
Expand All @@ -40,7 +40,7 @@ if not opts.errors.is_empty or opt_help.value then
end

# Serve everything with a standard FilesHandler
var vh = new VirtualHost("localhost:80")
var vh = new VirtualHost("localhost:{opt_port.value}")
vh.routes.add new Route(null, new FileServer("www/hello_world/"))
var factory = new HttpFactory.and_libevent
factory.config.virtual_hosts.add vh
Expand Down
5 changes: 1 addition & 4 deletions lib/nitcorn/file_server.nit
Expand Up @@ -145,8 +145,7 @@ class FileServer
response.header["Content-Type"] = media_types["html"].as(not null)
else
# It's a single file
var file = new FileReader.open(local_file)
response.body = file.read_all
response.files.add local_file

var ext = local_file.file_extension
if ext != null then
Expand All @@ -155,8 +154,6 @@ class FileServer
response.header["Content-Type"] = media_type
else response.header["Content-Type"] = "application/octet-stream"
end

file.close
end

else response = new HttpResponse(404)
Expand Down
26 changes: 25 additions & 1 deletion lib/nitcorn/http_response.nit
Expand Up @@ -37,12 +37,36 @@ class HttpResponse
# Body of this response
var body = "" is writable

# Files appended after `body`
var files = new Array[String]

# Finalize this response before sending it over HTTP
fun finalize
do
# Set the content length if not already set
if not header.keys.has("Content-Length") then
header["Content-Length"] = body.bytelen.to_s
# Size of the body
var len = body.bytelen

# Size of included files
for path in files do
# TODO handle these error cases elsewhere, an error here will result in an invalid response
if not path.file_exists then
print_error "File does not exists at '{path}'"
continue
end

var stat = path.file_stat
if stat == null then
print_error "Failed to stat file at '{path}'"
continue
end

len += stat.size
end

# Set header
header["Content-Length"] = len.to_s
end

# Set server ID
Expand Down
2 changes: 2 additions & 0 deletions lib/nitcorn/reactor.nit
Expand Up @@ -85,6 +85,8 @@ class HttpServer

# Send back a response
write response.to_s
for path in response.files do write_file path

close
end
end
Expand Down
4 changes: 0 additions & 4 deletions tests/sav/file_server_on_port_80.res

This file was deleted.

1 change: 1 addition & 0 deletions tests/sav/simple_file_server.res
@@ -0,0 +1 @@
libevent warning: Opening localhost:80 failed

0 comments on commit 84095b1

Please sign in to comment.