class Vines::Stream::Http::Request
Constants
- BUF_SIZE
- CONTENT_TYPES
- IF_MODIFIED
- MODIFIED
- MOVED
- NOT_FOUND
- NOT_MODIFIED
- OPTIONS
- TEXT_PLAIN
Attributes
Public Class Methods
# File lib/vines/stream/http/request.rb, line 28 def initialize(stream, parser, body) @stream, @body = stream, body @headers = parser.headers @method = parser.http_method @path = parser.request_path @url = parser.request_url @query = parser.query_string @received = Time.now end
Public Instance Methods
Return the number of seconds since this request was received.
# File lib/vines/stream/http/request.rb, line 39 def age Time.now - @received end
Return true if the request method is OPTIONS
, signaling a CORS preflight check.
# File lib/vines/stream/http/request.rb, line 86 def options? @method == OPTIONS end
Send an HTTP 200 OK response wrapping the XMPP node content back to the client.
# File lib/vines/stream/http/request.rb, line 72 def reply(node, content_type) body = node.to_s header = [ "HTTP/1.1 200 OK", "Access-Control-Allow-Origin: *", "Content-Type: #{content_type}", "Content-Length: #{body.bytesize}", vroute_cookie ].compact.join("\r\n") @stream.stream_write([header, body].join("\r\n\r\n")) end
Send a 200 OK response, allowing any origin domain to connect to the server, in response to CORS preflight OPTIONS
requests. This allows any web application using strophe.js to connect to our BOSH port.
# File lib/vines/stream/http/request.rb, line 93 def reply_to_options allow = @headers['Access-Control-Request-Headers'] headers = [ "Access-Control-Allow-Origin: *", "Access-Control-Allow-Methods: POST, GET, OPTIONS", "Access-Control-Allow-Headers: #{allow}", "Access-Control-Max-Age: #{60 * 60 * 24 * 30}" ] send_status(200, 'OK', headers) end
Write the requested file to the client out of the given document root directory. Take care to prevent directory traversal attacks with paths like ../../../etc/passwd. Use the If-Modified-Since request header to implement caching.
# File lib/vines/stream/http/request.rb, line 47 def reply_with_file(dir) path = File.expand_path(File.join(dir, @path)) # redirect requests missing a slash so relative links work if File.directory?(path) && !@path.end_with?('/') send_status(301, MOVED, "Location: #{redirect_uri}") return end path = File.join(path, 'index.html') if File.directory?(path) if path.start_with?(dir) && File.exist?(path) modified?(path) ? send_file(path) : send_status(304, NOT_MODIFIED) else missing = File.join(dir, '404.html') if File.exist?(missing) send_file(missing, 404, NOT_FOUND) else send_status(404, NOT_FOUND) end end end
Private Instance Methods
# File lib/vines/stream/http/request.rb, line 156 def content_type(path) ext = File.extname(path).sub('.', '') CONTENT_TYPES[ext] || TEXT_PLAIN end
Return true if the file has been modified since the client last requested it with the If-Modified-Since header.
# File lib/vines/stream/http/request.rb, line 120 def modified?(path) @headers[IF_MODIFIED] != mtime(path) end
# File lib/vines/stream/http/request.rb, line 124 def mtime(path) File.mtime(path).utc.strftime(MODIFIED) end
Attempt to rebuild the full request URI from the Host header. If it wasn't sent by the client, just return the relative path that was requested. The Location response header must contain the fully qualified URI, but most browsers will accept relative paths as well.
# File lib/vines/stream/http/request.rb, line 110 def redirect_uri host = headers['Host'] uri = "#{path}/" uri = "#{uri}?#{query}" unless (query || '').empty? uri = "http://#{host}#{uri}" if host uri end
Stream
the contents of the file to the client in a 200 OK response. Send a Last-Modified response header so clients can send us an If-Modified-Since request header for caching.
# File lib/vines/stream/http/request.rb, line 140 def send_file(path, status=200, message='OK') header = [ "HTTP/1.1 #{status} #{message}", "Content-Type: #{content_type(path)}", "Content-Length: #{File.size(path)}", "Last-Modified: #{mtime(path)}" ].join("\r\n") @stream.stream_write("#{header}\r\n\r\n") File.open(path) do |file| while (buf = file.read(BUF_SIZE)) != nil @stream.stream_write(buf) end end end
# File lib/vines/stream/http/request.rb, line 128 def send_status(status, message, *headers) header = [ "HTTP/1.1 #{status} #{message}", "Content-Length: 0", *headers ].join("\r\n") @stream.stream_write("#{header}\r\n\r\n") end