╭ changed ──╮ │src/web.zig│ ╰───────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │211 // before the routable pages │ │212 if (attachmentRequest(path)) |attachment| return serveAttachment(io, request, allocator, attachment, host);│ │213 │ │214 - const current_page_maybe = switch (host) { │ │214 + const route_maybe = switch (host) { │ │215 .server => ui.RoutablePage.fromUrl(path), │ │216 .local => ui.RoutablePage.fromUrlLocal(path), │ │217 }; │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────╮ │218 - if (current_page_maybe) |current_page| { │ │218 + // a path that's neither a page nor an embed gets the not-found page │ │219 + if (route_maybe == null) if (findEmbed(path)) |embed| { │ │220 + // the embeds change with every build, so the browser must revalidate │ │221 + // rather than heuristically cache them across server restarts │ │222 + try request.respond(embed.body, .{ │ │223 + .extra_headers = &.{ │ │224 + .{ .name = "content-type", .value = embed.content_type }, │ │225 + .{ .name = "cache-control", .value = "no-cache" }, │ │226 + }, │ │227 + }); │ │228 + return; │ │229 + }; │ │230 + { │ │231 + const current_page = route_maybe orelse .not_found; │ │232 // resolve the haxy_session cookie's token to a user_id via the │ │233 // store. user_id_buf lives on the stack for the rest of handleRequest,│ │234 // which is plenty for renderIndexHtml to consume. local mode has no │ ╰────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │294 .server => |server| .{ server.git_http_port, server.git_ssh_port, server.git_ssh_prefix },│ │295 .local => .{ null, null, "" }, │ │296 }; │ │284 - const html = renderIndexHtml(io, allocator, host, session_token, .{ │ │297 + var session_data: ui.Session.Data = .{ │ │298 .user_id = user_id, │ │299 .form_feedback = form_feedback, │ │300 .sync_failure = sync_failure, │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │303 .git_http_port = git_http_port, │ │304 .git_ssh_port = git_ssh_port, │ │305 .git_ssh_prefix = git_ssh_prefix, │ │293 - }) catch |err| switch (err) { │ │294 - error.NotFound => { │ │295 - try request.respond("not found", .{ │ │296 - .status = .not_found, │ │297 - .extra_headers = &.{.{ .name = "content-type", .value = "text/plain" }}, │ │298 - }); │ │299 - return; │ │306 + }; │ │307 + // a page that can't be built shows the not-found page instead │ │308 + const html = renderIndexHtml(io, allocator, host, session_token, session_data) catch |err| switch (err) {│ │309 + error.NotFound => blk: { │ │310 + session_data.current_page = .not_found; │ │311 + break :blk try renderIndexHtml(io, allocator, host, session_token, session_data); │ │312 }, │ │313 else => |e| return e, │ │314 }; │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │325 if (expired_form_cookie) |cookie| headers.appendAssumeCapacity(.{ .name = "set-cookie", .value = cookie }); │ │326 if (local_flash_seen) headers.appendAssumeCapacity(.{ .name = "set-cookie", .value = local_flash_cookie ++ "=; Path=/; Max-Age=0" });│ │327 if (session_cookie) |cookie| headers.appendAssumeCapacity(.{ .name = "set-cookie", .value = cookie }); │ │316 - try request.respond(html, .{ .extra_headers = headers.items }); │ │317 - return; │ │328 + try request.respond(html, .{ │ │329 + .status = if (session_data.current_page == .not_found) .not_found else .ok, │ │330 + .extra_headers = headers.items, │ │331 + }); │ │332 } │ │319 - │ │320 - const embed = findEmbed(path) orelse { │ │321 - try request.respond("not found", .{ │ │322 - .status = .not_found, │ │323 - .extra_headers = &.{.{ .name = "content-type", .value = "text/plain" }}, │ │324 - }); │ │325 - return; │ │326 - }; │ │327 - │ │328 - // the embeds change with every build, so the browser must revalidate │ │329 - // rather than heuristically cache them across server restarts │ │330 - try request.respond(embed.body, .{ │ │331 - .extra_headers = &.{ │ │332 - .{ .name = "content-type", .value = embed.content_type }, │ │333 - .{ .name = "cache-control", .value = "no-cache" }, │ │334 - }, │ │335 - }); │ │333 } │ │334 │ │335 fn handleLogin( │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯