# frozen_string_literal: true require 'uri' require 'webrick' require 'webrick/httpstatus' module Intranet class Core # @!visibility protected # WEBrick servlet for the Intranet. class Servlet < WEBrick::HTTPServlet::AbstractServlet # Initializes a new Servlet instance. # @param server [WEBrick::HTTPServer] The web server. # @param builder [Intranet::Core::Builder] The web pages builder. def initialize(server, builder) super(server) @builder = builder end # Processes a GET request issued to the web server. # @param request [WEBrick::HTTPRequest] The GET request. # @param response [WEBrick::HTTPResponse] Fields +status+, +content_type+ and +body+ are # filled with the server response. def do_GET(request, response) # rubocop:disable Naming/MethodName # See https://github.com/nahi/webrick/blob/master/lib/webrick/httprequest.rb # We could use request.request_uri (which is a URI object) but its path is not normalized # (it may contain '../' or event start with '..'). Hence we use request.path which has been # normalized with HTTPUtils::normalize_path, and request.query for the URL parameters. path = request.path.force_encoding('UTF-8') path += 'index.html' if path.end_with?('/') handle_redirections(request, path, response, '/index.html' => @builder.home_url) status, content_type, body = @builder.do_get(path, encode_query(request.query)) raise WEBrick::HTTPStatus[status] if WEBrick::HTTPStatus.error?(status) response.status = status response.content_type = content_type response.body = body end private # Issues an HTTP redirection (307) in +response+ if the +path+ associated to the +request+ # has an entry if the redirection table +redirects+. def handle_redirections(request, path, response, redirects) target = redirects.fetch(path) location = URI.join(request.request_uri, target).to_s response.set_redirect(WEBrick::HTTPStatus[307], location) if path != target rescue KeyError # nothing to do end # Reencodes the +query+ in UTF-8 strings for compatibility. def encode_query(query) query.map do |k, v| { k.dup.force_encoding('UTF-8') => v.force_encoding('UTF-8') } end.reduce({}, :merge) end end end end