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
Create a new request parsed from an HTTP client connection. We'll try to keep this request open until there are stanzas available to send as a response.
stream - The Stream::Http
client connection that received the request. parser - The Http::Parser that parsed the HTTP request. body - The String request body.
# File lib/vines/stream/http/request.rb, line 35 def initialize(stream, parser, body) uri = URI(parser.request_url) @stream = stream @body = body @headers = parser.headers @method = parser.http_method @url = parser.request_url @path = uri.path @query = uri.query @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 48 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 99 def options? @method == OPTIONS end
Send an HTTP 200 OK response wrapping the XMPP node content back to the client.
Returns nothing.
# File lib/vines/stream/http/request.rb, line 85 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.
Returns nothing.
# File lib/vines/stream/http/request.rb, line 108 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.
Returns nothing.
# File lib/vines/stream/http/request.rb, line 58 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 175 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 137 def modified?(path) @headers[IF_MODIFIED] != mtime(path) end
# File lib/vines/stream/http/request.rb, line 141 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.
Returns the String URL.
# File lib/vines/stream/http/request.rb, line 127 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.
Returns nothing.
# File lib/vines/stream/http/request.rb, line 159 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 145 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