@@ -210,26 +210,66 @@ func (s *Server) handleConnect(w http.ResponseWriter, r *http.Request) {
210210// handleRequest handles incoming HTTP requests and routes them to the appropriate tunnel.
211211func (s * Server ) handleRequest (w http.ResponseWriter , r * http.Request ) {
212212 var tunnelID string
213+ var fromPath bool
213214
214215 if s .config .RoutingMode == protocol .RoutingModePath {
215216 // Extract tunnel ID from the first path segment
216217 tunnelID = protocol .ExtractTunnelIDFromPath (r .URL .Path )
217- if tunnelID == "" {
218- http .Error (w , "Missing tunnel ID in path" , http .StatusNotFound )
219- return
218+ if tunnelID != "" && s .registry .Exists (tunnelID ) {
219+ fromPath = true
220+ }
221+
222+ // If no valid tunnel ID in path, try cookie
223+ if ! fromPath {
224+ if cookie , err := r .Cookie ("exio_tunnel" ); err == nil && cookie .Value != "" {
225+ if s .registry .Exists (cookie .Value ) {
226+ tunnelID = cookie .Value
227+ s .logger .Printf ("Cookie routing: %s (tunnel: %s)" , r .URL .Path , tunnelID )
228+ }
229+ }
220230 }
221231
222- // Rewrite the path to strip the tunnel ID prefix
223- originalPath := r .URL .Path
224- r .URL .Path = protocol .StripTunnelIDPrefix (r .URL .Path , tunnelID )
225- r .RequestURI = r .URL .RequestURI ()
232+ // If still no tunnel, try Referer header as fallback
233+ if tunnelID == "" || ! s .registry .Exists (tunnelID ) {
234+ referer := r .Header .Get ("Referer" )
235+ if referer != "" {
236+ refererTunnelID := protocol .ExtractTunnelIDFromReferer (referer )
237+ if refererTunnelID != "" && s .registry .Exists (refererTunnelID ) {
238+ tunnelID = refererTunnelID
239+ s .logger .Printf ("Referer routing: %s (tunnel: %s)" , r .URL .Path , tunnelID )
240+ }
241+ }
242+ }
226243
227- // Also update RawPath if set
228- if r . URL . RawPath != "" {
229- r . URL . RawPath = protocol . StripTunnelIDPrefix ( r . URL . RawPath , tunnelID )
244+ if tunnelID == "" || ! s . registry . Exists ( tunnelID ) {
245+ http . Error ( w , "Tunnel not found" , http . StatusNotFound )
246+ return
230247 }
231248
232- s .logger .Printf ("Path routing: %s -> %s (tunnel: %s)" , originalPath , r .URL .Path , tunnelID )
249+ // Set cookie for future requests (when accessing via path with tunnel ID)
250+ if fromPath {
251+ http .SetCookie (w , & http.Cookie {
252+ Name : "exio_tunnel" ,
253+ Value : tunnelID ,
254+ Path : "/" ,
255+ MaxAge : 3600 , // 1 hour
256+ HttpOnly : true ,
257+ SameSite : http .SameSiteLaxMode ,
258+ })
259+ }
260+
261+ // Only strip tunnel ID prefix if it was in the path
262+ if fromPath {
263+ originalPath := r .URL .Path
264+ r .URL .Path = protocol .StripTunnelIDPrefix (r .URL .Path , tunnelID )
265+ r .RequestURI = r .URL .RequestURI ()
266+
267+ if r .URL .RawPath != "" {
268+ r .URL .RawPath = protocol .StripTunnelIDPrefix (r .URL .RawPath , tunnelID )
269+ }
270+
271+ s .logger .Printf ("Path routing: %s -> %s (tunnel: %s)" , originalPath , r .URL .Path , tunnelID )
272+ }
233273 } else {
234274 // Extract subdomain from Host header (existing behavior)
235275 tunnelID = protocol .ExtractSubdomain (r , s .config .BaseDomain )
0 commit comments