public function beginRequest($req, $upstream)
    {
        $e = array_map('rawurldecode', explode('/', $req->attrs->server['DOCUMENT_URI']));

        $serverId = null;
        $sessId = null;

        /* Route discovery */
        $path = null;
        $extra = [];
        do {
            foreach ($this->wss as $wss) {
                $try = implode('/', $e);
                if ($try === '') {
                    $try = '/';
                }
                if ($wss->routeExists($try)) {
                    $path = $try;
                    break 2;
                }
            }
            array_unshift($extra, array_pop($e));
        } while (sizeof($e) > 0);

        if ($path === null) {
            return $this->callMethod('NotFound', $req, $upstream);
        }

        if (sizeof($extra) > 0 && end($extra) === '') {
            array_pop($extra);
        }

        $method = sizeof($extra) ? array_pop($extra) : null;

        if ($method === null) {
            $method = 'Welcome';
        } elseif ($method === 'info') {
        } elseif (preg_match('~^iframe(?:-([^/]*))?\.html$~', $method, $m)) {
            $method = 'Iframe';
            $version = isset($m[1]) ? $m[1] : null;
        } else {
            if (sizeof($extra) < 2) {
                return $this->callMethod('NotFound', $req, $upstream);
            }
            $sessId = array_pop($extra);
            $serverId = array_pop($extra);
            if ($sessId === '' || $serverId === '' || mb_orig_strpos($sessId,
                    '.') !== false || mb_orig_strpos($serverId, '.') !== false
            ) {
                return $this->callMethod('NotFound', $req, $upstream);
            }
        }
        $req->attrs->sessId = $sessId;
        $req->attrs->serverId = $serverId;
        $req->attrs->path = $path;
        $req = $this->callMethod($method, $req, $upstream);
        if ($req instanceof Methods\Iframe && mb_orig_strlen($version)) {
            $req->attrs->version = $version;
        }
        return $req;
    }