From c3565bbb2c1f66db0930bd0823c72cf449ccf185 Mon Sep 17 00:00:00 2001 From: Pierre-Emmanuel Date: Thu, 8 Jan 2026 16:04:22 +0100 Subject: [PATCH 1/4] Fix / route crash --- .../Private/SimpleHttpServer.cpp | 34 ++++++++++--------- .../Public/SimpleHttpServer.h | 2 +- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/Source/SimpleHttpServer/Private/SimpleHttpServer.cpp b/Source/SimpleHttpServer/Private/SimpleHttpServer.cpp index e2277ae..4565da6 100644 --- a/Source/SimpleHttpServer/Private/SimpleHttpServer.cpp +++ b/Source/SimpleHttpServer/Private/SimpleHttpServer.cpp @@ -10,6 +10,20 @@ DEFINE_LOG_CATEGORY(LogSimpleHttpServer); +namespace +{ + FHttpPath MakeHttpPathForRoute(const FString& HttpPath) + { + if (HttpPath == TEXT("/")) + { + TArray RootPathSegments; + return FHttpPath(RootPathSegments); + } + + return FHttpPath(HttpPath); + } +} + void USimpleHttpServer::BeginDestroy() { Super::BeginDestroy(); @@ -72,18 +86,12 @@ void USimpleHttpServer::BindRoute(FString HttpPath, ENativeHttpServerRequestVerb if (HttpRouter.IsValid()) { - FHttpRouteHandle HttpRouteHandle = HttpRouter->BindRoute(FHttpPath(HttpPath), (EHttpServerRequestVerbs)Verbs, -#if UE_VERSION_OLDER_THAN(5, 4, 0) - [&, HttpPath](const FHttpServerRequest& Request, const FHttpResultCallback& OnComplete) - { - return HandleRequest(HttpPath, Request, OnComplete); - }); -#else + FHttpRouteHandle HttpRouteHandle = HttpRouter->BindRoute(MakeHttpPathForRoute(HttpPath), (EHttpServerRequestVerbs)Verbs, + FHttpRequestHandler::CreateLambda([&, HttpPath](const FHttpServerRequest& Request, const FHttpResultCallback& OnComplete) { return HandleRequest(HttpPath, Request, OnComplete); })); -#endif CreatedRouteHandlers.Add(HttpRouteHandle); } @@ -99,18 +107,12 @@ void USimpleHttpServer::BindRouteNative(FString HttpPath, ENativeHttpServerReque if (HttpRouter.IsValid()) { - FHttpRouteHandle HttpRouteHandle = HttpRouter->BindRoute(FHttpPath(HttpPath), (EHttpServerRequestVerbs)Verbs, -#if UE_VERSION_OLDER_THAN(5, 4, 0) - [&, HttpPath](const FHttpServerRequest& Request, const FHttpResultCallback& OnComplete) - { - return HandleRequestNative(HttpPath, Request, OnComplete); - }); -#else + FHttpRouteHandle HttpRouteHandle = HttpRouter->BindRoute(MakeHttpPathForRoute(HttpPath), (EHttpServerRequestVerbs)Verbs, + FHttpRequestHandler::CreateLambda([&, HttpPath](const FHttpServerRequest& Request, const FHttpResultCallback& OnComplete) { return HandleRequestNative(HttpPath, Request, OnComplete); })); -#endif CreatedRouteHandlers.Add(HttpRouteHandle); } diff --git a/Source/SimpleHttpServer/Public/SimpleHttpServer.h b/Source/SimpleHttpServer/Public/SimpleHttpServer.h index 031576c..1ef6ff0 100644 --- a/Source/SimpleHttpServer/Public/SimpleHttpServer.h +++ b/Source/SimpleHttpServer/Public/SimpleHttpServer.h @@ -82,7 +82,7 @@ class SIMPLEHTTPSERVER_API USimpleHttpServer : public UObject bool IsServerStarted() const { return bServerStarted; } UFUNCTION(BlueprintCallable, Category = "Simple HTTP Server") - void StartServer(int32 ServerPort = 8080); + void StartServer(int32 ServerPort = 9080); UFUNCTION(BlueprintCallable, Category = "Simple HTTP Server") void StopServer(); From 8669470c13a415a3fd76d9f175a0deb8103ab7eb Mon Sep 17 00:00:00 2001 From: Pierre-Emmanuel Date: Thu, 8 Jan 2026 16:06:22 +0100 Subject: [PATCH 2/4] edit defaut port (less conflict) --- .../Private/SimpleHttpServer.cpp | 16 ++-------------- .../SimpleHttpServer/Public/SimpleHttpServer.h | 2 +- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/Source/SimpleHttpServer/Private/SimpleHttpServer.cpp b/Source/SimpleHttpServer/Private/SimpleHttpServer.cpp index e2277ae..41c5fff 100644 --- a/Source/SimpleHttpServer/Private/SimpleHttpServer.cpp +++ b/Source/SimpleHttpServer/Private/SimpleHttpServer.cpp @@ -73,17 +73,11 @@ void USimpleHttpServer::BindRoute(FString HttpPath, ENativeHttpServerRequestVerb if (HttpRouter.IsValid()) { FHttpRouteHandle HttpRouteHandle = HttpRouter->BindRoute(FHttpPath(HttpPath), (EHttpServerRequestVerbs)Verbs, -#if UE_VERSION_OLDER_THAN(5, 4, 0) - [&, HttpPath](const FHttpServerRequest& Request, const FHttpResultCallback& OnComplete) - { - return HandleRequest(HttpPath, Request, OnComplete); - }); -#else + FHttpRequestHandler::CreateLambda([&, HttpPath](const FHttpServerRequest& Request, const FHttpResultCallback& OnComplete) { return HandleRequest(HttpPath, Request, OnComplete); })); -#endif CreatedRouteHandlers.Add(HttpRouteHandle); } @@ -100,17 +94,11 @@ void USimpleHttpServer::BindRouteNative(FString HttpPath, ENativeHttpServerReque if (HttpRouter.IsValid()) { FHttpRouteHandle HttpRouteHandle = HttpRouter->BindRoute(FHttpPath(HttpPath), (EHttpServerRequestVerbs)Verbs, -#if UE_VERSION_OLDER_THAN(5, 4, 0) - [&, HttpPath](const FHttpServerRequest& Request, const FHttpResultCallback& OnComplete) - { - return HandleRequestNative(HttpPath, Request, OnComplete); - }); -#else + FHttpRequestHandler::CreateLambda([&, HttpPath](const FHttpServerRequest& Request, const FHttpResultCallback& OnComplete) { return HandleRequestNative(HttpPath, Request, OnComplete); })); -#endif CreatedRouteHandlers.Add(HttpRouteHandle); } diff --git a/Source/SimpleHttpServer/Public/SimpleHttpServer.h b/Source/SimpleHttpServer/Public/SimpleHttpServer.h index 031576c..1ef6ff0 100644 --- a/Source/SimpleHttpServer/Public/SimpleHttpServer.h +++ b/Source/SimpleHttpServer/Public/SimpleHttpServer.h @@ -82,7 +82,7 @@ class SIMPLEHTTPSERVER_API USimpleHttpServer : public UObject bool IsServerStarted() const { return bServerStarted; } UFUNCTION(BlueprintCallable, Category = "Simple HTTP Server") - void StartServer(int32 ServerPort = 8080); + void StartServer(int32 ServerPort = 9080); UFUNCTION(BlueprintCallable, Category = "Simple HTTP Server") void StopServer(); From 8339476ea080cdc520f7ee13e3b61d98e44d7696 Mon Sep 17 00:00:00 2001 From: Pierre-Emmanuel Date: Thu, 8 Jan 2026 18:06:35 +0100 Subject: [PATCH 3/4] fix --- Content/Showcase/BP_HttpServerShowcase.uasset | Bin 69976 -> 0 bytes Content/Showcase/Cube/BP_Cube.uasset | Bin 39198 -> 0 bytes Content/Showcase/Cube/M_Cube.uasset | Bin 8439 -> 0 bytes Content/Showcase/Showcase.umap | Bin 71709 -> 0 bytes .../Private/SimpleHttpServer.cpp | 26 +++++++----------- 5 files changed, 10 insertions(+), 16 deletions(-) delete mode 100644 Content/Showcase/BP_HttpServerShowcase.uasset delete mode 100644 Content/Showcase/Cube/BP_Cube.uasset delete mode 100644 Content/Showcase/Cube/M_Cube.uasset delete mode 100644 Content/Showcase/Showcase.umap diff --git a/Content/Showcase/BP_HttpServerShowcase.uasset b/Content/Showcase/BP_HttpServerShowcase.uasset deleted file mode 100644 index 52eb7011c214e6063e9b1c695273a51db7c14682..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 69976 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 diff --git a/Content/Showcase/Cube/BP_Cube.uasset b/Content/Showcase/Cube/BP_Cube.uasset deleted file mode 100644 index 6a20a4eabb21e3b0723866c3a58ae1b8d0f58e1c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 39198 zcmdUY2V7Iv_xKG%6t@NUh`7MP-VSD1vV)^o#Q;H~A;BadSP|SU?roj8a8zrpsI8-p zR&BMmZok!9>#Sn6TD2+;{^z`RZxTX)pnm_~&+kHV-#ho*bMG1V+;i`HdGFAq?kk^{ zmzNJWC&b!}kcW_CY6PEE)1Nnc6_NExgI~uLJM8!M?gg+bS+^Xzg{=J}`%IG+rN8y; z)D&QS4h{2q8FsVI!^vdl_|e_FS^zA5=%o+C!d;u?e38dkRR*j!> zJ@YfA0APNaSHBble;IVuX6}5ouw9ET01F(p>^~t<`#W#k(rj{Wi`1(Q0K1?5<;}Z+ z3!c=!)IT7J1!>#%bdirj7+&SOryyZOI6uY zm6JGKIVMG-mO2GxB}<(GW0NokObb#1-x(lZ_$T?z2P*Pc8!HBd+f56f zWwAs?C<+Xr}=xl_WP-rOcG7G`S@F%Nw%B08NIP$}z#f zmPV#jkn%^3?%5(ZNSTo#RcHdUl9T1qSeZg0O(mlpyF|9Z!bs@|NlI?CRGONgjLlMw zkcvl1Osgfx)p;@w2@{3jL0j>0*;R=mZrI5%6sHHIqc`ljy zM^Ri0eFSl?S|iOEC{?MkR}(b#dQ_mAkeewb4Vuoo+7K%#Q**-=YK=sZA|?JeH=g8y zO1YNVCKg{7q7IW|!2DFQRB1?-B8B6($-i@kps@xjbI35S)bn-mm>T5KcFlxn3xTl% zB`TQ&JC^T+Mvjt_{H0^h%?o8cDE3BM~Vys$6nrQDy;lBv~w#rv)j2;T#P~ zzBX<<`hsK_6IpVJMjD%*tCppx$@(|uaW+^mP^Qk3$Yo=tpny!J0#ragpXPaqV<{K# znf`7^_d4hX6@nykIdYQ}1Pa$kgL4&<3|UGP9731nOe{(9QcadhF;D_(A)|MVZG<)x z1V|&4(A8(-7aYL`7$91bAtkds2RCS<2NWw+8ku4Qv1!`==lTdwm&sFkn_DKc*@IjK zDdln*Domt6X{Ew|{%1Q{lePf5pC*$_xd!Uh?Yk0{qAiSY?&(^ff}R6N{+YMw+f9~D?5G!xV-sy0N)Z7X@V3y5^zt>ZMHj%qa`RN zIyfmB#7#<`xjM8*NOj^Q!4bz^SRxiWuH9{;ldu=4`~K2g((pjm5G0D{yu?L!#;xKo zq-l~YxrR(ASN21J1@q^jDoJKKijtIEzn!gDAWo4gr146nhU}ZM(h?;}YiJ9&TE4OS zZ=wEZA>U?`qfgvW%c(H5MJ8i>X<9|MYavD z-wEX;%7(^;TnEYR7ag{79Yz>9I;l#E&St}!YoDVTNOPnqWL)X1)~IAW$pU%H7T?^A zPEW+24@j1(MxdgTn15*_@sOZb6Xj$o(GQ9#^N;KNx{&K_buTjMz zDw$M~D(AIle&l$4>=pB7Twm2B*ulOps)&Jg{av5<$`&hxf?27+CQ|wFF}3dC1TbJR@gKeao$1qvW7a+wt{hJtNSuMM~6~ zih5O(2JOvGq41-m86X_4t$*W3Tj@X?)fpXj>_XOgtXK(%UPH#;&Fh1P%L8>Bj^Fi- zA4-q;Vs6qS@oCL2qCG?@Q?uk!n8PI+S+>y6691N0iWm7PP7J_!gjSBO#G*A z1P7FkVce?8y5dJWaCG7L<2rtNi^b;*5UW%VCP#*RVx|Z9kf=iLOVM><6*c+h%`!Q* z%Q>AV=0_T$Q7SpRCer?k%TZ0#%$ds%xV)njWy6EH5i@IgTdu<~+?*tla{?2dy~vHO zm@G|ZmIkMGZu~dMm=}d+!RA0VN2tlQU6;RW2PLtRlu?oq(nw_r&Ojg|r2+}6GbLc_ z%`~~6pkzS-0E6j;Yb&zz&W5ORUM;*iwY;)^2nvjj_J9-(xa$6)1IFQW$&E3oDnW_k zfit)eq(>6g^jXT0r`(3fB_q`2vaYwRS3|*GG z1(Ty9k1c4Q@zPAWEQMo1H};hWrp>@MpfFmgk)`G02q9L>&duYY{Pe?{Oi<@>8GHjg zl=;7L|3*$lhV>`ZwHmuZ96#u(dF{4n5IP8JizV68)PXYTn3%LQwNyjK{qR??7M`e7 zW&~s?v%s8_n$P?Z4M3cdF3pgT^1ai?pmC@nbRbDRs+1F|M1H9 z$>?YJFdMj4YgAcWbR*`16=KsPUWn!-R;Fq6JZJvu%d2^CmMTTctbzQ{V?!ufnOFnT zONo-I(@C=r{S%O9u|}mG6}=CsI%ALd#>j$>iw1MVxVE)e&Sd#3G=&5Rezd^veKot0 zJ59P2Lc8r}3Q+n9=~)@c3W*Ft7I61pMY`=kUz(s)$`fRnWM`?>w@BW=XxhsbdZS6} zz$~uwDZhS;Rp7jCEEu+$wC=RVjRS*=@^shsXjtY)atuEq990<+VAPJ`1V=6}?={XY z8?kTT47ia$+2wm~24c>E1Ae|}{3Yxe1L{1~g`RUmI<#A)H42v3 zH7Rauk&14FKXnZz1DxgcP~A@a4CWLlfdEpRF3FUtx%Ctox%cULWX6eCzmqN$$JvM6 zy*w@$9WpBpQmUi_c(WkS!+Z5Z@vt&FNlx{j63#VADMm}OW#Cf4J@8>V+5B~9Cmg1% z-T(zePjXQz>1naJZa1!=`ZZt_zXZJTef=O5H19Hc{nF_}99CKeh>ee1LoVjlt}ZH0 zWDd(RdtpBynokN9MJEjmhz}14j1-aa%~GDA9YTRNHY7tHdJ>L4AMYmxk?R}J@8_aR zZsDXElQS1}h(TUOa$RSCdJg481FobbzQdpWG-N(bGg>g6>4EaVz6;7RtTc?@D$@O8 z{NymS1sWF-3uVbrKI-8-CGQ=Q`n!^^4=rhkgOrO=xH2+yyYr~uMMd{_ zMW2+!77APx^lb6EpHLpOj3YzTQxe;t@1#IRhzpI#va^=mkvCe%>^c;jnx|^s0(1|N z5Ku{A{K&!G+XSgY(2A*IrA-r;VCS@6=Kh!exS%E(fGt$$`h|Sk=2Ux>y{;T)oHU$= zKAf_&Ek}y3w#dzblKChku*v{1yQG+8SPG`drKBt=Jrnytja%CPz5sa})4T z&P?Xj$q(`7nMiNGiFgZ5#9MA6-Ubu#Hkyd{g^76EOvL-jL_C#=csoqMy9RpOYy#dN zfcIrJc+58c1w5$VoB?X(R2#yS)5aQvni!DGB-(Xv~B*To3lQ-D)2m+8B4YYa^w;eIho zxL=JQ{lw0JR0Udy^8{dMTMT~@J;3QGpH@7_1_nbi$g89OSdTVt;xC|e9Uz}bD~dG+ z1gkg&Qrdnp6r`!2meLa!$VK${JQK1$qLE``^#9Ro6T7>T*2BPIKRs@pO%H0wOrbx4 z(m?uK>G8#Pp#MUz|0t_|lqT{rgvx*N7z(T*GuD5ke}}e#^qG%B(yXnkIW-Wb#m4Br zrnC{o5cK zo2fNX=F5%If2l_w-N70?`g5=$NP9o!^P0Ym(J#}ZkK(|XiuHdV?SFsf_-kmuRQgC3 z<^P(}w_*6g(z%K}o`UR9Yf z`55az8^4XIBEMmiT2+K8+!+18^yGv6#;K6WC!f~)fh~&Yc~zM)`u7azFQJvuesHW| z3S~h4w90Q|^l{9hUNJ}i&=fw%2ZQ5!7{?m&gnRm!upB=~5Akrx*bqMT;Dh@kxIKsX zXn!bcq=ERi0UzObj`a{9>tY?OkL8Gu=U9exupZ*zxjs$S9+qPr#Kn4euAi_DF4{3~ z4j+b(%Wte_10OtY1|KZ@4f=rnfJ0rv$^eUkM#}$F{s(Ci5fUCk1OUbh{-pde2_p6D z*0ru{Ro}Xvb;Abr8#Zm*tZC!MP3>B>wrT6oxkq>V&fU88a`pG><=oe~TQ~1WpT0q& zu<)=Ro-qTWLlXQ$!$e3#(4b+%rj46+Y}Tx!$g!KFsMe|cAZc0``(!S#BW6tn=1m3V z-;)l|PfG!p7*7H-a|_ElR(0!H*9U~1O^BJm+}zB<+|tqlv@FPja$?ccvROx$fI1(< zNv!Nf+qh1cySi?t!0m@@<4-^A?3S#WSkJn7iVBny^A10=xO4CN9%SNg-S=nQ9a>q`ZJZ0*%Pd+W2H-EvxMT?hwwsg(fb?b{a zY}~Z@s~sgfckTZAn>~lW`~Jw$V?X?O{LI;N=Pz9R&##xRUB7Yj*6ly<+%0|d&*LXg z|9$rSMH%vie6qxIX24fd;LFUy!ra0N`4X6ofsc7p3(Jl!b(#glSxH8JVCOoau1(*N;y&^B3h+PZmX_iJ4qA!{6GrZG10tvJ&%rsL}pX<#k@<(W4ne&nCy_G=2P zQ?lI4;6oO~iAZ1H_%q!i5=r7H%?9z1^~AN%zR1ey_YG%TZ0%QI4cML56xx#w+pZLg zFFrVBc3NaZj^2yf;FXv`Y;M9qw?vX<6X##|s^+Z2{by0G1xmsS)%bYM+R;yotj-Qu-}T15h<=KO#Itbx>ANAP z@A@}P+8?t{D3}}dTVA^0iP)<{;?Sc7ZA9TEW8+H3##(5ezAOPU?(-U165qnK8zDFD z`I~1IpFQ}S&-zRDX1=Pd4H@khOwMQa>;)E^z#F0mcmre4D zLKpwWYZlui7c^U|C|-ZWW!g#q2Hd%=uXtnJ5l4H0!?rUk3P)**>cq#N_BVT7n&&e9 zX}Etqkxi_b+(vFwYA@Jp+3NDa4dR&J-HF0|?@Xc1!{UM_jt`=o7IhE1(OI)8xaU}h zR~yX^EV946dv0R$vW$}_GA8~W-sW`d($muqmHqa-UhzkdPnD!LzA&flGxvQLQ>?yI zHi`HyZ*xfF?1lNOw|bBNpfqE)XX$yX9WH*y3;H~C=+io>$Gu@|I~)$0@$F_oIZ10< zP7>t@>aFiky3_vh>pMTZDK6;q-SM*1w+5~2Fr~$nZ5idHN&ev_<84a&ZtIorSq={I z@ya~=+xzRjvOgc%e_2pDF;~9nx@5d<>5VsumsUM*g(!dcJXxET>+!qa;rpqL8Z>+| zznpB1?J#xeKeL3NyzXKnIFhSbIrxj8UU@wtH!ibU_44_F8*#e}`uHDs+$jIhgf}GzZ>eN1dnXOG`L_N=yPxm7 z{!vc$OfDzgx4db6e)W&@qxK|i>FKwgq{!PpS!Nk=Vp3#Lou<2&Mjc%aHfk>z(_y4n z>kJz~FPmjk+8iO?;?a*|TZ#*Q{Gq7P-hQYa7Vv6wv!%y=JI;u$FqCp-x+Y%z2Jvk4;N3n-zfRaYQMkdm6KmQRySI; zVaW1B8!m^0YCa8pvguAy>fwYA-_1U}_~)dc*f{?WUYxj-{&?}Jb2hP-vpxEzKmOq2 zlg&@)vG_vKx}y3+7Qg)N@mf_m$r+zDu#oKhCV!uwub0!tSEV~`1S1PSj}LtobD^Ni zZw_AZ@v$9MBYg^AG;8s4Z}j*j8_q`!*d_CtdAI(mQ>Uzc-ZA@kuM0&U?k692*y=x6 zENJs!>8zE}4=lTW=ihM6iZ9Q|c^_cEY3-fvO~s*S3i>)-3rda(&l}MA)~ZL_!nZj- zANc&---9kR$xnRR+TSKlWR5Pu=x34N-sk5A^vu`1hA|r-f2w2mse3MK8jAM!TIcut z?&nWGyY6}U+R3nTa(2gT=-V&iyc|5N#MsBSXUeUOn^Rv-gwbphE8L>A{W_+8X=hMYvmVJ`jvIM-T&Inz%F?V#?adEK zEw*ngT)Luc>5Q{xLT8n1Oyk6XFN@a}Sv_c9vTWK`*FpmBt;o`5)sg<#tzTcc&sP@O z=I{TY@L%6YNz?3Cqc`Bbosx$N9^10w3n*6v6ovlB0g=(P~qNts%04qtKsCsL6t6NOsY@ zMFq{*MK5f*NxYt9^&`EwYlc!iuO4V^?s*n#P~~cXov5>NDGrw5Q)f%jg4|JbOX< znnH^%nSQoiE*F0o`ugtRH-URgAJ3lN>ysx(p1O8;U8kVW{ypc?R$h@!UD80gXQc1k zZ|`orLttVRTt3<6q-P07PtTs~{gexaf7Rh>k2jq)uU_{!T0Cca=jHR#&AO^19n-rmi?satfkSrT zNSMG#*VBK8mxwnO)xER+Qu?KILHFRhk(Xo#@BeYi;!#`YeovoxE_D9-jQrNH+16gS zEyvyYN-%Wb;zw2=o|Vk9T;wB}8E6;Y@`eB19}cav+7&lUI_lA|;Ro&}Y7}`XbGF@4 zCtkSv!IN)n^446s-nDP`wSw0o^WI~7tekYLUx(!dPUq|Wb>~Fc4co05n+Ff`ygcf1 z?y}RJElyePvHy9jF;mvb!R(^n^#eACuAOjn>2kB^MO;~aN#21~e@5@}s7%KT+{&8(ikyTvO@AkjLXa?seh*a*AJvsXF9EqP4wWgqJ z$n_O_)`4x!h|z;lRos$8Epa z0TY~bzRiB>@G~jzk*QTbUppW0{6s)yZf4l*}MtaS3k>Meb2u`$g!TP zqV#ox#HTj>;9mCPaF1__GEYa``EK<+M_QmUI zyRFJDOuX^>`J-3cu?Oq^)9-BYS}%3mz4?I+$=Cs&Wo7N$VirBPwd;trqTieEetYtT z@8#=?xsIp%3~Dm}+`THJ7I(f@k=3$t4EkbKa=!K%%HOa02piN{6O?d>1+ zy7-Cmr?V@zcWWBlxUS!^a~JzX^_)3BZhjszyZo@eJZ!zae%*%get1--R@resq-OUTQ>}I$A zo$N?ROZ`%VJMy@i+S?MkIuo*sZu%o#eM+t1oZWW8->%`PYZ6!gxRTaFxI0WZNNmD~ zu_CzotjdtcxfQb(M|aB?)Z~i7;kH>7+%2drQFCi;dk1a_4yF9Pm(o=3u0Xs>ug0ns zo96De)9*Q6+Av@{5kOTjQxUbBiN7jv)ZT*8joZJ_zfTRMs%=g0E*MAdE;eX@yL*b> zX5+}+;n9uTSBQpNU-0fhyb+PVu?*!#ns#0%f;E7D+^cSUCZ1(`M7-) zB9X)W*r>G-Ss<2>GPn|E4m%R~Hv_g?Fdxo+^Dz9br#){;k3z{vqJ)bD5%3*EGDtQ_ zBcq9$gJzLvk__-7{dgkAUro$d+SURpamQYqoEyVXbEj3jSM9E z^qoi)C($(M1>EAzX`8nt>-WSp>vaV17zk~sp(WHw5HV<5mPc(CFFYNU$`eo))SqZ%nz= z^@G_*Wq&V#Eqs2Y#sGC4uZCWXjb{gt5%wYtF0twA>RNg`j+v)H+ER{d0bI(^^^3uD zqnIx<(~bz8$B86vTpzKHF^vt^YFPj=6HiB{&yHjq2?Z~P7LOhrd1Y2H9@U-#UmL6C1BgSnHy&98ZAlD1@Exoz%h@)^MXPH58ln%#A5=U)U06_!aqOr1O zwCr6q#oEyMU?v@1`^L&XpzZ54$Rw$gsQ{u>o&$Xy>W@VMjdFCJP$#R}&5g`cGm8rY zosR_D6TnJ=??dGhrp4-cu%q?8i3f2ft}s6Y5>GhxfN0AF&b^2)z=FZ^xPzsM0OC!2 z;21GH0oNO#?trPY&Ue)r^U654F<+?DTJ@zZC^yyf%&aQ}B&hQt`t1!Ts8gM`-jyfj z9m2r+$AbTs0c~TjRwnhIajEM&axxM;0FFH;z1d(mr@>sH+L}^+S5BC>)^U;m?T!V$ z(qQ&VgJS{QLCo7^bvSJ(PW75%v!*_Oy7mO5?R(;iS(UEG`f*bArEHe2o)ah9QwQ*j z{Xi>DFlKary}%BQL4%A!1C2m&erx}pq`_+zDnR&~-~ag_cH zr;Ad;fI=3`=s2(IJhX1~V<|=`6*2VV64p{h42(vqmjdG=7$l7`w}5mpiF+H0rO(fB zPEWXsN(NdeQ=TsY>1q;9rZ=1kLtsV}!N-f6Lp`}UG!(|U51m61;tE*4@bLh65a7AO zpAUQlq?<|YvC*cBTOvS@82LGY2hQSbdn7=jffEhPH2f$Y&0*l$2tBmDNi9|MSuRF> z7DAB|_SXw|>IY{|z@w`kv?`zFU{X&i>l^(Y{#9=$%ziWV*5d-w!=$=wTo|shLqLXn zESpvfiT5=xB#(=X)bXWwUPX{AKes@s-7H&#!SOlR@MdvYb?AL6|#%So)0T`{;OoQz^1_G{o zt!e}TwnwdM1Ov8bt!kh>d6`s$X*Y$7IWu6+MK6cG4d*qq5^s~}FxyWdgTXd5T!etT z%Q!RgF#@i!d?+nm!uV}VA*Qa7nTBy+dL-B*S~9;fuI!zA125PEzI_qI)=D_WI_T4R zDDN9GxLtAF$;4f7e$R`|M*1``^3kW#u@aq*Mkx7G9;^4TOcE7mRNTGIfIq|i1_A60 zm|~}l3pemcq3{<7w&wQ$O%1ae zzgi72sV!KL^WLDNPs9IljLyTSpy|_&4XV7ID=0cu03r}5}V?G$?9W}S| zh_ZI!8{um0cQf@3JW;@&h@ZqL#$?Ea5N*dJZZ&E!r=VC0H#pzlJ zJ=I_1Mw&#&o?_Kr%K9^1#TiWi*SL7zb>D1eGIfr|k%E85^jmeyy*UfTwLX8f4|m}B zIFrBn%Ug!Nl-QmXzgvb9)Ya^0q;5qSN7G)iac6v&fLU@VH(!ci^aat`GnkuEJRr{U zff>dZ;v}4V@ErGfJ>V0>edCOZ9w5e~_Sn89&yzk!)ypE*B!p3j6yK( z3gT=A_cL(cUjUZRORRcZtW9iXxbD@(Rs&3Gi_Imv*oy5-V6Ka;bUPCWWjhvLfW!WJ z0gsh;WO3JFAnnP!##ZdwlwpjF`<~U64XV^W^UV6utNzst-R_v~ih=Q~c{qdOItu+A zyE}rvs)+P()qyjW?z)y~*n?@0tG5&8udAZj5$sLB4`{ zfPLe~kO$qp0o7wAnZyaZB2;~Z!}DpZFCW7mn=^cT!8Y*Ng*&zbyRjoZ;p0Zn-RZdp zJ@=&NUi93Xp8Ig;X+%QgVB=Dbh6`=MndFh76vDStu}!=N%(sfGYU~sChqa7WT)CgP zmSuHVUvPvl7~db{2f0L!&>!=(aW|a7SbI1FF&N|3Roez$qh@tk8#vZ@7^~@KRHANN zySz-XUF43{U@hU8Uia)s+L)q4wtuZ<8=8l9WFoijN|fUh|7AxB&aX@ie(k$ zkNbF4_nR-%`73M(sbO!JpTL=w**en*u3{LB*`|k{U9-Bzd<;gveBJ8p-&1SNm3@q- zws*KM$y2LpOt4a3?kG1N!p5GP7Q%C)lLqQt-+Nb-3!_u@SbJN_xIbA_uPcvZ&$r|Q z<0iw_JheJ!Qu5SlymnIZ)LMm3PPpG%Q3sW|@zQF)cI{z=Xvhu5hZWoN(n`3t)N9td zFSy@(JNmrzv}-Jms##iZJ4XI{l;3Xjd1*&c zO**dVMR0e>&|cq{wR&sEkZ$ZTx#`9=-#YW`EUv4Gi^`VjtsQwfOEnfJd22^w^_Gge zCVbzjpC`Pvey{R8VSG+t^8If}g^xsx&FMJv@KUchL;o)#B$NOjHQF5 z(!|y)t`fcV<^!IGnpcV5+POhDGQG8)8zqSC*a3w3qUuK`O5Bu@iCSfNtPSRWjE_uR zDX-smiPm(ItSnm}(066oq8;-6MJvW~rd@soz)Pv}{EkF=>B@Xi)0P|2S6r6W4BlYw(LpZPkju{Nx@tRr8N0@nKc( z`V&q3u_XV>2<}Pk`afR9XG|G+n*>1L<4;7Z`?01eKkMxby@AIa`{6Hb@tIecBzy+@ zqkLiy0VDWSQ2aS4rf@#fJ|T?zK`MJHXr-F?gH!fwG<*gZCX^K>hRn5(4+#t8!2H9y z@X#nC{`6FAfOr9a6bmVb&v=d)5(BQLNce~_qiHII#?zcNj}O)2(j=NQii}bSg;&a+ zXjZT6=-eq_dsyzQ_&+y(GtGd2h@QJus!0LtX`F-U`R|60D`N#!5kPnVEo6@l#UGG! z2}Q|2lD!3mu%~A_(sNz~_yD&4GBv!}gT8|TB}1Q9&tb6RR9dZo=2{7&b}^;%8L1>< z#>WVXfOdn4QSjnV3F$-+Vrb5cs(_v|-Ec<5kQlH(MMB49Gl<@Am_`WWV&Rpsl+Si#K2I>w2vrObmuSOw-X)Ri#x02v0A z*f{!B52xBg1ugZbIcpV83;Y=4weA`Uq}E+)>EF8jrP1<(n!jvk^uC;Z(4?+?O#96| zptk>Ln88&QqW{7niwUQ&iph$eGEFd{R_UA^x>(w#|CSW7+~Mp-vw5SPnB0(#iV~~T zK^&Lkt184U=u^RI13Qg_7|YP~SobhKz$73-n)45DBtrgNkJ1$&!#dK4L*}cYzVO4G z7dFE@5yJ7@0={|aYCDFHp=RW|0177T#aogyd}=3q(lIhD<%rXs)SXP8LDSw8hRw00 z?Hd5Fw{)h`&X8LBC`W;!IA5ywJ%k<``c!9z<3tbe{f(Fm5nXsNyd{$! z7&;#2rQxnSKDDPg>*Fwb-j3##G8u(1?_@Z5xnhRIs4^-e*@0os63vG6P}BA4WGNc&Rch$iHC8@4JPd1d+co2jIUdyUV9ugsjL6C zGp*hF>UUQE7+U2L4x(^+>_c-l=rG5w>7Hh+rNCIgC&*&bufo{mOSDz+MGHFtb_70n z_ZETmET7N`48u#x{1a&rh@e&igfQoW9d&?@Ay%8t0K~+N8X-Qawj*n^dEzjGc*m<4{^=wx37e$LGk>wE=e!xHPDjak$e3ko2oiM5EQ?CI`! zjPhv)pJ9o^xVQPV`y7FZP@B}Ps})ob05Rq88Qem_r)Zj2%AzQQseu^~`5QQhq=oS` z*EYi>#X38HA~5}HsXT;&fmIel6A84Cb-2bcWVf!o$GIgdgD0MR8uzEeDehIvlm@43 zJjUUhxpsq{)zVgB^V<2v#awaCHU{g^H#@^i^6tydRF*q zghQ?|*jT-aMmQAw_c=rpkG$yl>3#LKnAyD-{+xZnb~tv*6b>B@uYcU*nkM{HkDObL z%s-Dq4h>g6{w_GsQSq20ZBsUu-N)Q>q+=!tgYxk_~UGOzl~*Sf&=js{rAhwIigd zLWv?(7(E~|QV38L_abCzsv|snjCQU{Nmg0F*n%7#yEFY};0lT|MVwK-AGPj$yD)Tm zSxEYi^Tw%BoQ5zBqYk-NoVaEaEAjn}LiVOKYjyzgrSD8L!Mq;6t$A5O54d-jvZt)q zn)!>42X4;pvNyUoPuABqwEF{O-VpW?z*y2Uj}aex@u?7Z=&ZSII=K0oPgSa~$^zB| z3w9>Pdao@~=A= z()Z<6*08|PfnWfm*ND!uQ~=g+!ckyz1bW$DiZ^Y4G%zphv#EJ68W#7PhxMzo`1cnp zAU{>c3Zp3>Ow(1y3b8PL-*2qY`QC~rQ$jwCTpluK@s*!SB3T!(M`%l!jLlERVE_AA z0d3WA&PNWa(=nDKH+v&&wn^^HiY~c1<5jOWCx12u``^V1*h@^NaAIiX$cZ7W_A!Ag zP@yq_p3kmnU{{I^-v7Wh=AcX!Rohb^6m1Bc9bPi~VAP6DKb4}W3}M5O7)@GdX9EE3 zn~mSQJI4T<-v)m-e~#>APdI;Exu`+N)}np=N?XpC8-q=x>|v&55!ZOUBj;b03IQOz zD^ z4$a?wfrq<=RXT0ppG%B+3{WvO;4|$v{&<5=;WXDS{qXf+%*j@+R_k?N!f_YPPclLO zNiANVb^X&~;A@OhHOh&5Lx5vCJSmS)-5@iqRSy6EWT#Ps>;jEen?jBs zLeM*c=&kDsyTeLHp$6kf(a4kvp_+TM0>5KRw|136b*5yDLYSh2cTFfjRiF{rwM|tD zm9Q185~^X_Hq((K<*!g`q}&2gn5Bl@UDzZJQb}Q7SbM{uFb(#8u_eUUDbxn~Q=uRH z8y?<5wRq=C1xjzvQ7yRPMnV!5Zb!%igI&E{T!P%)y#hUhT|EPRTs(X{McyJWXRkn! zcTh0*HcZ5?Ix?cvDomS58dD;lal?r_#FyXNQDCJ)oVi-k!d#knp*e3OXyM`@xO50P zyN5&n80`g<$#Y@(tDpsaf9w~rH%9*L*u?VLVSIhiLq3bTsDU$ z{(p11!_j>2_<)GX&-2EH)<1EuN-mkSP2v*okg1YO^LOU5HB|*t!o*a;%!adN+`zB3 z((^nX%s=vRX29%Co-Ler&-k@Uap1&@Nnadt9;Cgy&SS6)0>|FppGF?rvI3fC|Lz@Uar}UTGd)NA{|B1shcN&E diff --git a/Content/Showcase/Cube/M_Cube.uasset b/Content/Showcase/Cube/M_Cube.uasset deleted file mode 100644 index fb5c04e733b3305e981dee73567a098c10d156fa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8439 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 diff --git a/Source/SimpleHttpServer/Private/SimpleHttpServer.cpp b/Source/SimpleHttpServer/Private/SimpleHttpServer.cpp index 73c4862..1e291df 100644 --- a/Source/SimpleHttpServer/Private/SimpleHttpServer.cpp +++ b/Source/SimpleHttpServer/Private/SimpleHttpServer.cpp @@ -14,12 +14,6 @@ namespace { FHttpPath MakeHttpPathForRoute(const FString& HttpPath) { - if (HttpPath == TEXT("/")) - { - TArray RootPathSegments; - return FHttpPath(RootPathSegments); - } - return FHttpPath(HttpPath); } } @@ -88,11 +82,11 @@ void USimpleHttpServer::BindRoute(FString HttpPath, ENativeHttpServerRequestVerb { FHttpRouteHandle HttpRouteHandle = HttpRouter->BindRoute(MakeHttpPathForRoute(HttpPath), (EHttpServerRequestVerbs)Verbs, - FHttpRequestHandler::CreateLambda([&, HttpPath](const FHttpServerRequest& Request, const FHttpResultCallback& OnComplete) - { - return HandleRequest(HttpPath, Request, OnComplete); - })); -#endif + FHttpRequestHandler::CreateLambda([&, HttpPath](const FHttpServerRequest& Request, const FHttpResultCallback& OnComplete) + { + return HandleRequest(HttpPath, Request, OnComplete); + })); + CreatedRouteHandlers.Add(HttpRouteHandle); } @@ -110,11 +104,11 @@ void USimpleHttpServer::BindRouteNative(FString HttpPath, ENativeHttpServerReque { FHttpRouteHandle HttpRouteHandle = HttpRouter->BindRoute(MakeHttpPathForRoute(HttpPath), (EHttpServerRequestVerbs)Verbs, - FHttpRequestHandler::CreateLambda([&, HttpPath](const FHttpServerRequest& Request, const FHttpResultCallback& OnComplete) - { - return HandleRequestNative(HttpPath, Request, OnComplete); - })); -#endif + FHttpRequestHandler::CreateLambda([&, HttpPath](const FHttpServerRequest& Request, const FHttpResultCallback& OnComplete) + { + return HandleRequestNative(HttpPath, Request, OnComplete); + })); + CreatedRouteHandlers.Add(HttpRouteHandle); } From 14a67e44ef09bfa02ac0d348315982ac86658010 Mon Sep 17 00:00:00 2001 From: Pierre-Emmanuel REMY Date: Fri, 9 Jan 2026 09:24:54 +0100 Subject: [PATCH 4/4] Fix "/" route crash --- .../Private/SimpleHttpServer.cpp | 160 +++++++++++++++++- .../Public/SimpleHttpServer.h | 6 + 2 files changed, 158 insertions(+), 8 deletions(-) diff --git a/Source/SimpleHttpServer/Private/SimpleHttpServer.cpp b/Source/SimpleHttpServer/Private/SimpleHttpServer.cpp index 1e291df..ad5010e 100644 --- a/Source/SimpleHttpServer/Private/SimpleHttpServer.cpp +++ b/Source/SimpleHttpServer/Private/SimpleHttpServer.cpp @@ -16,6 +16,34 @@ namespace { return FHttpPath(HttpPath); } + + FString NormalizeHttpPath(FString InPath) + { + InPath.TrimStartAndEndInline(); + if (InPath.IsEmpty()) + { + return TEXT("/"); + } + + if (!InPath.StartsWith(TEXT("/"))) + { + InPath = TEXT("/") + InPath; + } + + while (InPath.Len() > 1 && InPath.EndsWith(TEXT("/"))) + { + InPath.LeftChopInline(1, false); + } + + return InPath; + } + + bool VerbsMatch(ENativeHttpServerRequestVerbs AllowedVerbs, EHttpServerRequestVerbs RequestVerb) + { + const uint8 AllowedMask = static_cast(AllowedVerbs); + const uint8 RequestMask = static_cast((ENativeHttpServerRequestVerbs)RequestVerb); + return (AllowedMask & RequestMask) != 0; + } } void USimpleHttpServer::BeginDestroy() @@ -64,6 +92,12 @@ void USimpleHttpServer::StopServer() if (HttpRouter.IsValid()) { + if (bRootPreprocessorRegistered) + { + HttpRouter->UnregisterRequestPreprocessor(RootRequestPreprocessorHandle); + bRootPreprocessorRegistered = false; + } + // Editor will crash after receive request if you start game from editor, close it and start again. // It is because HttpRouter lived in FHttpServerModule and don't be destroyed on game ending. // When server stopped or being destroyed we must unbind all handlers to prevent errors on the next game start. @@ -76,15 +110,70 @@ void USimpleHttpServer::StopServer() void USimpleHttpServer::BindRoute(FString HttpPath, ENativeHttpServerRequestVerbs Verbs, FHttpServerRequestDelegate OnHttpServerRequest) { - RouteDelegates.Add(HttpPath, OnHttpServerRequest); + const FString NormalizedPath = NormalizeHttpPath(HttpPath); + RouteDelegates.Add(NormalizedPath, OnHttpServerRequest); + if (ENativeHttpServerRequestVerbs* ExistingVerbs = RouteVerbs.Find(NormalizedPath)) + { + *ExistingVerbs = (ENativeHttpServerRequestVerbs)((uint8)(*ExistingVerbs) | (uint8)Verbs); + } + else + { + RouteVerbs.Add(NormalizedPath, Verbs); + } if (HttpRouter.IsValid()) { - FHttpRouteHandle HttpRouteHandle = HttpRouter->BindRoute(MakeHttpPathForRoute(HttpPath), (EHttpServerRequestVerbs)Verbs, + if (NormalizedPath == TEXT("/")) + { + if (!bRootPreprocessorRegistered) + { + RootRequestPreprocessorHandle = HttpRouter->RegisterRequestPreprocessor( + FHttpRequestHandler::CreateLambda([this](const FHttpServerRequest& Request, const FHttpResultCallback& OnComplete) + { + if (!Request.RelativePath.IsRoot()) + { + return false; + } + + if (const ENativeHttpServerRequestVerbs* AllowedVerbs = RouteVerbs.Find(TEXT("/"))) + { + if (!VerbsMatch(*AllowedVerbs, Request.Verb)) + { + return false; + } + } + + if (RouteDelegates.Contains(TEXT("/"))) + { + return HandleRequest(TEXT("/"), Request, OnComplete); + } + + if (RouteHandlers.Contains(TEXT("/"))) + { + return HandleRequestNative(TEXT("/"), Request, OnComplete); + } + + return false; + })); + + bRootPreprocessorRegistered = true; + } + + return; + } - FHttpRequestHandler::CreateLambda([&, HttpPath](const FHttpServerRequest& Request, const FHttpResultCallback& OnComplete) + const FHttpPath RoutePath = MakeHttpPathForRoute(NormalizedPath); + if (!RoutePath.IsValidPath()) { - return HandleRequest(HttpPath, Request, OnComplete); + UE_LOG(LogSimpleHttpServer, Error, TEXT("Invalid route path: '%s'. This route will not be bound."), *NormalizedPath); + return; + } + + FHttpRouteHandle HttpRouteHandle = HttpRouter->BindRoute(RoutePath, (EHttpServerRequestVerbs)Verbs, + + FHttpRequestHandler::CreateLambda([&, NormalizedPath](const FHttpServerRequest& Request, const FHttpResultCallback& OnComplete) + { + return HandleRequest(NormalizedPath, Request, OnComplete); })); @@ -98,15 +187,70 @@ void USimpleHttpServer::BindRoute(FString HttpPath, ENativeHttpServerRequestVerb void USimpleHttpServer::BindRouteNative(FString HttpPath, ENativeHttpServerRequestVerbs Verbs, FHttpRouteHandler Handler) { - RouteHandlers.Add(HttpPath, Handler); + const FString NormalizedPath = NormalizeHttpPath(HttpPath); + RouteHandlers.Add(NormalizedPath, Handler); + if (ENativeHttpServerRequestVerbs* ExistingVerbs = RouteVerbs.Find(NormalizedPath)) + { + *ExistingVerbs = (ENativeHttpServerRequestVerbs)((uint8)(*ExistingVerbs) | (uint8)Verbs); + } + else + { + RouteVerbs.Add(NormalizedPath, Verbs); + } if (HttpRouter.IsValid()) { - FHttpRouteHandle HttpRouteHandle = HttpRouter->BindRoute(MakeHttpPathForRoute(HttpPath), (EHttpServerRequestVerbs)Verbs, + if (NormalizedPath == TEXT("/")) + { + if (!bRootPreprocessorRegistered) + { + RootRequestPreprocessorHandle = HttpRouter->RegisterRequestPreprocessor( + FHttpRequestHandler::CreateLambda([this](const FHttpServerRequest& Request, const FHttpResultCallback& OnComplete) + { + if (!Request.RelativePath.IsRoot()) + { + return false; + } + + if (const ENativeHttpServerRequestVerbs* AllowedVerbs = RouteVerbs.Find(TEXT("/"))) + { + if (!VerbsMatch(*AllowedVerbs, Request.Verb)) + { + return false; + } + } + + if (RouteDelegates.Contains(TEXT("/"))) + { + return HandleRequest(TEXT("/"), Request, OnComplete); + } + + if (RouteHandlers.Contains(TEXT("/"))) + { + return HandleRequestNative(TEXT("/"), Request, OnComplete); + } + + return false; + })); + + bRootPreprocessorRegistered = true; + } + + return; + } + + const FHttpPath RoutePath = MakeHttpPathForRoute(NormalizedPath); + if (!RoutePath.IsValidPath()) + { + UE_LOG(LogSimpleHttpServer, Error, TEXT("Invalid route path: '%s'. This route will not be bound."), *NormalizedPath); + return; + } + + FHttpRouteHandle HttpRouteHandle = HttpRouter->BindRoute(RoutePath, (EHttpServerRequestVerbs)Verbs, - FHttpRequestHandler::CreateLambda([&, HttpPath](const FHttpServerRequest& Request, const FHttpResultCallback& OnComplete) + FHttpRequestHandler::CreateLambda([&, NormalizedPath](const FHttpServerRequest& Request, const FHttpResultCallback& OnComplete) { - return HandleRequestNative(HttpPath, Request, OnComplete); + return HandleRequestNative(NormalizedPath, Request, OnComplete); })); diff --git a/Source/SimpleHttpServer/Public/SimpleHttpServer.h b/Source/SimpleHttpServer/Public/SimpleHttpServer.h index 1ef6ff0..46f8e01 100644 --- a/Source/SimpleHttpServer/Public/SimpleHttpServer.h +++ b/Source/SimpleHttpServer/Public/SimpleHttpServer.h @@ -128,10 +128,16 @@ class SIMPLEHTTPSERVER_API USimpleHttpServer : public UObject // Usualy used for c++ TMap RouteHandlers; + // Keep track of verbs for paths that are handled without route binding (e.g. "/"). + TMap RouteVerbs; + // Cached Route Handlers. We should unbing them from route on self destroy TArray CreatedRouteHandlers; TSharedPtr HttpRouter; + FDelegateHandle RootRequestPreprocessorHandle; + bool bRootPreprocessorRegistered = false; + bool bServerStarted = false; };