Cesivi URL Contract
Created: 2026-04-14 (PLAN-1020 Phase 4)
This document defines the URL routing contract for Cesivi. All SharePoint protocol endpoints are served same-origin through the WebUI host on port 443. Internal server ports are never exposed to browsers.
Topology
Browser ──── HTTPS 443 ────→ Cesivi.WebUI (IIS / Kestrel)
│
┌─────────┴──────────────────────────┐
│ YARP / Custom Proxy │
│ /signalr/* ─────────────────┐ │
│ /_api/* ─────────────────┤ │
│ /_vti_bin/* ─────────────────┤ │
│ /_catalogs/*─────────────────┤ │
│ /_trust/* ─────────────────┤ │
└────────────────────────────────┼───┘
│
HTTP loopback ──────────────▼
Cesivi.Server (:5010 internal)
Key rule: Browsers ONLY ever send requests to the WebUI host. The internal server port (default 5010) is never exposed to the public network.
YARP + Custom Proxy Route Table
| Path Prefix |
Handler |
Notes |
/signalr/* |
SignalRProxyMiddleware (YARP IHttpForwarder) |
WebSocket + HTTP negotiate |
/_api/* |
CesiviApiProxyMiddleware (HTTP) |
REST API — top-level |
/_vti_bin/* |
CesiviApiProxyMiddleware (HTTP) |
SOAP + CSOM |
/_vti_pvt/* |
CesiviApiProxyMiddleware (HTTP) |
FPSE web services |
/_spmock/* |
CesiviApiProxyMiddleware (HTTP) |
Cesivi internal API |
/_trust/* |
CesiviApiProxyMiddleware (HTTP) |
SAML/WS-Federation redirect target |
/_catalogs/* |
CesiviApiProxyMiddleware (HTTP) |
Master pages, web templates, solution gallery |
/health, /ready, /live |
CesiviApiProxyMiddleware (HTTP) |
Health check endpoints |
{subweb}/_api/* |
CesiviApiProxyMiddleware (deep path) |
Sub-web REST — marker /_api/ found anywhere |
{subweb}/_vti_bin/* |
CesiviApiProxyMiddleware (deep path) |
Sub-web SOAP/CSOM |
/_layouts/* |
Cesivi.WebUI Razor Pages |
NOT proxied — served by WebUI directly |
/css/*, /js/*, /lib/* |
UseStaticFiles |
Static assets |
/api/Search/* |
Cesivi.WebUI SearchController |
WebUI's own search controller |
| Everything else |
Cesivi.WebUI Razor Pages |
Default — UI pages |
URL Samples by Object Type
REST API
| Object |
URL |
| Web properties |
https://cesivi.devlab.farm/_api/web |
| List by title |
https://cesivi.devlab.farm/_api/web/lists/getbytitle('Tasks') |
| List items |
https://cesivi.devlab.farm/_api/web/lists/getbytitle('Tasks')/items |
| File content |
https://cesivi.devlab.farm/_api/web/getfilebyserverrelativeurl('/Documents/file.docx')/$value |
| Sub-web list |
https://cesivi.devlab.farm/subweb/_api/web/lists/getbytitle('Notes') |
| Host-named site |
https://cesivi.devlab.farm/sites/team/_api/web |
CSOM
| Object |
URL |
| CSOM batch endpoint |
https://cesivi.devlab.farm/_vti_bin/client.svc/ProcessQuery |
| Sub-web CSOM |
https://cesivi.devlab.farm/subweb/_vti_bin/client.svc/ProcessQuery |
SOAP
| Service |
URL |
| Lists.asmx |
https://cesivi.devlab.farm/_vti_bin/Lists.asmx |
| Webs.asmx |
https://cesivi.devlab.farm/_vti_bin/Webs.asmx |
| Authentication.asmx |
https://cesivi.devlab.farm/_vti_bin/Authentication.asmx |
SignalR
| Object |
URL |
| SignalR hub |
https://cesivi.devlab.farm/signalr/changes |
| Negotiate endpoint |
POST https://cesivi.devlab.farm/signalr/changes/negotiate |
Web UI Pages
| Page |
URL |
| Home |
https://cesivi.devlab.farm/ |
| List view |
https://cesivi.devlab.farm/Lists/Tasks/AllItems.aspx |
| New item form |
https://cesivi.devlab.farm/Lists/Tasks/NewForm.aspx |
| Edit item |
https://cesivi.devlab.farm/Lists/Tasks/EditForm.aspx?ID=1 |
| Server diagnostics |
https://cesivi.devlab.farm/_layouts/15/ServerDiag.aspx |
| Central Admin |
https://cesivi.devlab.farm/_admin/ |
Multiple Web Applications (HNSC)
Host-named site collections use the same origin with different path prefixes:
| Site |
URL |
| Root |
https://cesivi.devlab.farm/ |
| Sub-site |
https://cesivi.devlab.farm/subweb/ |
| Named site collection |
https://cesivi.devlab.farm/sites/team/ |
| App web (Addin) |
https://cesivi.devlab.farm/appwebs/{id}/ |
Do / Don't Rules for Authors
DO
- ✅ Use relative URLs in all client-side JavaScript:
fetch('/_api/web', ...)
- ✅ Use
Request.Scheme + "://" + Request.Host in server-side code when you need a full URL (e.g., SAML redirects)
- ✅ Use the WebUI origin as the SignalR server URL (
CesiviRealTime.init(serverUrl, ...) where serverUrl is the WebUI host)
- ✅ Register new proxy paths in
CesiviApiProxyMiddleware.ProxiedPrefixes when Cesivi.Server adds new top-level endpoints
DON'T
- ❌ Never hardcode
http://localhost:5010 or http://127.0.0.1:5010 in any client-visible file
- ❌ Never embed
_restClient.BaseUrl in responses rendered to the browser
- ❌ Never use absolute Cesivi.Server URLs in JavaScript files (
wwwroot/**/*.js)
- ❌ Never use absolute Cesivi.Server URLs in Razor pages (
.cshtml or .cshtml.cs) that are rendered to the browser
- ❌ Never configure
ApiBaseUrl or similar to point at the internal server port
Middleware Pipeline Order (Critical)
The order matters. Incorrect ordering breaks WebSocket upgrades or static file serving.
1. UseHttpsRedirection
2. UseResponseBuffering
3. UseStaticFiles ← serves /js/, /css/, /lib/signalr/signalr.min.js
4. UseWebSockets ← enables WebSocket upgrade protocol in Kestrel
5. UseSignalRProxy ← YARP proxy: /signalr/* → Server:5010
6. UseCesiviApiProxy ← HTTP proxy: /_api/*, /_vti_bin/*, /_catalogs/*, /_trust/*
7. UseWebContext ← extracts sub-web path prefix
8. UseWikiPages ← URL rewriting for wiki pages
9. UseFormsPattern ← URL rewriting for /Lists/.../Form.aspx patterns
10. UseViewUrls ← URL rewriting for view URLs
11. UseRouting
12. UseAuthentication
13. UseIisWindowsAutoSignIn
14. UseAuthorization
15. MapRazorPages / MapControllers
Testing
Same-origin contract regression tests live in Cesivi.Tests.WebUI/BrowserTests/SameOriginContractTests.cs:
| Test |
Validates |
SameOrigin_HomePage_NoInternalHostsLeak |
Rendered HTML contains no 127.0.0.1, :5010, mocksharepoint.local |
SameOrigin_AllItems_NoInternalHostsLeak |
AllItems page has no internal host leak |
SameOrigin_SignalRScript_UsesWebUIOrigin |
SignalR init gets the WebUI origin, not the internal server URL |
SameOrigin_RestApi_ViaWebUI_Returns200 |
GET /_api/web through WebUI port succeeds |
SameOrigin_CSOM_ViaWebUI_Returns200 |
POST /_vti_bin/client.svc/ProcessQuery through WebUI port succeeds |
Last updated: 2026-04-14 (PLAN-1020 Phase 4)